-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathamazon-links.user.js
More file actions
214 lines (195 loc) · 8.97 KB
/
amazon-links.user.js
File metadata and controls
214 lines (195 loc) · 8.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
// ==UserScript==
// @namespace https://github.com/cbaoth/userscripts
// @author cbaoth235
//
// @name Amazon Tweaks
// @version 2022-01-11
// @description Some improvments to amazon shop pages
// @downloadURL https://github.com/cbaoth/userscripts/raw/master/amazon-links.user.js
//
// @include /^https?://(www\.|smile\.)?amazon\.(com|de|co\.uk)//
//
// @grant GM_addStyle
//
// @require http://code.jquery.com/jquery-latest.min.js
// @require https://gist.github.com/raw/2625891/waitForKeyElements.js
// @require https://raw.githubusercontent.com/jashkenas/underscore/master/underscore.js
// @require https://github.com/cbaoth/userscripts/raw/master/lib/cblib.js
// ==/UserScript==
this.$ = this.jQuery = jQuery.noConflict(true);
(function () {
// constants
const PAGE_PRODUCT = 1;
const PAGE_SEARCH = 2;
const PRICE_SELECTOR = 'div#corePrice_desktop span.a-price.a-text-price span:not(.a-offscreen)';
const PRICE_SELECTOR_SEARCH = `span.a-price-whole, span.a-color-price.a-size-base`;
const AVG_RATING_SELECTOR = 'div#averageCustomerReviews_feature_div';
const LINK_SELECTOR_SEARCH = `div[data-asin][data-cel-widget] a.a-text-normal[href*="/dp/"],
div[data-asin][data-cel-widget] a.a-link-normal[href*="/dp/"],
li[data-asin] a.s-access-detail-page,
li[data-asin] a.a-text-normal`;
const KEEPA_ICO = 'https://keepa.com/favicon.ico';
const PRICE_TWEAKS_ID = 'cb-price-tweaks';
const AVG_RATING_TWEAKS_ID = 'cb-avg-rating-tweaks';
const HOVER_FADE_CLASS = 'cb-hover-fade';
// static styles
GM_addStyle(`div.order > div.shipment-is-delivered { background: #90ee9050 !important; }`); // delivered order -> green
GM_addStyle(`div.order > div.shipment:not(.shipment-is-delivered) { background: #ff990030 !important; }`); // open/shipped -> orange
// TODO move to lib
GM_addStyle(`.${HOVER_FADE_CLASS} {
-webkit-transition: .25s ease-in-out opacity;
-moz-transition: .25s ease-in-out opacity;
-o-transition: .25s ease-in-out opacity;
transition: .25s ease-in-out opacity;
}
.${HOVER_FADE_CLASS}:hover {
opacity: 0.65;
}`); // fade on hover
const TLD = getTld();
function getTld() {
// get top level domain (the simple way)
let tld = document.domain.split('.').pop();
if (['au', 'br', 'mx'].indexOf(tld) > -1) {
// add .com to some domains
tld = 'com.' + tld;
} else if (['uk', 'jp'].indexOf(tld) > -1) {
// add .co to others
tld = 'co.' + tld;
}
return tld;
}
// clean-up product page link (strip all parameters and unnecessary texts)
function cleanLink(a) {
const href = $(a).attr('href');
if (!/\/[dg]p\/\w{10}([/?].+)?$/.test(href)) {
// not a product page links?
return; // do nothing
}
const custReview = /#customerReviews/.test(href) ? '#customerReviews' : '';
if (/^\s*http/.test(href)) {
// absolute link?
$(a).attr('href', toSmileURL(href).replace(/(?<=\w)\/.*(\/[dg]p\/\w{10})[/?].+/, '$1/') + custReview);
} else {
$(a).attr('href', toSmileURL(href).replace(/.*(\/[dg]p\/\w{10})[/?].+/, '$1/') + custReview);
}
}
// add average rating links
function addRatingLins(e) {
if ($('#' + AVG_RATING_TWEAKS_ID)[0]) {
return; // already done
}
const div = $(e);
const asin = $('input#ASIN').val();
const reviewMetaURL = `https://reviewmeta.com/amazon-${TLD}/${asin}`;
const tweak = `<a target="_blank" class="${HOVER_FADE_CLASS}" style="text-decoration: none; padding-right: .25em;"
href="${reviewMetaURL}" title="ReviewMeta (click to open in new tab).">
<span style="background: #2173b9; color: white; font-size: .65em; font-weight: bold; vertical-align: text-top; line-height: 16px;
padding: .2em .4em .1em .45em; text-align: center; filter: drop-shadow(1px 1px 1px black); border-radius: 2px;">R</span>
</a>`;
div.prepend(tweak);
}
// add price links
function addAmazonLinks(e, page) {
if ($('#' + PRICE_TWEAKS_ID)[0]) {
return; // already done
}
// get price tag
const price = $(e).hasClass('corePrice_desktop') ? $(e).parent() : $(e);
// get the ASIN (product id)
let asin;
if (page == PAGE_PRODUCT) {
asin = $('input#ASIN').val();
} else if (page == PAGE_SEARCH) {
if (price.parent().is('a')) {
// un-link price tag
price.unwrap();
}
asin = price.closest('li[data-asin], div[data-asin]').attr('data-asin');
} else {
return; // unknown page
}
// direct link
const azURL = `https://smile.amazon.${TLD}/dp/${asin}`;
const azICO = `https://www.amazon.${TLD}/favicon.ico`;
// keepa.com
const keepaIds = {
com: 1,
uk: 2,
de: 3,
fr: 4,
jp: 5,
ca: 6,
cn: 7,
it: 8,
es: 9,
in: 10,
mx: 11,
br: 12,
au: 13,
};
const keepaURL = `https://keepa.com/#!product/${keepaIds[TLD]}-${asin}`;
// add kappa link icon and amazon (clean product "share") link icon next to the price
price.after(`<span id="${PRICE_TWEAKS_ID}" style="display: inline-block; vertical-align: middle; margin-bottom: 1px;">
<a target="_blank" class="${HOVER_FADE_CLASS}" style="text-decoration: none"
href="${keepaURL}" title="Keepa price watch (click to open in new tab).">
<img style="margin-left: 4px; height: 16px; width: auto;" src="${KEEPA_ICO}" />
</a>
<a href="${azURL}" class="${HOVER_FADE_CLASS}" style="style="text-decoration: none" title="Clean product page link (copy to share).">
<img style="margin-left: 2px; padding-top: 2px; height: 18px; width: auto;" src="${azICO}" />
</a>
</span>`);
// make price a link to keepa (open in new tab/window)
price.wrapInner(
`<a target="_blank" class="a-color-price" href="${keepaURL}" title="Keepa price watch (click to open in new tab)."></a>`
);
}
function toSmileURL(url) {
return url.replace(/\/\/(www\.)?amazon\.(\w{2})/g, '//smile.amazon.$2');
}
function smileRedirect() {
// are we logged in? if not, don't redirect (won't work, infinite loop)
if (!$('#nav-link-accountList[data-nav-role="signin"] ~ a[href*="signout"]').length) {
return;
}
if (/^(www\.)?amazon.(\w+)/.test(location.hostname) && !/^smile\./.test(location.hostname)) {
const orgURL = window.location.href || window.parent.location.href;
const smileURL = toSmileURL(orgURL);
if (orgURL != smileURL) {
// try replacing location in various ways
try {
Location.replace(smileURL);
} catch {}
try {
window.location.replace(smileURL);
} catch {}
try {
window.parent.location.replace(smileURL);
} catch {}
}
}
}
// tweak pages, currently only
// smile rederict only on these pages (to be safe, pages might exist where this will not work)
if (/\/[dg]p\/(product\/)?\w{10}([/?].*)?$/.test(window.location.pathname)) {
// product page
// redirect to smile (if not already the case)
smileRedirect();
waitForKeyElements(PRICE_SELECTOR, (e) => addAmazonLinks(e, PAGE_PRODUCT));
waitForKeyElements(AVG_RATING_SELECTOR, (e) => addRatingLins(e));
// auto selection of one-time buy option (instead of default: subscription)
waitForKeyElements('#oneTimeBuyBox .a-accordion-radio', (e) => cb.clickElement(e));
}
if (/\/s([/?].+)?$/.test(window.location.pathname)) {
// search result
// redirect to smile (if not already the case)
smileRedirect();
// change price links (normally product link too) to keepa links
waitForKeyElements(PRICE_SELECTOR_SEARCH, (e) => addAmazonLinks(e, PAGE_SEARCH));
// replace all product links in search result with clean links
waitForKeyElements(LINK_SELECTOR_SEARCH, (e) => cleanLink(e));
} else if (/\/gp\/cart\//.test(window.location.pathname)) {
// shopping cart
// redirect to smile (if not already the case)
smileRedirect(); // most important smile redirect (checkout)
}
})();