Bandcamp - Display Prices on Wishlist

Simply display a price tag on each item in the wishlist

  1. // ==UserScript==
  2. // @name Bandcamp - Display Prices on Wishlist
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0.1
  5. // @description Simply display a price tag on each item in the wishlist
  6. // @author Romain Racamier-Lafon
  7. // @match https://bandcamp.com/*/wishlist
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. var app = {
  15. id: "bcp-sp"
  16. };
  17.  
  18. app.debug = false;
  19.  
  20. var cls = {
  21. price: app.id + '-price',
  22. handled: app.id + '-handled'
  23. };
  24.  
  25. var selectors = {
  26. product: 'li[data-trackid]:not(.' + cls.handled + ')'
  27. };
  28.  
  29. function findOne(selector, context, dontYell) {
  30. context = context || document;
  31. var item = context.querySelector(selector);
  32. if (item && app.debug) {
  33. console.log(app.id, ': found element matching "' + selector + '"');
  34. } else if (!item && !dontYell) {
  35. console.warn(app.id, ': found no element for selector "' + selector + '"');
  36. }
  37. return item;
  38. }
  39.  
  40. function findFirst(selector, context) {
  41. return findAll(selector, context)[0];
  42. }
  43.  
  44. function findAll(selector, context, dontYell) {
  45. if (!selector || !selector.length || selector.length === 1) {
  46. console.error(app.id, ': incorrect selector : ', selector);
  47. }
  48. context = context || document;
  49. var items = Array.prototype.slice.call(context.querySelectorAll(selector));
  50. if (items.length && app.debug) {
  51. console.log(app.id, ': found', items.length, 'elements matching "' + selector + '"');
  52. } else if (!items.length && !dontYell) {
  53. console.warn(app.id, ': found no elements for selector "' + selector + '"');
  54. }
  55. return items;
  56. }
  57.  
  58. function debounce(func, wait, immediate) {
  59. var timeout;
  60. return function () {
  61. var context = this;
  62. var args = arguments;
  63. var later = function later() {
  64. timeout = null;
  65. if (!immediate) {
  66. func.apply(context, args);
  67. }
  68. };
  69. var callNow = immediate && !timeout;
  70. clearTimeout(timeout);
  71. timeout = setTimeout(later, wait);
  72. if (callNow) {
  73. func.apply(context, args);
  74. }
  75. };
  76. }
  77.  
  78. function cleanPrevious() {
  79. findAll('[class^="' + cls.price + '"]', document, true).forEach(function (node) {
  80. return node.remove();
  81. });
  82. }
  83.  
  84. function displayPrice(product, price) {
  85. var tag = document.createElement('div');
  86. tag.innerHTML = price.value + ' <small>' + price.currency + '</small>';
  87. tag.style = 'position: absolute; top: 0; right: 0; background-color: green; color: white;';
  88. tag.classList.add(cls.price, 'col-edit-box');
  89. product.appendChild(tag);
  90. if (price.value > 2) {
  91. product.style.filter = 'grayscale(1) opacity(.5)';
  92. }
  93. product.classList.add(cls.handled);
  94. }
  95.  
  96. function displayPrices() {
  97. findAll(selectors.product, document, true).forEach(function (product) {
  98. var trackid = parseInt(product.getAttribute('data-trackid'));
  99. if (trackid) {
  100. if (app.debug) {
  101. console.log(app.id, ': adding price for', trackid);
  102. }
  103. if (!app.tracks.hasOwnProperty(trackid)) {
  104. throw new Error('failed at gettting track price');
  105. }
  106. var price = app.tracks[trackid];
  107. displayPrice(product, price);
  108. }
  109. });
  110. }
  111.  
  112. function setTracksFromList(list) {
  113. if (!app.tracks) {
  114. app.tracks = {};
  115. }
  116. var added = 0;
  117. list.map(function (track) {
  118. var trackid = track.track_id;
  119. if (!app.tracks.hasOwnProperty(trackid)) {
  120. app.tracks[trackid] = {
  121. value: Math.round(track.price),
  122. currency: track.currency
  123. };
  124. added++;
  125. }
  126. });
  127. console.log(app.id, ': added', added, 'tracks to local db :D');
  128. }
  129.  
  130. function getDataFromApi() {
  131. fetch('https://bandcamp.com/api/fancollection/1/wishlist_items', {
  132. method: 'POST',
  133. headers: {
  134. 'Accept': 'application/json',
  135. 'Content-Type': 'application/json'
  136. },
  137. body: JSON.stringify({
  138. fan_id: app.userid,
  139. older_than_token: app.token
  140. })
  141. }).then(function (json) {
  142. return json.json();
  143. }).then(function (data) {
  144. app.token = data.last_token;
  145. setTracksFromList(data.track_list);
  146. if (data.more_available) {
  147. getDataFromApi();
  148. }
  149. });
  150. }
  151.  
  152. function getDataFromPage() {
  153. var dataEl = findOne('#pagedata');
  154. var data = JSON.parse(dataEl.getAttribute('data-blob'));
  155. setTracksFromList(data.track_list);
  156. app.token = data.wishlist_data.last_token;
  157. app.userid = data.fan_data.fan_id;
  158. }
  159.  
  160. function process() {
  161. displayPrices();
  162. }
  163.  
  164. function init() {
  165. console.log(app.id, ': init !');
  166. cleanPrevious();
  167. getDataFromPage();
  168. getDataFromApi();
  169. process();
  170. }
  171.  
  172. init();
  173.  
  174. var processDebounced = debounce(process, 500);
  175. document.addEventListener('scroll', processDebounced);
  176.  
  177. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址