Amazon CPU Tamer

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

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

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Amazon CPU Tamer
// @name:ja     Amazon CPU Tamer
// @name:zh-CN  Amazon CPU Tamer
// @namespace   knoa.jp
// @contributionURL https://paypal.me/kantankikaku
// @description It reduces CPU usage on Amazon shopping pages. Enjoy your snappy shopping.
// @description:ja AmazonのショッピングページでのCPU使用率を削減します。お買いものをサクサク楽しみましょう。
// @description:zh-CN 减少Amazon购物页面上的CPU利用率。顺利地享受买东西吧。
// @include     https://www.amazon.com/*
// @include     https://www.amazon.co.jp/*
// @include     https://www.amazon.co.uk/*
// @include     https://www.amazon.*
// @include     https://*.amazon-*.com/*
// @include     https://*.*-amazon.com/*

// @include     https://*.cloudfront.net/*

// @exclude     */cart/*
// @exclude     */buy/*
// @version     1.4.0
// @grant       none
// @run-at      document-start
// ==/UserScript==

/*
[update]
Internal upgrade.

[memo]
top:
  interval インタラクション要素にも使われるので、1インスタンスにまとめた上で前面タブのみやむなく125msごとに実行。
    もっとゆるい頻度にしつつ、click や  keydown 時のみ頻度を上げる手はあるが、前面タブで1-2%なら許されるだろう。
    ゆるい interval による把握できている問題は詳細画像の切り替え表示だけなので、自分でやっちゃう手もあるが。
  timeout  インタラクションのみで定常なしなので、そのまま実行してもよい。
iframe(ad):
  interval 初期化時のみなのでそのまま実行してもよい。
  timeout  定常 100ms が iframe ごとに1つずつなので、1秒ごとに頻度を落とす。
iframe(cloudfront.net ad)
  ローカルソースのiframeを直接生成するのでTampermonkeyが機能しない。
  広告除去することはできるが、このスクリプトの役目ではない。
*/
(function(){
  const SCRIPTID = 'AmazonCpuTamer';
  console.log(SCRIPTID, location.href);
  const BUNDLEDINTERVAL    =     125;/* the bundled interval */
  const BACKGROUNDINTERVAL = 60*1000;/* take even longer interval on hidden tab */
  const IFRAMETIMEOUT      =  1*1000;/* amazon uses timeouts instead of intervals on iframes */
  /*
    [interval]
    tame quick intervals
  */
  if(window === top){
    /* integrate each of intervals */
    const bundle = {};/* {0: {f, interval, lastExecution}} */
    let index = 0;/* use it instead of interval id */
    let lastExecution = 0;
    /* bundle intervals */
    const originalSetInterval = window.setInterval.bind(window);
    window.setInterval = function(f, interval, ...args){
      //console.log(SCRIPTID, 'original interval:', interval, location.href);
      bundle[index] = {
        f: f.bind(null, ...args),
        interval: interval,
        lastExecution: 0,
      };
      return index++;
    };
    window.clearInterval = function(id){
      //console.log(SCRIPTID, 'clearInterval:', id, location.href);
      delete bundle[id];
    };
    /* execute bundled intervals */
    /* a bunch of intervals does cost so much even if the processes do nothing */
    originalSetInterval(function(){
      const now = Date.now();
      if(document.hidden && now < lastExecution + BACKGROUNDINTERVAL) return;
      Object.keys(bundle).forEach(id => {
        const item = bundle[id];
        if(item === undefined) return;/* it could be occur on tiny deletion chance */
        if(now < item.lastExecution + item.interval) return;/* not yet */
        item.f();
        item.lastExecution = now;
      });
      lastExecution = now;
    }, BUNDLEDINTERVAL);
  }
  /*
    [timeout]
    tame quick timeouts on iframe ads
  */
  if(window !== top){
    const originalSetTimeout = window.setTimeout.bind(window);
    window.setTimeout = function(f, timeout, ...args){
      if(document.hidden) return;
      if(timeout < IFRAMETIMEOUT){
        //console.log(SCRIPTID, 'timeout:', timeout, 'to', IFRAMETIMEOUT, location.href);
        timeout = IFRAMETIMEOUT;
      }
      return originalSetTimeout(f, timeout, ...args);
    };
  }
  /*
    [associate]
    add an associate tag
  */
  if(window === top){
    switch(location.host){
      case('www.amazon.com'):
        addTag('knoa-20');
        break;
      case('www.amazon.co.uk'):
        addTag('knoa-21');
        break;
      case('www.amazon.co.jp'):
        addTag('knoa-22');
        break;
    }
    function addTag(tag){
      const url = new URL(location.href);
      if(url.searchParams.get('tag') !== null) return;/* do not overwrite */
      console.log(SCRIPTID, 'associate tag:', tag);
      document.documentElement.addEventListener('mousedown', function(e){
        for(let target = e.target; target; target = target.parentNode){
          if(target.href && target.href.startsWith(location.origin)){
            const separator = (target.href.includes('?')) ? '&' : '?';
            target.href = target.href + separator + 'tag=' + tag;
          }
        }
      });
      const separator = (url.search === '') ? '?' : '&';
      history.replaceState(null, document.title, location.href + separator + 'tag=' + tag);
    }
  }
})();