Amazon CPU Tamer

减少Amazon购物页面上的CPU利用率。顺利地享受买东西吧。

当前为 2020-12-19 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Amazon CPU Tamer
  3. // @name:ja Amazon CPU Tamer
  4. // @name:zh-CN Amazon CPU Tamer
  5. // @namespace knoa.jp
  6. // @contributionURL https://paypal.me/kantankikaku
  7. // @description It reduces CPU usage on Amazon shopping pages. Enjoy your snappy shopping.
  8. // @description:ja AmazonのショッピングページでのCPU使用率を削減します。お買いものをサクサク楽しみましょう。
  9. // @description:zh-CN 减少Amazon购物页面上的CPU利用率。顺利地享受买东西吧。
  10. // @include https://www.amazon.com/*
  11. // @include https://www.amazon.co.jp/*
  12. // @include https://www.amazon.co.uk/*
  13. // @include https://www.amazon.es/*
  14. // @include https://www.amazon.fr/*
  15. // @include https://www.amazon.de/*
  16. // @include https://www.amazon.it/*
  17. // @include https://www.amazon.*
  18. // @include https://*.amazon-*.com/*
  19. // @include https://*.*-amazon.com/*
  20. // @exclude */cart/*
  21. // @exclude */buy/*
  22. // @version 1.4.1.1
  23. // @grant none
  24. // @run-at document-start
  25. // ==/UserScript==
  26.  
  27. /*
  28. [update]
  29. Updated associate IDs on EU nations.
  30.  
  31. [memo]
  32. top:
  33. interval インタラクション要素にも使われるので、1インスタンスにまとめた上で前面タブのみやむなく125msごとに実行。
  34. もっとゆるい頻度にしつつ、click や keydown 時のみ頻度を上げる手はあるが、前面タブで1-2%なら許されるだろう。
  35. ゆるい interval による把握できている問題は詳細画像の切り替え表示だけなので、自分でやっちゃう手もあるが。
  36. timeout インタラクションのみで定常なしなので、そのまま実行してもよい。
  37. iframe(ad):
  38. interval 初期化時のみなのでそのまま実行してもよい。
  39. timeout 定常 100ms が iframe ごとに1つずつなので、1秒ごとに頻度を落とす。
  40. iframe(cloudfront.net ad)
  41. ローカルソースのiframeから事後生成されるのでTampermonkeyが機能しない。
  42. 広告除去することはできるが、このスクリプトの役目ではない。
  43. */
  44. (function(){
  45. const SCRIPTID = 'AmazonCpuTamer';
  46. console.log(SCRIPTID, location.href);
  47. const BUNDLEDINTERVAL = 125;/* the bundled interval */
  48. const BACKGROUNDINTERVAL = 60*1000;/* take even longer interval on hidden tab */
  49. const IFRAMETIMEOUT = 1*1000;/* amazon uses timeouts instead of intervals on iframes */
  50. /*
  51. [interval]
  52. tame quick intervals
  53. */
  54. if(window === top){
  55. /* integrate each of intervals */
  56. const bundle = {};/* {0: {f, interval, lastExecution}} */
  57. let index = 0;/* use it instead of interval id */
  58. let lastExecution = 0;
  59. /* bundle intervals */
  60. const originalSetInterval = window.setInterval.bind(window);
  61. window.setInterval = function(f, interval, ...args){
  62. //console.log(SCRIPTID, 'original interval:', interval, location.href);
  63. bundle[index] = {
  64. f: f.bind(null, ...args),
  65. interval: interval,
  66. lastExecution: 0,
  67. };
  68. return index++;
  69. };
  70. window.clearInterval = function(id){
  71. //console.log(SCRIPTID, 'clearInterval:', id, location.href);
  72. delete bundle[id];
  73. };
  74. /* execute bundled intervals */
  75. /* a bunch of intervals does cost so much even if the processes do nothing */
  76. originalSetInterval(function(){
  77. const now = Date.now();
  78. if(document.hidden && now < lastExecution + BACKGROUNDINTERVAL) return;
  79. Object.keys(bundle).forEach(id => {
  80. const item = bundle[id];
  81. if(item === undefined) return;/* it could be occur on tiny deletion chance */
  82. if(now < item.lastExecution + item.interval) return;/* not yet */
  83. item.f();
  84. item.lastExecution = now;
  85. });
  86. lastExecution = now;
  87. }, BUNDLEDINTERVAL);
  88. }
  89. /*
  90. [timeout]
  91. tame quick timeouts on iframe ads
  92. */
  93. if(window !== top){
  94. const originalSetTimeout = window.setTimeout.bind(window);
  95. window.setTimeout = function(f, timeout, ...args){
  96. if(document.hidden) return;
  97. if(timeout < IFRAMETIMEOUT){
  98. //console.log(SCRIPTID, 'timeout:', timeout, 'to', IFRAMETIMEOUT, location.href);
  99. timeout = IFRAMETIMEOUT;
  100. }
  101. return originalSetTimeout(f, timeout, ...args);
  102. };
  103. }
  104. /*
  105. [associate]
  106. add an associate tag
  107. */
  108. if(window === top){
  109. switch(location.host){
  110. case('www.amazon.com'):
  111. addTag('knoa-20');
  112. break;
  113. case('www.amazon.co.jp'):
  114. addTag('knoa-22');
  115. break;
  116. case('www.amazon.co.uk'):
  117. addTag('knoa01-21');
  118. break;
  119. case('www.amazon.es'):
  120. addTag('knoa0c-21');
  121. break;
  122. case('www.amazon.fr'):
  123. addTag('knoa09-21');
  124. break;
  125. case('www.amazon.de'):
  126. addTag('knoa03-21');
  127. break;
  128. case('www.amazon.it'):
  129. addTag('knoa0a-21');
  130. break;
  131. }
  132. function addTag(tag){
  133. const url = new URL(location.href);
  134. if(url.searchParams.get('tag') !== null) return;/* do not overwrite */
  135. console.log(SCRIPTID, 'associate tag:', tag);
  136. document.documentElement.addEventListener('mousedown', function(e){
  137. for(let target = e.target; target; target = target.parentNode){
  138. if(target.href && target.href.startsWith(location.origin)){
  139. const separator = (target.href.includes('?')) ? '&' : '?';
  140. target.href = target.href + separator + 'tag=' + tag;
  141. }
  142. }
  143. });
  144. const separator = (url.search === '') ? '?' : '&';
  145. history.replaceState(null, document.title, location.href + separator + 'tag=' + tag);
  146. }
  147. }
  148. })();