- // ==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
- };
-
- /***/ })
- /******/ ]);