common_libs_of_array

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

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.sleazyfork.org/scripts/476583/1526778/common_libs_of_array.js

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