// ==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 // @downloadURL https://update.greasyfork.icu/scripts/11153/bt_search_for_bgm.user.js // @updateURL https://update.greasyfork.icu/scripts/11153/bt_search_for_bgm.meta.js // ==/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 += "
"; }, 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 }; /***/ }) /******/ ]);