Greasy Fork

bt_search_for_bgm

add search icons in bangumi.tv for search anime

当前为 2018-06-18 提交的版本,查看 最新版本

/** h */
// ==UserScript==
// @name        bt_search_for_bgm
// @name:zh-CN  bangumi 辅助搜索
// @namespace   https://bgm.tv/user/a_little
// @description add search icons in bangumi.tv for search anime
// @description:zh-cn 条目页面、合集页面增加搜索图标,辅助搜索
// @include     /^https?://(bangumi|bgm|chii)\.(tv|in)/(subject|index|anime|game|book|subject_search)/.*$/
// @include     /^https?://(bangumi|bgm|chii).(tv|in)/$/
// @author      22earth
// @version     1.0.1
// @note        1.0.0 使用定期更新搜索引擎列表的方式
// @grant       GM_addStyle
// @grant       GM_registerMenuCommand
// @grant       GM_xmlhttpRequest
// ==/UserScript==

(function () {
  'use strict';

  function gmFetchBinary(url, TIMEOUT) {
    return new Promise((resolve, reject) => {
      GM_xmlhttpRequest({
        method: "GET",
        timeout: TIMEOUT || 10 * 1000,
        url: url,
        overrideMimeType: "text\/plain; charset=x-user-defined",
        onreadystatechange: function (response) {
          if (response.readyState === 4 && response.status === 200) {
            resolve(response.responseText);
          }
        },
        onerror: function (err) {
          reject(err);
        },
        ontimeout: function (err) {
          reject(err);
        }
      });
    });
  }

  function gmFetch(url, TIMEOUT) {
    return new Promise((resolve, reject) => {
      GM_xmlhttpRequest({
        method: "GET",
        timeout: TIMEOUT || 10 * 1000,
        url: url,
        onreadystatechange: function (response) {
          if (response.readyState === 4 && response.status === 200) {
            resolve(response.responseText);
          }
        },
        onerror: function (err) {
          reject(err);
        },
        ontimeout: function (err) {
          reject(err);
        }
      });
    });
  }

  var gmFetch_1 = {
    gmFetch,
    gmFetchBinary
  };
  var gmFetch_2 = gmFetch_1.gmFetch;

  function infoOutdated(prefix, interval, version) {
    const localVersion = localStorage.getItem(prefix + 'VERSION');
    const time = localStorage.getItem(prefix + 'LATEST_UPDATE_TIME');
    if (!localVersion || !time || localVersion !== version){
      return true;
    }
    const now = new Date();
    if (now - new Date(time) > interval) {
      clearInfoStorage(prefix);
      return true;
    }
  }

  function clearInfoStorage(prefix) {
    for (var key in localStorage) {
      if (key.match(prefix)) {
        console.log(localStorage.getItem(key));
        localStorage.removeItem(key);
      }
    }
  }

  var utils = {
    infoOutdated,
    clearInfoStorage
  };
  var utils_1 = utils.infoOutdated;
  var utils_2 = utils.clearInfoStorage;

  const USERJS_PREFIX = 'E_USERJS_SEARCH_';
  const API_STR = USERJS_PREFIX + 'SEARCH_APIS';
  const UPDATE_INTERVAL = 24 * 60 * 60 * 1000 * 30;
  const VERSION = '1.0.1';
  const SEARCH_APIS_URL = 'https://raw.githubusercontent.com/22earth/gm_scripts/master/searchapis.json'; 

  if (GM_registerMenuCommand) {
    // 用户脚本命令清除缓存信息
    GM_registerMenuCommand('获取最新搜索引擎列表', () => utils_2(USERJS_PREFIX), 'f');
  }

  async function getSearchAPIs(str) {
    var searchAPIsResource = localStorage.getItem(str);
    if (!searchAPIsResource || utils_1(USERJS_PREFIX, UPDATE_INTERVAL, VERSION)) {
      console.log('begin fetch apis');
      searchAPIsResource = await gmFetch_2(SEARCH_APIS_URL);
      localStorage.setItem(str, searchAPIsResource);

      localStorage.setItem(USERJS_PREFIX + 'VERSION', VERSION);
      localStorage.setItem(USERJS_PREFIX + 'LATEST_UPDATE_TIME', new Date().getTime());
    }
    return await JSON.parse(searchAPIsResource);
  }

  async function init() {
    const deprecatedEngines = ["btdigg", "camoe", "btcherry"];
    const allSearchEngineLists = [
      ["dmhy"],  // CN
      ["google", "sukebei", "tokyotosho", "torrentproject"],  // JP
    ];

    if (!localStorage.getItem('searchEngines') || typeof JSON.parse(localStorage.getItem('searchEngines')) !== 'object') {
      localStorage.setItem('searchEngines', JSON.stringify(['dmhy', 'google', 'shousibaocai']));
    }

    var searchAPIs = await getSearchAPIs(API_STR);

    for (var i = 0, len = deprecatedEngines.length; i < len; i++) {
      delete searchAPIs[deprecatedEngines[i]];
    }
    var searchEngineLists = Object.keys(searchAPIs);
    var searchEngines = JSON.parse(localStorage.getItem('searchEngines'));
    searchEngines = searchEngines.filter(function(e) {
      if (searchEngineLists.indexOf(e) !== -1)
        return true;
    });


    var addSearchIcon = {
      init: function() {
        if (window.location.href.match("/subject/") && document.getElementById("navMenuNeue").children[2].children[0].className !== "focus chl")
          this.addIcon1();
        else if (window.location.href.match("/anime|index|game|book|subject_search/"))
          this.addIcon2();

      },
      createLink: function(link) {
        var searchIcon = document.createElement("a");
        searchIcon.href = link;
        searchIcon.target = "_blank";
        searchIcon.className = "searchicon";
        var searchIconImg = document.createElement("img");
        searchIconImg.style.cssText = "display:inline-block;border:none;height:12px;width:14px;margin-left:2px";
        searchIcon.appendChild(searchIconImg);
        // add title and icon
        var re = new RegExp(searchEngineLists.join("|"));
        if (link.match(re)) {
          var domain = link.match(re)[0];
          searchIcon.title = searchAPIs[domain][0];
          searchIconImg.src = searchAPIs[domain][1];
        }
        return searchIcon;
      },

      getChineseName: function(title) {
        if (window.location.href.match(/subject_search|index/))
          return title.getElementsByClassName("l")[0].textContent;
        if (title.getElementsByTagName("a")[0].title)
          return title.children[0].title;
        return title.children[0].textContent;
      },

      getJanpaneseName: function(title) {
        if (window.location.href.match(/subject_search/)) {
          if (title.getElementsByClassName("grey").length)
            return title.getElementsByClassName("grey")[0].textContent;
          else
            return title.getElementsByClassName("l")[0].textContent;
        }
        if (title.tagName === "H3" && title.children[1] !== undefined) {
          return title.children[1].textContent;
        }
        else if (title.tagName === "H1")
          return title.children[0].textContent;
        return "";
      },
      getLink: function(engineName, animeName) {
        return searchAPIs[engineName][2].replace(/\{searchTerms\}/, encodeURIComponent(animeName));
      },
      addIcon1: function() {
        // add search icon in subject page
        var h1 = document.getElementsByTagName("h1")[0];
        if (h1) {
          for (var i = 0, len = searchEngines.length; i < len; i++) {
            var animeName = this.getJanpaneseName(h1);
            var engineName = searchEngines[i];
            if (allSearchEngineLists[0].indexOf(engineName) > -1 || !animeName.length)
              animeName = this.getChineseName(h1);

            h1.appendChild(this.createLink(this.getLink(engineName, animeName)));
          }
        }
      },

      addIcon2: function addSearchIcon2() {
        // add search icon in anime or index page
        //    if (window.location.href.match(/subject_search/))
        for (var i = 0, len = document.getElementsByTagName("h3").length; i < len; i++) {
          var h3 = document.getElementsByTagName("h3")[i];
          for (var j = 0; j < searchEngines.length; j++) {
            var animeName = this.getJanpaneseName(h3);
            var engineName = searchEngines[j];
            if (allSearchEngineLists[0].indexOf(engineName) > -1 || !animeName.length)
              animeName = this.getChineseName(h3);
            h3.appendChild(this.createLink(this.getLink(engineName, animeName)));
          }
        }
      },
    };

    var searchSwitch = {
      init: function() {
        if (this.isHomepge()) {
          this.addStyle();
          this.insertStatus();
          this.insertSearchEngineSwitch();
        }
      },
      isHomepge: function() {
        return window.location.pathname === '/' && document.getElementById('columnTimelineInnerWrapper')? true : false;
      },
      addStyle: function(css) {

        if (css) {
          GM_addStyle(css);
        } else {
          GM_addStyle([
            '.search-switches {display:none;}',
            '*:hover > .search-switches {display:block;}',
            '.search-status {padding: 5px 15px 0;}',
            '.search-switches {overflow:hidden;}',
            '.search-switches a {display:inline-block;float:left;margin:5px 5px;padding:5px 5px;border-radius:4px;box-shadow:1px 1px 2px #333;}',
            '.search-switches a.engine-off {background:#ccffcc none repeat scroll 0 0;color:#333;}',
            '.search-switches a.engine-on {background:#f09199 none repeat scroll 0 0;color:#fff;}'
          ].join(''));
        }
      },
      insertStatus: function() {
        // move to sidepanel because of confliction of default function
        var colB = document.querySelector('#columnHomeB');
        var b = document.createElement('div');
        // b.style.height = '500px';  // as high as posible to activate mouse hover event.
        colB.appendChild(b);
        // main div to show status and toggle search engine
        var status = document.createElement('div');
        status.className = 'search-status';
        status.textContent = '已开启'+ searchEngines.length + '个搜索引擎';
        b.appendChild(status);
        var div = document.createElement('div');
        div.className = 'search-switches';
        b.appendChild(div);
        b.innerHTML += '<br />';
      },
      insertSearchEngineSwitch: function() {
        var div = document.querySelector('.search-switches');
        for (var i = 0; i < searchEngineLists.length; i += 1) {
          if (searchEngines.indexOf(searchEngineLists[i]) > -1) {
            div.appendChild(this.createSwitch(searchEngineLists[i], 'engine-on'));
          } else {
            div.appendChild(this.createSwitch(searchEngineLists[i], 'engine-off'));
          }
        }
      },
      createSwitch: function(name, aclass) {
        var a = document.createElement('a');
        a.className = aclass;
        a.textContent = name;
        a.href = '#';
        a.addEventListener('click', function(e) {
          var engines = searchEngines;
          if (e.target.className === 'engine-on') {
            e.target.className = 'engine-off';
            var index = engines.indexOf(e.target.textContent);
            if (index > -1) engines.splice(index, 1);
          } else {
            e.target.className = 'engine-on';
            engines.push(e.target.textContent);
          }
          var status = document.querySelector('.search-status');
          status.textContent = '已开启'+ document.querySelectorAll('.engine-on').length + '个搜索引擎';
          localStorage.setItem('searchEngines', JSON.stringify(engines));
          e.preventDefault();
        });
        return a;
      },
      registerEvent: function () {

      }
    };

    try {
      searchSwitch.init();
      addSearchIcon.init();
    } catch (e) {
      console.log(e);
    }
  }


  init();

}());