common_libs_of_array

增加页面顶部底部按钮和一键下种按钮

目前為 2024-09-17 提交的版本,檢視 最新版本

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.sleazyfork.org/scripts/476583/1449370/common_libs_of_array.js

  1. // ==UserScript==
  2. // @name common_libs_of_array
  3. // @namespace websiteEnhancement
  4. // @author jimmly
  5. // @version 2024.7.24
  6. // @description 增加页面顶部底部按钮和一键下种按钮
  7. // @create 2023-9-21
  8. // @include *
  9. // @grant GM_getValue
  10. // @grant GM_setValue
  11. // @grant GM.getValue
  12. // @grant GM.setValue
  13. // @license MIT
  14. // @run-at document-idle
  15. // ==/UserScript==
  16. // https://raw.githubusercontent.com/sodiray/radash/master/cdn/radash.min.js
  17. async function withJQuery(callback, safe, unsafeWindow) {
  18. if (typeof jQuery == "undefined") {
  19. let script = document.createElement("script")
  20. script.type = "text/javascript"
  21. script.src = "https://code.jquery.com/jquery-3.7.1.min.js"
  22. if (safe) {
  23. let cb = document.createElement("script")
  24. cb.type = "text/javascript"
  25. cb.textContent = `jQuery.noConflict();(${callback.toString()})(jQuery, window);`
  26. script.addEventListener("load", function () {
  27. document.head.appendChild(cb)
  28. })
  29. }
  30. else {
  31. let dollar
  32. if (typeof $ != "undefined")
  33. dollar = $
  34. script.addEventListener("load", function () {
  35. jQuery.noConflict()
  36. $ = dollar
  37. callback(jQuery, window)
  38. })
  39. }
  40. document.head.appendChild(script)
  41. }
  42. else {
  43. setTimeout(function () {
  44. // Firefox supports
  45. callback(jQuery, typeof unsafeWindow === "undefined" ? window : unsafeWindow)
  46. }, 30)
  47. }
  48. }
  49. // addStyle
  50. function addStyle(css) {
  51. let s = document.createElement('style')
  52. s.appendChild(document.createTextNode(css))
  53. document.getElementsByTagName('head')[0].appendChild(s)
  54. }
  55.  
  56. function getFilePathFromUrl(url) {
  57.  
  58. try {
  59. url = new URL(urlString)
  60. }
  61. catch (e) {
  62. try {
  63. url = new URL(urlString, window.location.origin)
  64. }
  65. catch {
  66.  
  67. }
  68. }
  69. return url.pathname.split('/').pop() // 或使用 url.pathname.split('/').pop() 如果url已经是一个URL对象
  70. }
  71.  
  72. const getUrlWithoutHost = radash.memo((urlString) => {
  73. let url = urlString
  74. try {
  75. url = new URL(urlString)
  76. }
  77. catch (e) {
  78. try {
  79. url = new URL(urlString, window.location.origin)
  80. } catch {
  81.  
  82. }
  83. }
  84. return url.href.substring(url.origin.length)
  85. })
  86.  
  87. class LRUCache {
  88. cache = []
  89. saveMapToLocalStorage() {
  90. const mergedArray = this.loadMapFromLocalStorage().concat(this.cache);
  91. this.cache = mergedArray.filter((item, index, arr) => arr.indexOf(item) === index);
  92. if (this.cache.length >= this.capacity) {
  93. // 如果达到容量限制,删除最老的项
  94. this.cache.splice(0, this.cache.length - this.capacity)
  95. }
  96. // 将Map转换为普通对象
  97. const obj = this.cache ?? []
  98. // 将对象转换为JSON字符串
  99. const jsonString = JSON.stringify(obj)
  100. // 存储到localStorage
  101. localStorage.setItem(this.key, jsonString)
  102. }
  103. loadMapFromLocalStorage() {
  104. // 从localStorage获取JSON字符串
  105. const jsonString = localStorage.getItem(this.key)
  106. if (!jsonString) {
  107. return [] // 如果没有数据,返回空Map
  108. }
  109. // 将JSON字符串转换为普通对象
  110. try {
  111. const obj = JSON.parse(jsonString)
  112. if (Array.isArray(obj))
  113. return obj
  114. return Object.keys(obj)
  115. } catch (error) {
  116.  
  117. }
  118. return []
  119. }
  120. autoSave() {
  121.  
  122. setTimeout(() => {
  123.  
  124. this.saveMapToLocalStorage()
  125. this.autoSave()
  126. }, 60_000)
  127. }
  128. constructor(key = "default_key", capacity = 500, win) {
  129. this.key = key
  130. this.capacity = capacity
  131. this.compare = function (cacheVal, currVal) {
  132.  
  133. if (win.__compareKey) {
  134. this.compare = (cacheVal, currVal) => win.__compareKey(cacheVal, currVal)
  135. return win.__compareKey(cacheVal, currVal)
  136. } else {
  137. this.compare = (cacheVal, currVal) => cacheVal == currVal
  138. return cacheVal == currVal
  139. }
  140. }
  141.  
  142. this.fixValue = (key) => {
  143. if (win.fixValue) {
  144. this.fixValue = (value) => win.fixValue(value)
  145. return win.fixValue(key)
  146. }
  147. this.fixValue = (value) => value
  148. return key
  149. }
  150. this.cache = this.loadMapFromLocalStorage()
  151. this.autoSave()
  152. }
  153.  
  154. get(value) {
  155. value = this.fixValue(value)
  156. let idx = this.cache.findIndex(cacheVal => this.compare(cacheVal, value))
  157. if (idx > -1) {
  158. // 如果存在,则先删除再添加,以更新Map中的顺序(模拟最近最少使用)
  159. this.cache.splice(idx, 1)
  160. this.cache.push(value)
  161. return value
  162. }
  163. return null
  164. }
  165.  
  166. put(value) {
  167. value = this.fixValue(value)
  168. let idx = this.cache.findIndex(cacheVal => this.compare(cacheVal, value))
  169. if (idx > -1) {
  170. // 如果键已经存在,先删除旧值
  171. this.cache.splice(idx, 1)
  172. } else if (this.cache.length >= this.capacity) {
  173. // 如果达到容量限制,删除最老的项
  174. this.cache.splice(0, this.cache.length - this.capacity)
  175. }
  176. // 添加新值
  177. this.cache.push(value)
  178. }
  179. clearAllCache() {
  180. this.cache.length = 0
  181. this.saveMapToLocalStorage()
  182. }
  183. }
  184.  
  185. // createSuperLabel 创建超链接,不会被拦截
  186. function createSuperLabel(url, id, downloadName, win) {
  187. win = win ?? window
  188. id = getUrlWithoutHost(url)
  189. if (downloadName) {
  190. if (localStorage.getItem("autoclosewindow") == 'Auto') {
  191. if (win.closeTimer) {
  192. win.clearTimeout(win.closeTimer)
  193. }
  194. win.closeTimer = setTimeout(function () {
  195. win.open("about:blank", "_self").close()
  196. }, 500)
  197. }
  198. win.open(url, '_blank')
  199. return true
  200. }
  201. else {
  202. const cached = win.__LRUCache.get(id)
  203. const isNotHit = !cached
  204. if (isNotHit) {
  205. win.__LRUCache.put(id, true)
  206. win.open(url, '_blank')
  207. console.log(cached, !isNotHit, id)
  208. return true
  209. }
  210. console.log(cached, !isNotHit, id)
  211. }
  212. return false
  213. }
  214.  
  215. function unique(arr) {
  216. let obj = {}
  217. return arr.filter(function (item, index, arr) {
  218. return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
  219. })
  220. }
  221.  
  222. /// ignore \r \t \n space and caseinsitive
  223. function a_Contains_b(a, b) {
  224. a = a.replace(/(\r\n|[\n\r\t ])/g, "").toLowerCase()
  225. b = b.replace(/(\r\n|[\n\r\t ])/g, "").toLowerCase()
  226. if (!!a && !!b && a.includes(b)) {
  227. return true
  228. }
  229.  
  230. return false
  231. }
  232. function createMenu($, win, isList, funcDownload, funcList, funcDetail) {
  233. win = win || window
  234. funcDownload = funcDownload ?? win.funcDownload
  235. funcList = funcList ?? win.funcList
  236. funcDetail = funcDetail ?? win.funcDetail
  237.  
  238. let w = 40, h = 40;
  239. addStyle(`
  240. a:link{color:green;}
  241. a:hover{color:red;}
  242. a:active{color:yellow;}
  243. a:visited{color:orange;}
  244. .btn1 {
  245. opacity:0.8;-moz-transition-duration:0.2s;-webkit-transition-duration:0.2s;
  246. padding:1px; margin-top:1px;
  247. font-size: 10; text-align: center; vertical-align: middle; line-height:${h}px;
  248. border-radius:5px 5px 5px 5px;cursor:pointer; left:0px;z-index:9999;
  249. background:white;
  250. width:${w}px;height:${h}px;
  251. }
  252. `);
  253. let container = $(document.createElement('div')).css({
  254. 'cssText': `position:fixed;top:15%;width:${w}px;height:${h * 7}px;left:0px;z-index:9999`
  255. });
  256.  
  257. let downloadBtn, closeBtn, fastBtn, switchBtn, slowBtn
  258. if (!isList) {
  259.  
  260. //下载按钮
  261. downloadBtn = $(document.createElement('div')).text('下載').appendTo(container)
  262. .click(function () {
  263. funcDownload()
  264. });
  265. //close
  266. closeBtn = $(document.createElement('div')).text('關閉').appendTo(container)
  267. .click(function () {
  268. win.open("about:blank", "_self").close();
  269. })
  270. //加速
  271. fastBtn = $(document.createElement('div')).text('加速').attr('title', '加速').appendTo(container)
  272. .click(function () {
  273. if (win.__wait > 5) {
  274. win.__wait = win.__wait / 1.5
  275. } else {
  276. win.__wait = 5
  277. }
  278. win.___reset()
  279.  
  280. })
  281. switchBtn = $(document.createElement('div')).text(!win.__t ? '啓' : '停').appendTo(container)
  282. .click(function () {
  283. if (!win.__t) {
  284. win.__startTimer();
  285. } else {
  286. win.__stopTimer()
  287. }
  288. })
  289. slowBtn = $(document.createElement('div')).text('減速').attr('title', '減速').appendTo(container)
  290. .click(function () {
  291. win.__wait *= 1.5
  292. win.___reset()
  293. })
  294.  
  295. $(document).keydown(function (event) {
  296. let e = event || win.event;
  297. let k = e.keyCode || e.which;
  298. if (k === 16) {
  299. // isCtrl = true;
  300. switchBtn.click()
  301. } else if (k === 38) { //up
  302. event.stopPropagation()
  303. slowBtn.click()
  304.  
  305. } else if (k === 40) {//down
  306. event.stopPropagation()
  307. //fastBtn.click()
  308. }
  309. })
  310. $(document).mousedown(function (e) {
  311. if (e.which == 2) {
  312. downloadBtn.click();
  313. }
  314. })
  315. $(win).blur(function () {
  316. win.__stopTimer()
  317. }).focus(function () {
  318. win.__startTimer();
  319. })
  320.  
  321. win.__wait = 900
  322. win.__step = 100;
  323. win.__startTimer = function () {
  324. win.______h = $(document).scrollTop() + win.__step;
  325. if (win.______h >= $(document).height() - $(win).height()) {
  326. win.__stopTimer()
  327. // win.__t = setTimeout(win.__startTimer, 30000)
  328. } else {
  329. $(document).scrollTop(win.______h);
  330. win.__t = setTimeout(win.__startTimer, win.__wait)
  331. }
  332. win.__syncState()
  333. };
  334. win.__stopTimer = function () {
  335. clearTimeout(win.__t)
  336. win.__t = 0
  337. win.__syncState()
  338. }
  339. win.___reset = function () {
  340. win.__stopTimer()
  341. win.__startTimer();
  342. win.__syncState()
  343. }
  344. win.__syncState = function () {
  345. fastBtn.text(`${Math.floor(win.__wait)}`)
  346. slowBtn.text(`${Math.floor(win.__wait)}`)
  347. switchBtn.text(win.__t ? '停' : '啓')
  348. }
  349. }
  350. else {
  351. $('tr').hover(
  352. function () {
  353. $(this).find('*').css("background-color", "#9AAAC7")
  354. }, function () {
  355. $(this).find('*').css("background-color", '');
  356. });
  357. }
  358. //最顶按钮
  359. let
  360. toTopBtn = $(document.createElement('div')).text('Top').appendTo(container)
  361. .click(function () {
  362. win.scrollTo(0, 0);
  363. }), //最低按钮
  364. toBottomBtn = $(document.createElement('div')).text('Bottom').appendTo(container)
  365. .click(function () {
  366. win.scrollTo(0, document.body.scrollHeight);
  367. }),
  368. setBtn = $(document.createElement('div')).attr('id', 'btnSet').text('設置').appendTo(container)
  369. .click(function () {
  370. win.gmc.open();
  371. });
  372. container
  373. .find('div')
  374. .addClass('btn1')
  375. .hover(function (e) {
  376. let o = $(this)
  377. o.data('old_opacity', o.css('opacity'))
  378. .data('old_border', o.css('border'))
  379. o.css('opacity', 1).css('border', '1px solid black')
  380. }, function (e) {
  381. let o = $(this)
  382. o.css('opacity', o.data('old_opacity')).css('border', o.data('old_border'))
  383. })
  384. let clearBtn = $(document.createElement('div')).attr('id', 'clear').text('clear').appendTo(container)
  385. clearBtn.click(function () {
  386. win.__LRUCache.clearAllCache()
  387. })
  388. let autocloseBtn = $(document.createElement('div')).attr('id', 'autoclose').text(`${localStorage.getItem("autoclosewindow") ?? 'Keep'}`).appendTo(container)
  389. autocloseBtn.click(function () {
  390. localStorage.setItem("autoclosewindow", `${localStorage.getItem("autoclosewindow") == 'Auto' ? 'Keep' : 'Auto'}`)
  391. $(this).text(`${localStorage.getItem("autoclosewindow") ?? 'Keep'}`)
  392. })
  393.  
  394. container.appendTo('body');
  395. if (isList) {
  396. if (typeof funcList === 'function') {
  397. funcList(container)
  398. }
  399. } else {
  400. if (typeof funcDetail === 'function') {
  401. funcDetail(container)
  402. }
  403. }
  404.  
  405. }
  406. function autoFind(funcIsListPage, cmgId, selector, funcText, $, elBindOpen, unsafeWindow, funcDownload, funcList, funcDetail) {
  407. let isList = funcIsListPage()
  408. win = unsafeWindow || window
  409. createMenu($, unsafeWindow, isList, funcDownload, funcList, funcDetail)
  410.  
  411. new Promise(resovle => resovle(new GM_config({
  412. id: `GM_config_${cmgId}`,
  413. title: 'javdb Configurable Options Script',
  414. fields: {
  415. asdf: {
  416. label: 'Search keys',
  417. type: 'textarea',
  418. rows: 30,
  419. cols: 50,
  420. default: '调J; 阴环;18岁;19岁;20岁;gvh;sm;tki;一字马;一线天;乳环;固定;圈养;奴隶;实录;性奴;拘;拘束;拷问;捆绑;挛;无毛;束;束缚;母G;母狗;痉;白虎;紧缚;萝莉;调教;软派;软体;缚;身动;绑;;肛塞;尾巴;极品;奴宠; 淫媚;尤物;凌辱;屈辱;少女;天然;素人;清纯;耻;調J; 陰環;18歲;19歲;20歲;18歳;20歳;21歳;一字馬;一綫天;乳環;圈養;奴隸;實錄;拷問;捆綁;攣;無毛;束縛;痙;緊縛;蘿莉;調教;軟派;軟體;縛;身動;綁;極品;奴寵;清純;恥;GIF;潮吹;陵辱;19歳;痉挛;弓背;高潮',
  421.  
  422. },
  423. isRunInNewTabs: {
  424. options: ['Auto Run In New Tab', 'Not Run In New Tab'],
  425. label: 'Auto Run In New Tab?',
  426. type: 'radio',
  427. default: 'Auto Run In New Tab',
  428. },
  429. },
  430. events:
  431. {
  432. open() {
  433. let vals = unique(this.get('asdf').split(/[;;,,]/g)).join(';')
  434. this.set('asdf', vals)
  435. },
  436. save() {
  437. let vals = unique(this.get('asdf').split(/[;;,,]/g)).join(';')
  438. this.set('asdf', vals)
  439. },
  440. },
  441. })))
  442. .then((gmc) => {
  443. setTimeout(() => $(elBindOpen).click(() => gmc.open()), 500)
  444. return gmc
  445. })
  446. .then((gmc) => {
  447. win.gmc = gmc
  448. if (!funcIsListPage(gmc))
  449. throw new Error(`no run due to contion failed`)
  450. // list页面添加事件,关闭页面时候保存缓存
  451. win.__LRUCache = new LRUCache("__vistList", 500, win)
  452. win.addEventListener('beforeunload', function (event) {
  453. win.__LRUCache?.saveMapToLocalStorage()
  454. })
  455. $(document).keydown(function (event) {
  456. win.__LRUCache?.saveMapToLocalStorage()
  457. })
  458. $(win).bind("onunload", function (event) {
  459. win.__LRUCache?.saveMapToLocalStorage()
  460. })
  461. $(document).mousedown(function (e) {
  462. if (e.which == 2) {
  463. win.__LRUCache?.saveMapToLocalStorage()
  464. }
  465. })
  466. return gmc
  467. })
  468. .then((gmc) => {
  469. return { gmc, conf: gmc.get('asdf') }
  470. },
  471.  
  472. )
  473. .then(({ gmc, conf }) => {
  474. console.log('config value of keys', conf)
  475. return ({ gmc, keys: conf.split(/[;;,,]/) })
  476. })
  477. .then(({ gmc, keys }) => {
  478. $(selector).each((i, element) => {
  479. let el = $(element)
  480. $.each(keys, (inex, key) => {
  481. if (a_Contains_b(funcText(el), key)) {
  482. let res = el.prop ? createSuperLabel(el.prop('href'), el.prop('href'), null, win) : createSuperLabel(el.attr('href'), el.attr('href'), null, win)
  483.  
  484. return false
  485. }
  486. })
  487. })
  488. return { gmc, keys }
  489. })
  490. .catch(e => console.log('error', e))
  491. };