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