Black Belt

Finds useful links and displays a top bar with various of links from contact details to media documents, including Metalinks, Podcasts, Syndication Feeds (Atom, JSON & RSS), Torrents and Userscripts. Also supports Chat, Email, Geoposition, IPFS, Magnet links of eXact Topic (xt), VoIP, Wallet schemes and more.

当前为 2023-05-17 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Black Belt
  3. // @author Schimon Jehudah, Adv.
  4. // @namespace i2p.schimon.blackbelt
  5. // @homepageURL https://greasyfork.org/en/scripts/466113-black-belt
  6. // @supportURL https://greasyfork.org/en/scripts/466113-black-belt/feedback
  7. // @copyright 2023, Schimon Jehudah (http://schimon.i2p)
  8. // @license MIT; https://opensource.org/licenses/MIT
  9. // @description Finds useful links and displays a top bar with various of links from contact details to media documents, including Metalinks, Podcasts, Syndication Feeds (Atom, JSON & RSS), Torrents and Userscripts. Also supports Chat, Email, Geoposition, IPFS, Magnet links of eXact Topic (xt), VoIP, Wallet schemes and more.
  10. // @include *
  11. // @version 23.05.18
  12. // @run-at document-end
  13. // @noframes
  14. // @icon data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMDAgMTAwIj48dGV4dCB5PSIuOWVtIiBmb250LXNpemU9IjkwIj7wn6WLPC90ZXh0Pjwvc3ZnPg==
  15. // ==/UserScript==
  16.  
  17. // NOTE
  18. // Robe icons (Sauna pack) created by Freepik
  19. // https://www.flaticon.com/free-icon/robe_2520932
  20. // https://www.flaticon.com/authors/freepik
  21. // https://www.freepik.com/
  22.  
  23. // TODO
  24. //
  25. // 0) Bar like https://www.croxyproxy.com/
  26. //
  27. // 0) Decode string for magnet links
  28. // https://btdig.com/9fe6281eaf39f8bee656f27cacf48713c0608c3e/20-birds-&-animals-books-collection-pack-4
  29. //
  30. // 0) Tooltip
  31. // https://www.w3schools.com/howto/howto_css_tooltip.asp
  32. // or DIV on the middle or center of screen
  33. // https://web.archive.org/web/20050423235409/http://karmatics.com/aardvark/
  34. // https://css-tricks.com/quick-css-trick-how-to-center-an-object-exactly-in-the-center/
  35. //
  36. // 1) Brand: Access Bar, Alt Bar, Black Bar, Black Robe, Distribar, Distributed Bar, Distribution Bar, Easy Access Bar, Free Bar, Freenet Bar, Handler Bar, Harvest Bar, IETF Bar, IETF Black Bar, IETF ToolBar, Instant Media Bar, Media Bar, Power Bar, Power Download Bar, Reaping Bar, Simple Access Bar, Simple Bar, Super Bar
  37. //
  38. // 2) Recognize btih of 32 and convert it to 40
  39. //
  40. // 3) Check cache links for none 200 code
  41. // https://bookshelf.theanarchistlibrary.org/library/librarian-previous-announcements-en
  42. //
  43. // 4) FIXME feedx
  44. // http://freebase.be/db/software.rss.xml
  45. //
  46. // 5) Case insensitive (XPath)
  47. // String.prototype.toLowerCase()
  48. // See 'Magnet:' heperlink at https://ddosecrets.com/wiki/Rosatom
  49. // See getPathTo()
  50. //
  51. // 6) Fetch button (guess on demand) instead of auto-guess
  52. // Find file by Hash or ID (Hint: find duplicate chars/strings)
  53. //
  54. // 7) Display software for IPFS, GPS, Monero, RSS, SIP, Tribler, XMPP
  55. //
  56. // 8) Market diaspora*, Linux, Mastodon, ownCloud, RetroShare
  57. //
  58. // 9) TODO cancel *:after "open in new tab" https://cookidoo.thermomix.com/foundation/en-US
  59.  
  60. const types = [
  61. 'alt,📰,feed_a,Follow,Subscribe to News Feed', //索 //參
  62. 'ext,📱,app_android,Android', //App Installer (Android)
  63. 'ext,🗝️,asc,ASC Key,Additional Sense Code',
  64. 'ext,🔵️,chromium,Chromium',
  65. 'ext,🐧️,debian,Debian',
  66. 'ext,📰,feed_x,Follow,Subscribe to News Feed',
  67. 'ext,🐧️,flatpak,Linux',
  68. 'ext,📍️,geo_x,Location',
  69. 'ext,🐯️,mac,OSX',
  70. 'ext,♾️,metalink,Metalink', //∞
  71. 'ext,📦️,torrent,Torrent',
  72. 'ext,📜,userjs,Userscript', //🐒
  73. 'ext,📥️,reactos,React OS',
  74. 'ext,🐺️,xpi,LibreWolf', //🦊️
  75. 'uri,🫐️,adc,DC', //⚛️
  76. 'uri,🛍️,appstream,AppStream', //👜️
  77. // if (type[5]) { ele.style.transform = 'rotate(90deg)' }
  78. 'uri,🔽,cabal,Cabal', //︾ //🔽 //⧩ //➤
  79. 'uri,👁️‍🗨️️,chateye,Chat,WARNING: This chat service logs your conversations to its records. Use XMPP instead',
  80. 'uri,♈,ed2k,eDonkey',
  81. 'uri,✉️,email,Email,Send an Email Message',
  82. 'uri,📰,feed,Follow,Subscribe to News Feed',
  83. 'uri,📍️,geo,Location',
  84. 'uri,💠,ipfs,IPFS', //📁 //📂 //🗃️ //⚛️ //💎️ //🕸️
  85. 'uri,🗨️,irc,IRC',
  86. 'uri,🎙️,itpc,Podcast',
  87. // (Supports VoIP and OMEMO & OpenPGP encryption methods)
  88. 'uri,💡️,jid,Jabber,Chat securely over the XMPP network.',
  89. //'uri,🧲,magnet,Magnet',
  90. 'uri,#️,matrix,Matrix,We recommend using XMPP instead, for better privacy.', //#️⃣️ //# //⌗ //濫
  91. 'uri,🐧️,openstore,Ubuntu Touch',
  92. 'uri,☎️,telephone,Call',
  93. 'uri,📶,udp,Tracker',
  94. 'uri,📞️,voip,VoIP',
  95. 'uri,🪙️,wallet,Wallet',
  96. 'url,㊙️,i2p,i2p', //㊣
  97. 'url,🧅️,onion,Onion',
  98. 'urn,♈,aich,eDonkey',
  99. 'urn,🪩,bitprint,Gnutella2',
  100. 'urn,🌊️,btih,BitTorrent',
  101. 'urn,⛲️,btmh,BitTorrent2', //💧️
  102. 'urn,♈,ed2k_u,eDonkey',
  103. 'urn,⏭️,kzhash,Fasttrack',
  104. 'urn,❤️‍🔥️,md5,Shareaza',
  105. 'urn,❄️,sha1,Frostwire',
  106. 'urn,🌬️,tiger,DC',
  107. 'web,🟢️,app_android_w,Market', //📱
  108. 'web,🟤️,app_gallery_w,AppGallery', //📱
  109. 'web,🟣️,app_kaios_w,KaiStore',
  110. 'web,⚪️,app_ios_w,AppStore', //🍎️
  111. 'web,👁️‍🗨️️,chateye_w,Chat,WARNING: This chat service logs your conversations to its records. Use Use XMPP instead',
  112. 'web,🗨️,chat_w,Chat',
  113. 'web,🔵️,chromium_w,Chrome Store',
  114. 'web,🦅️,falkon,Falkon Store',
  115. 'web,🧊,flathub,Flatpak',
  116. 'web,🐲️,kde,KDE Store', //🪟️🏪️
  117. 'web,🔴️,mozilla,Mozilla Store',
  118. 'web,⚆,app_ubports_w,Open Store',
  119. 'web,🌕,palemoon,PaleMoon Store',
  120. 'web,🟠️,snapcraft,Snap Store', //🪶️
  121. 'web,🟡️,windows,Windows Store']; //🦎️
  122. // 'pge,✉️,contact,Contact'
  123.  
  124. // ADC aka DC (Advanced Direct Connect)
  125. const adc = [
  126. 'adc:',
  127. 'adcs:',
  128. 'dchub:'];
  129.  
  130. const aich = [
  131. 'aich'];
  132.  
  133. const asc = [
  134. '.asc',
  135. '.asc.txt',
  136. '.gpg',
  137. '.gpg.txt',
  138. '.pgp',
  139. '.pgp.txt'];
  140.  
  141. const app_android = [
  142. '.apk'];
  143.  
  144. const app_android_w = [
  145. '://f-droid.org/packages/',
  146. '://apt.izzysoft.de/fdroid/index/apk/',
  147. '://play.google.com/store/apps/details?id='];
  148.  
  149. const app_gallery_w = [
  150. '://appgallery.huawei.com/app/'];
  151.  
  152. const app_ios_w = [
  153. '://apps.apple.com/app/',
  154. '://apps.apple.com/us/app/'];
  155.  
  156. const app_kaios_w = [
  157. '://store.bananahackers.net/',
  158. '://www.kaiostech.com/store/apps/'];
  159.  
  160. const app_ubports_w = [
  161. '://open-store.io/app/'];
  162.  
  163. const appstream = [
  164. 'appstream:'];
  165.  
  166. const bitprint = [
  167. 'bitprint'];
  168.  
  169. const btih = [
  170. 'btih'];
  171.  
  172. const btmh = [
  173. 'btmh'];
  174.  
  175. const cabal = [
  176. 'cabal:'];
  177.  
  178. const chateye = [
  179. 'viber:',
  180. 'tencent:',
  181. 'tg:',
  182. 'whatsapp:'];
  183.  
  184. const chateye_w = [
  185. '://discord.com',
  186. '://discord.gg',
  187. '://t.me',
  188. '://telegram.me',
  189. '://chat.whatsapp.com',
  190. '://wa.me',
  191. '://api.whatsapp.com/send?phone=',
  192. '://web.whatsapp.com/send?phone=',
  193. '://m.me'];
  194.  
  195. const chat_w = [
  196. '://join.jabber.network/#',
  197. '://anonymous.cheogram.com',
  198. '://magicbroccoli.de/i/',
  199. '://webchat.disroot.org/#converse/room?jid=',
  200. '://xmpp.org/chat#converse/room?jid=',
  201. '://yaxim.org/chat/#converse/room?jid=',
  202. '://yax.im/i/'];
  203.  
  204. const chromium = [
  205. '.chrome.zip',
  206. '.chromium.zip',
  207. '.crx'];
  208.  
  209. const chromium_w = [
  210. '://chrome.google.com/webstore/detail/'];
  211.  
  212. const debian = [
  213. '.deb'];
  214.  
  215. const ed2k = [
  216. 'ed2k:'];
  217.  
  218. const ed2k_u = [
  219. 'ed2k',
  220. 'ed2khash'];
  221.  
  222. const email = [
  223. 'mailto:'];
  224.  
  225. const falkon = [
  226. '://store.falkon.org/p/'];
  227.  
  228. const feed = [
  229. 'feed:',
  230. 'news:'];
  231.  
  232. const feed_a = [
  233. 'atom',
  234. 'rss',
  235. 'stream',
  236. 'rdf',
  237. 'feed',
  238. 'feed+json'];
  239.  
  240. const feed_x = [
  241. '.atom', '.atom.php', '.atom.xml',
  242. '.rss', '.rss.php', '.rss.xml',
  243. '.rdf', '.rdf.php', '.rdf.xml'];
  244.  
  245. const flathub = [
  246. '://flathub.org/apps/details/'];
  247.  
  248. const flatpak = [
  249. '.flatpakref'];
  250.  
  251. const geo = [
  252. 'geo:',
  253. 'waze:'];
  254.  
  255. const geo_x = [
  256. '.gpx',
  257. '.geojson',
  258. '.kml',
  259. '.kmx'];
  260.  
  261. const i2p = [
  262. '.i2p',
  263. '.i2p:'];
  264.  
  265. const ipfs = [
  266. 'ipfs:',
  267. 'ipns:',
  268. 'dweb:'];
  269.  
  270. const irc = [
  271. 'ircs:',
  272. 'irc:'];
  273.  
  274. const itpc = [
  275. 'itpc:'];
  276.  
  277. // TODO handle ?join and ?message
  278. const jid = [
  279. 'xmpp:'];
  280.  
  281. const kde = [
  282. '://store.kde.org/p/'];
  283.  
  284. const kzhash = [
  285. 'kzhash'];
  286.  
  287. const mac = [
  288. '.pkg',
  289. '.dmg'];
  290.  
  291. const matrix = [
  292. 'element:',
  293. 'matrix:'];
  294.  
  295. const md5 = [
  296. 'md5'];
  297.  
  298. const metalink = [
  299. '.meta4',
  300. '.metalink'];
  301.  
  302. const windows = [
  303. '://apps.microsoft.com/store/detail/',
  304. '://microsoftedge.microsoft.com/addons/detail/',
  305. '://www.microsoft.com/store/apps/'];
  306.  
  307. const onion = [
  308. '.onion',
  309. '.onion:'];
  310.  
  311. const openstore = [
  312. 'openstore'];
  313.  
  314. const sha1 = [
  315. 'sha1'];
  316.  
  317. // TODO ask snapcraft for path /app/
  318. const snapcraft = [
  319. '://snapcraft.io/'];
  320.  
  321. const telephone = [
  322. 'tel:'];
  323.  
  324. const tiger = [
  325. 'tree:tiger'];
  326.  
  327. const torrent = [
  328. '.torrent'];
  329.  
  330. const udp = [
  331. 'udp:'];
  332.  
  333. const userjs = [
  334. '.user.js'];
  335.  
  336. const voip = [
  337. 'sip:',
  338. 'weixin:',
  339. 'skype:'];
  340.  
  341. const wallet = [
  342. 'monero:',
  343. 'ethereum:',
  344. 'litecoin:',
  345. 'bitcoin:'];
  346.  
  347. const reactos = [
  348. '.exe',
  349. '.msi'];
  350.  
  351. const xpi = [
  352. '.xpi',
  353. '.firefox.zip'];
  354.  
  355. const mozilla = [
  356. '://addons.mozilla.org'];
  357.  
  358. const palemoon = [
  359. '://addons.palemoon.org',
  360. '://realityripple.com/Software/XUL/',
  361. '://realityripple.com/Software/Mozilla-Extensions/'];
  362.  
  363. let eles = [];
  364.  
  365. // FIXME type to be applied everywhere
  366. let type = [];
  367.  
  368. const namespace = 'i2p.schimon.blackbelt';
  369.  
  370. function determineType(type) {
  371. type = type.split(',');
  372. // TODO find an alternative way
  373. // THIS IS NOT GOOD!
  374. // JSON might be a solution
  375. array = eval(type[2])
  376. switch (type[0]) {
  377.  
  378. case 'alt':
  379. extractRel(array, type);
  380. break;
  381.  
  382. case 'ext':
  383. extractFile(array, type);
  384. break;
  385.  
  386. case 'uri':
  387. extractURI(array, type);
  388. break;
  389.  
  390. case 'url':
  391. extractURL(array, type);
  392. break;
  393.  
  394. case 'urn':
  395. extractURN(array, type);
  396. break;
  397.  
  398. case 'web':
  399. extractWeb(array, type);
  400. break;
  401. }
  402. }
  403.  
  404. // NOTE TODO semi-recursive callback
  405. // NOTE TODO typeof
  406. function extractFile(array, type) {
  407. if (checkID(type)) {return};
  408. let i = 0;
  409.  
  410. do {
  411. // FIXME Mainstream to support ends-with
  412. // fn:ends-with appears to be missing in some engines
  413. query = [
  414. '//a[contains(@href, "' + array[i] + '")]/@href',
  415. '//a[contains(@download, "' + array[i] + '")]/@download'];
  416. // '//a[ends-with(@href, "' + array[i] + '")]/@href'
  417. // '//a[ends-with(text(), "' + array[i] + '")]/@href'
  418. result = executeQuery(query, 'xpath');
  419. i = i + 1;
  420. } while (!result && i < array.length);
  421.  
  422. if (result) {
  423. protocol = location.protocol
  424. hostname = location.hostname
  425. //console.log(result)
  426. switch (true) {
  427.  
  428. case (result.startsWith('/')):
  429. result = protocol + '//' + hostname + result;
  430. break;
  431.  
  432. case (!result.includes(':')):
  433. result = protocol + '//' + hostname + '/' + result;
  434. break;
  435.  
  436. //case (result.startsWith('http')):
  437. //break;
  438. }
  439.  
  440. //console.log(result)
  441. let url = new URL(result);
  442. let bol = url.pathname.endsWith(array[i-1]);
  443. if (bol) { createLink(result, type) };
  444. }
  445. }
  446.  
  447.  
  448. function extractRel(array, type) {
  449. if (checkID(type)) {return};
  450. let i = 0;
  451.  
  452. do {
  453. query = [
  454. // Also rel="feed". See https://miranda-ng.org/
  455. '//link[@rel="alternate"\
  456. and contains(@type, "' + array[i] + '")\
  457. ]/@href'];
  458. result = executeQuery(query, 'xpath');
  459. i = i + 1;
  460. } while (!result && i < array.length);
  461.  
  462. if (result) { createLink(result, type) };
  463. }
  464.  
  465.  
  466. function extractURI(array, type) {
  467. if (checkID(type)) {return};
  468. let i = 0;
  469.  
  470. do {
  471. query = [
  472. '//a[starts-with(@href, "' + array[i] + '")\
  473. and not(starts-with(@href, "tg://msg_url?"))\
  474. and not(starts-with(@href, "mailto:?"))\
  475. and not(contains(@href, "/send?"))\
  476. ]/@href'];
  477. result = executeQuery(query, 'xpath');
  478. i = i + 1;
  479. } while (!result && i < array.length);
  480.  
  481. if (result) {
  482. let url = new URL(result);
  483. let bol = url.protocol.match(array[i-1]);
  484. if (bol) { createLink(result, type) };
  485. }
  486. }
  487.  
  488.  
  489. function extractURL(array, type) {
  490. if (checkID(type)) {return};
  491. let i = 0;
  492.  
  493. do {
  494. query = [
  495. '//a[starts-with(@href, "http")\
  496. and contains(@href, "' + array[i] + '")\
  497. ]/@href'];
  498. // FIXME mainstream
  499. //'//a[starts-with(@href, "http") and ends-with(@href, "' + array[i] + '")]/@href'
  500. result = executeQuery(query, 'xpath');
  501. i = i + 1;
  502. } while (!result && i < array.length);
  503.  
  504. if (result) {
  505. let url = new URL(result);
  506. let bol = url.hostname.endsWith(array[i-1]);
  507. if (bol) { createLink(result, type) };
  508. //if (!url) {
  509. // url = url.host.contains(array[i] + ':');
  510. //}
  511. }
  512. }
  513.  
  514.  
  515. function extractURN(array, type) {
  516. if (checkID(type)) {return};
  517. let i = 0;
  518.  
  519. do {
  520. query = [
  521. '//a[starts-with(@href, "magnet")\
  522. and contains(@href, "' + array[i] + '")\
  523. ]/@href'];
  524. result = executeQuery(query, 'xpath');
  525. i = i + 1;
  526. } while (!result && i < array.length);
  527.  
  528. if (result) {
  529. let url = new URL(result);
  530. url.searchParams.delete('tr');
  531. result = url.protocol + url.search;
  532. result = decodeURIComponent(result);
  533. createLink(result, type)
  534. //let bol = url.hostname.startsWith(array[i-1]);
  535. //if (bol) { createLink(result, type) };
  536. }
  537. }
  538.  
  539.  
  540. function extractWeb(array, type) {
  541. if (checkID(type)) {return};
  542. let i = 0;
  543.  
  544. do {
  545. query = [
  546. '//a[starts-with(@href, "http")\
  547. and contains(@href, "' + array[i] + '")\
  548. and not(starts-with(@href, "https://wa.me/?text"))\
  549. and not(starts-with(@href, "https://t.me/share"))\
  550. and not(starts-with(@href, "https://telegram.me/share"))\
  551. and not(contains(@href, "com.github.android"))\
  552. and not(contains(@href, "1477376905"))\
  553. ]/@href'];
  554. result = executeQuery(query, 'xpath');
  555. i = i + 1;
  556. } while (!result && i < array.length);
  557.  
  558. if (result) { createLink(result, type) };
  559. }
  560.  
  561.  
  562. // TODO
  563. // String.prototype.toLowerCase()
  564. // href Magnet: (magnet:) is not detected, or
  565. // Set document MIMEType to plain/text
  566. function executeQuery(queries, method) {
  567.  
  568. let i = 0;
  569. do {
  570. switch(method) {
  571. case 'css':
  572. result = document.querySelector(queries[i]);
  573. //if (result) {result = result.href};
  574. if (result) {return result.href};
  575. break;
  576.  
  577. case 'xpath':
  578. // NOTE This may cause 404 error.
  579. // Use getPathTo()
  580. // https://stackoverflow.com/questions/2631820/how-do-i-ensure-saved-click-coordinates-can-be-reload-to-the-same-place-even-if/2631931#2631931
  581. /*
  582. xhtmlFile = new XMLSerializer().serializeToString(document).toLowerCase()
  583. //xhtmlFile = '<html>'+document.documentElement.innerHTML.toLowerCase()+'</html>'
  584. domParser = new DOMParser();
  585. xhtmlFile = domParser.parseFromString(xhtmlFile, 'text/html');
  586. result = document.evaluate(
  587. queries[i], xhtmlFile, null, XPathResult.STRING_TYPE);
  588. */
  589. result = document.evaluate(
  590. queries[i], document, null, XPathResult.STRING_TYPE);
  591. //if (result) {result = result.stringValue};
  592. if (result) {return result.stringValue};
  593. }
  594. } while (!result && i < queries.length);
  595. }
  596.  
  597. function checkID(type) {
  598. for (let i = 0; i < eles.length; i++) {
  599. if (eles[i].id === type[3] + '_' + type[1] + '_OUJS') {
  600. return true;
  601. }
  602. }
  603. }
  604.  
  605. function createLink(uri, type) {
  606. //if (type[4]) {
  607. //let tip = document.createElement('spna');
  608. //tip.class = 'tooltip';
  609. //tip.append('type[4]');
  610. //}
  611.  
  612. //type = type.split(' ');
  613. //sym = getUrnProperty(uri, 'sym');
  614. //net = getUrnProperty(uri, 'net');
  615.  
  616. let ele = document.createElement('a');
  617. ele.append(type[1] + ' ' + type[3]);
  618. ele.href = uri;
  619. ele.id = type[3] + '_' + type[1] + '_OUJS';
  620. if (type[4]) { ele.title = type[4] }
  621. ele.style.all = 'unset';
  622. ele.style.color = '#eee';
  623. ele.style.font = 'caption';
  624. ele.style.fontFamily = 'arial';
  625. ele.style.fontSize = '15px'; // 13px
  626. ele.style.fontVariantCaps = 'all-small-caps';
  627. ele.style.padding = '3px 9px 3px 9px';
  628. ele.style.textDecoration = 'none';
  629. ele.style.cursor = 'pointer';
  630.  
  631. //ele.style.forEach (style => style + '!important');
  632. for (let i = 0; i < ele.style.length; i++) {
  633. ele.style.setProperty(ele.style[i], ele.style.getPropertyValue(ele.style[i]), 'important');
  634. }
  635.  
  636. //ele.append(tip);
  637.  
  638. //console.log(ele)
  639. //console.log(eles)
  640. eles.push(ele);
  641. }
  642.  
  643. // TODO if eles[i].id does not exist
  644. types.forEach(type => determineType(type));
  645.  
  646.  
  647. // Torrent V1
  648. // TODO handle compressed sha1 http://www.debath.co.uk/MakeAKey.html
  649. // TODO convert base32 to hash
  650. // 32/40 https://linuxtracker.org/?page=torrent-details&id=173a0f61ef92b158547937fa0c01e9dc704779f9
  651. function generateTorrent() {
  652. for (let i = 0; i < eles.length; i++) {
  653. if (eles[i].id === 'Torrent_📦️_OUJS') {
  654. return
  655. // TODO generate link else-if onclick
  656. // 404 https://bookshelf.theanarchistlibrary.org/library/librarian-previous-announcements-en#toc1
  657. } else {
  658. if (eles[i].id === 'BitTorrent_🌊️_OUJS') {
  659. href = eles[i].href;
  660. let url = new URL(href);
  661. name = url.searchParams.get('dn');
  662. if (!name) {name = document.title};
  663. //xt = url.searchParams.get('xt');
  664. hash = url.searchParams.get('xt').slice(9);
  665. //if (ha.length === 40 && xt.startsWith('urn:btih'))
  666. if (hash.length === 40) {
  667. links = [
  668. 'https://watercache.libertycorp.org/get/' + hash + '/' + name,
  669. 'https://itorrents.org/torrent/' + hash + '.torrent?title=' + name,
  670. 'https://firecache.libertycorp.org/get/' + hash + '/' + name,
  671. 'http://fcache63sakpihd44kxdduy6kgpdhgejgp323wci435zwy6kiylcnfad.onion/get/' + hash + '/' + name,
  672. ];
  673. //type = types.findIndex(element => element === 'ext 📦️ torrent TORRENT');
  674. //type = type.split(' ');
  675. type = 'ext,📦️,torrent,TORRENT'; //🧧️ //🎁️
  676. type = type.split(',');
  677. //console.log('links[1]')
  678. //console.log(links[1])
  679. //console.log('result')
  680. //console.log(result)
  681. createLink(links[1], type)
  682. }
  683. }
  684. }
  685. }
  686. }
  687.  
  688.  
  689. if (eles.length > 0) {
  690. let bar = document.createElement(namespace);
  691. bar.style.all = 'unset';
  692. bar.style.opacity = 0.75;
  693. bar.style.backgroundColor = '#000'; //'#2c3e50';
  694. bar.style.color = '#eee';
  695. //bar.style.setProperty("color", "#eee", "!important")
  696. bar.style.fontVariant = 'small-caps';
  697. bar.style.left = 0;
  698. bar.style.right = 0;
  699. bar.style.top = 0;
  700. bar.style.zIndex = 10000000000;
  701. bar.style.maxHeight = 'fit-content';
  702. bar.style.padding = '6px'; //13px //15px //11px //9px //6px //3px //1px
  703. bar.style.position = 'fixed';
  704. bar.style.textAlign = 'center';
  705. bar.style.direction = 'ltr';
  706. bar.style.opacity = 0.5;
  707. bar.style.userSelect = 'none';
  708. bar.onclick = () => { bar.remove(); }
  709. bar.onmouseover = () => { bar.style.opacity = 0.9; }
  710. bar.onmouseout = () => {
  711. var secs = 20;
  712. function timeOut() {
  713. bar.onmouseout = () => { secs = 20; }
  714. secs -= 1;
  715. if (secs == 17) {
  716. bar.style.opacity = 0.3;
  717. setTimeout(timeOut, 1000);
  718. } else if (secs == 0) {
  719. bar.remove();
  720. return;
  721. } else {
  722. setTimeout(timeOut, 1000);
  723. }
  724. } timeOut();
  725. }
  726. for (let i = 0; i < bar.style.length; i++) {
  727. bar.style.setProperty(bar.style[i], bar.style.getPropertyValue(bar.style[i]), 'important');
  728. }
  729.  
  730. // document.body should be enough
  731. const top = document.querySelector('body');
  732. top.prepend(bar);
  733.  
  734. generateTorrent()
  735.  
  736. eles.forEach(ele => bar.append(ele));
  737. //console.log("eles.forEach(ele => bar.append(ele));")
  738. //console.log(eles)
  739.  
  740. // Timer from https://stackoverflow.com/questions/27406765/hide-div-after-x-amount-of-seconds
  741.  
  742. var secs = 33;
  743. function timeOut() {
  744. secs -= 1;
  745. if (secs == 0) {
  746. //bar.style.display = 'none';
  747. bar.style.opacity = 0.2;
  748. return;
  749. }
  750. else {
  751. setTimeout(timeOut, 1000);
  752. }
  753. }
  754. timeOut();
  755. }