bt_search_for_bgm

add search icons in bangumi.tv for search anime

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==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.1.0
// @note        1.0.0 使用定期更新搜索引擎列表的方式
// @grant       GM_addStyle
// @grant       GM_registerMenuCommand
// @grant       GM_xmlhttpRequest
// ==/UserScript==

/******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, {
/******/ 				configurable: false,
/******/ 				enumerable: true,
/******/ 				get: getter
/******/ 			});
/******/ 		}
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

var _gmFetch = __webpack_require__(1);

var _index = __webpack_require__(2);

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

if (GM_registerMenuCommand) {
  // 用户脚本命令清除缓存信息
  GM_registerMenuCommand("获取最新搜索引擎列表", function () {
    return (0, _index.clearInfoStorage)(USERJS_PREFIX);
  }, "f");
}

async function getSearchAPIs(str) {
  var searchAPIsResource = localStorage.getItem(str);
  if (!searchAPIsResource || (0, _index.infoOutdated)(USERJS_PREFIX, UPDATE_INTERVAL, VERSION)) {
    console.log("begin fetch apis");
    searchAPIsResource = await (0, _gmFetch.gmFetch)(SEARCH_APIS_URL);
    var myRules = JSON.parse(searchAPIsResource);
    var magnetWRules = await getMagnetWRule();
    var apis = Object.assign({}, magnetWRules, myRules);
    localStorage.setItem(str, JSON.stringify(apis));

    localStorage.setItem(USERJS_PREFIX + "VERSION", VERSION);
    localStorage.setItem(USERJS_PREFIX + "LATEST_UPDATE_TIME", new Date().getTime());
    return apis;
  } else if (searchAPIsResource) {
    return JSON.parse(searchAPIsResource);
  } else {
    (0, _index.clearInfoStorage)(USERJS_PREFIX);
    return {};
  }
}
async function getMagnetWRule() {
  var URL = "https://magnetw.app/rule.json";

  var rules = JSON.parse((await (0, _gmFetch.gmFetch)(URL)));
  var myRules = {};
  rules.forEach(function (obj) {
    var url = obj.url;
    if (obj.paths && obj.paths.preset) {
      var preset = obj.paths.preset.replace("{k}", "{searchTerms}").replace("{p}", "1");
      url = "" + url + preset;
      myRules[obj.id] = [obj.name, obj.icon || obj.url + "/favicon.ico", url];
    }
  });
  return myRules;
}

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

  if (!localStorage.getItem("searchEngines") || _typeof(JSON.parse(localStorage.getItem("searchEngines"))) !== "object") {
    localStorage.setItem("searchEngines", JSON.stringify(["dmhy", "google"]));
  }
  // Data format and order like this: name : ["title", "icon", "searchapi"].
  // In "searchapi", query string should indead by {searchTerms}.
  var searchAPIsUser = {};

  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 init() {
      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 createLink(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];
        var iconURL = searchAPIs[domain][1];
        searchIconImg.src = iconURL;
      }
      return searchIcon;
    },

    getChineseName: function getChineseName(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 getJanpaneseName(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 getLink(engineName, animeName) {
      return searchAPIs[engineName][2].replace(/\{searchTerms\}/, encodeURIComponent(animeName));
    },
    addIcon1: function addIcon1() {
      // 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 init() {
      if (this.isHomepge()) {
        this.addStyle();
        this.insertStatus();
        this.insertSearchEngineSwitch();
      }
    },
    isHomepge: function isHomepge() {
      return window.location.pathname === "/" && document.getElementById("columnTimelineInnerWrapper") ? true : false;
    },
    addStyle: function addStyle(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 insertStatus() {
      // 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 insertSearchEngineSwitch() {
      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 createSwitch(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 registerEvent() {}
  };

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

init();

/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


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

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

module.exports = {
  gmFetch: gmFetch,
  gmFetchBinary: gmFetchBinary
};

/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";


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

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

module.exports = {
  infoOutdated: infoOutdated,
  clearInfoStorage: clearInfoStorage
};

/***/ })
/******/ ]);