Twitter外部翻译器

将第三方翻译添加到推特

  1. // ==UserScript==
  2. // @name Twitter External Translator
  3. // @name:bg Външен преводач на Twitter
  4. // @name:zh Twitter外部翻译器
  5. // @name:zh-CN Twitter外部翻译器
  6. // @name:zh-TW Twitter外部翻译器
  7. // @name:cs Externí překladatel Twitter
  8. // @name:da Twitter ekstern oversætter
  9. // @name:et Twitteri väline tõlkija
  10. // @name:fi Twitter Ulkoinen kääntäjä
  11. // @name:el Εξωτερικός μεταφραστής Twitter
  12. // @name:hu Twitter külső fordító
  13. // @name:lv Twitter Ārējais tulkotājs
  14. // @name:lt 'Twitter' išorinis vertėjas
  15. // @name:ro Twitter Traducător extern
  16. // @name:sk Externý prekladateľ Twitter
  17. // @name:sl Twitter Zunanji prevajalec
  18. // @name:sv Twitter Extern översättare
  19. // @name:nl Twitter Externe Vertaler
  20. // @name:fr Traducteur externe Twitter
  21. // @name:de Externer Twitter-Übersetzer
  22. // @name:it Traduttore esterno di Twitter
  23. // @name:ja ツイッター外部翻訳者
  24. // @name:pl Zewnętrzny tłumacz Twittera
  25. // @name:pt Tradutor externo do Twitter
  26. // @name:pt-BR Tradutor externo do Twitter
  27. // @name:ru-RU Twitter Внешний переводчик
  28. // @name:ru Twitter Внешний переводчик
  29. // @name:es Traductor externo de Twitter
  30. // @description Adds external & internal translators to various sites.
  31. // @description:zh 将第三方翻译添加到推特
  32. // @description:zh-CN 将第三方翻译添加到推特
  33. // @description:zh-TW 將第三方翻譯添加到推特
  34. // @description:bg Добавя преводачи на трети страни в Twitter
  35. // @description:cs Přidává překladatele třetích stran na Twitter
  36. // @description:da Tilføjer tredjepartsoversættere til Twitter
  37. // @description:et Lisab kolmanda osapoole tõlkijad Twitterisse
  38. // @description:fi Lisää kolmannen osapuolen kääntäjiä Twitteriin
  39. // @description:el Προσθέτει μεταφραστές 3ου μέρους στο Twitter
  40. // @description:hu Hozzáadja a 3. féltől származó fordítókat a Twitterhez
  41. // @description:lv Pievieno trešās puses tulkotājus Twitter
  42. // @description:lt Prideda trečiųjų šalių vertėjus į 'Twitter
  43. // @description:ro Adaugă traducători de la terțe părți la Twitter
  44. // @description:sk Pridáva prekladateľov tretích strán na Twitter
  45. // @description:sl Dodaja prevajalce tretjih oseb na Twitterju
  46. // @description:sv Lägger till översättare från tredje part till Twitter
  47. // @description:nl Voegt vertalers van derden toe aan Twitter
  48. // @description:fr Ajout de traducteurs tiers à Twitter
  49. // @description:de Fügt Drittanbieter-Übersetzer zu Twitter hinzu
  50. // @description:it Aggiunge traduttori di terze parti a Twitter
  51. // @description:pl Dodaje tłumaczy innych firm do Twittera
  52. // @description:pt Adiciona tradutores de terceiros ao Twitter
  53. // @description:pt-BR Adiciona tradutores de terceiros ao Twitter
  54. // @description:ja サードパーティの翻訳者をツイッターに追加
  55. // @description:ru-RU Добавляет сторонних переводчиков в Twitter
  56. // @description:ru Добавляет сторонних переводчиков в Twitter
  57. // @description:es Añade traductores de terceros a Twitter
  58. // @author Magic <magicoflolis@tuta.io>
  59. // @version 2.6.1
  60. // @icon https://abs.twimg.com/favicons/twitter.ico
  61. // @namespace https://github.com/magicoflolis/twitter-translator#twitter-external-translator
  62. // @homepageURL https://github.com/magicoflolis/twitter-translator#twitter-external-translator
  63. // @supportURL https://github.com/magicoflolis/twitter-translator/issues/new
  64. // @license GPL-3.0
  65. // @connect *
  66. // @match https://mobile.x.com/*
  67. // @match https://x.com/*
  68. // @match https://mobile.twitter.com/*
  69. // @match https://twitter.com/*
  70. // @match https://tweetdeck.twitter.com/*
  71. // @match https://www.twitlonger.com/show/*
  72. // @match https://nitter.*/*
  73. // @match https://nitter.*.*/*
  74. // @match https://nitter.lacontrevoie.fr/*
  75. // @match https://nitter.fdn.fr/
  76. // @match https://nitter.kavin.rocks/*
  77. // @match https://nitter.moomoo.me/*
  78. // @match https://nitter.weiler.rocks/*
  79. // @match https://nitter.nl/*
  80. // @match https://nitter.esmailelbob.xyz/*
  81. // @match https://nitter.tiekoetter.com/*
  82. // @match https://nitter.poast.org/*
  83. // @match https://nitter.privacydev.net/*
  84. // @match https://nitter.projectsegfau.lt/*
  85. // @match https://nitter.in.projectsegfau.lt/*
  86. // @match https://canada.unofficialbird.com/*
  87. // @match https://nederland.unofficialbird.com/*
  88. // @match https://n.sneed.network/*
  89. // @match https://nitter.caioalonso.com/*
  90. // @match https://nitter.nicfab.eu/*
  91. // @match https://nitter.hostux.net/*
  92. // @match https://nitter.kling.gg/*
  93. // @match https://nitter.onthescent.xyz/*
  94. // @match https://nitter.oksocial.net/*
  95. // @match https://nitter.datura.network/*
  96. // @match https://nitter.catsarch.com/*
  97. // @exclude https://twitter.com/login
  98. // @exclude https://twitter.com/signup
  99. // @exclude https://twitter.com/i/flow/login
  100. // @exclude https://twitter.com/i/flow/signup
  101. // @exclude https://twitter.com/teams/*
  102. // @exclude https://twitter.com/*/authorize?*
  103. // @exclude https://twitter.com/*/begin_password_reset
  104. // @exclude https://twitter.com/account/*
  105. // @exclude https://mobile.twitter.com/i/flow/login
  106. // @exclude https://mobile.twitter.com/i/flow/signup
  107. // @exclude https://nitter.com
  108. // @grant navigator.userAgent
  109. // @grant document.cookie
  110. // @grant GM_getValue
  111. // @grant GM_setValue
  112. // @grant GM_info
  113. // @grant GM_openInTab
  114. // @grant GM_xmlhttpRequest
  115. // @compatible chrome
  116. // @compatible firefox
  117. // @compatible edge
  118. // @compatible opera
  119. // @compatible safari
  120. // @noframes
  121. // @run-at document-start
  122. // ==/UserScript==
  123. 'use strict';
  124. (() => {
  125. // Uncompressed source code:
  126. // https://github.com/magicoflolis/twitter-translator/src
  127. // eslint-disable-next-line no-unused-vars, quotes
  128. const tetCSS = `.r-1bih22f{box-shadow:rgb(29, 161, 242) 0px 0px 0px 1px}.r-1cqwhho{box-shadow:rgb(23, 191, 99) 0px 0px 0px 1px}.r-b8m25f{box-shadow:rgb(244, 93, 34) 0px 0px 0px 1px}.r-11mmphe{box-shadow:rgb(121, 75, 196) 0px 0px 0px 1px}.r-jd07pc{box-shadow:rgb(224, 36, 94) 0px 0px 0px 1px}.r-cdj8wb{box-shadow:rgb(255, 173, 31) 0px 0px 0px 1px}.tet-29u:not(.tetswitch){background-color:rgb(29, 155, 240)}.tet-186u:not(.tetswitch){background-color:rgb(0, 186, 124)}.tet-122u:not(.tetswitch){background-color:rgb(255, 122, 0)}.tet-120u:not(.tetswitch){background-color:rgb(120, 86, 255)}.tet-249u:not(.tetswitch){background-color:rgb(249, 24, 128)}.tet-255u:not(.tetswitch){background-color:rgb(255, 212, 0)}.tetswitch.tet-29u>input:checked+label{background-color:rgba(26,145,218,.384)}.tetswitch.tet-29u>input:checked+label:before{background-color:#1d9bf0}.tetswitch.tet-186u>input:checked+label{background-color:rgba(21,172,89,.384)}.tetswitch.tet-186u>input:checked+label:before{background-color:#00ba7c}.tetswitch.tet-122u>input:checked+label{background-color:rgba(220,84,31,.384)}.tetswitch.tet-122u>input:checked+label:before{background-color:#ff7a00}.tetswitch.tet-120u>input:checked+label{background-color:rgba(134,93,202,.384)}.tetswitch.tet-120u>input:checked+label:before{background-color:#7856ff}.tetswitch.tet-249u>input:checked+label{background-color:rgba(202,32,85,.384)}.tetswitch.tet-249u>input:checked+label:before{background-color:#f91880}.tetswitch.tet-255u>input:checked+label{background-color:rgba(230,156,28,.384)}.tetswitch.tet-255u>input:checked+label:before{background-color:#ffd400}.tetswitch.nitter>input:checked+label{background-color:rgba(255,108,96,.384)}.tetswitch.nitter>input:checked+label:before{background-color:#ff6c60}.tetswitch.tweetdeck>input:checked+label{background-color:rgba(29,161,242,.384)}.tetswitch.tweetdeck>input:checked+label:before{background-color:#1da1f2}#tetReset,#tetMenuButton>span{color:#fff !important}#tetSelector>select{background-color:rgba(0,0,0,0);border:rgba(0,0,0,0)}#tetSelector>select:focus{box-shadow:none !important}.navbackground.d1tet{background-color:rgba(91,112,131,.4)}.navbackground.d2tet{background-color:rgba(0,0,0,.4)}.navbackground.d3tet{background-color:rgba(91,112,131,.4)}.tet-header>span:last-child,.tet-at>span:last-child{color:#6e767d}.r-demo,.tet-help-container,#apifield,#tetSelector{border-color:rgba(0,0,0,0)}.r-demo.r-14lw9ot,.tet-help-container.r-14lw9ot,#apifield.r-14lw9ot,#tetSelector.r-14lw9ot{border-color:#536471}.r-demo.r-yfoy6g,.tet-help-container.r-yfoy6g,#apifield.r-yfoy6g,#tetSelector.r-yfoy6g{border-color:#38444d}.r-demo.nitter,.r-demo.r-tetTD,.r-demo.r-kemksi,.tet-help-container.nitter,.tet-help-container.r-tetTD,.tet-help-container.r-kemksi,#apifield.nitter,#apifield.r-tetTD,#apifield.r-kemksi,#tetSelector.nitter,#tetSelector.r-tetTD,#tetSelector.r-kemksi{border-color:#2f3336}.r-14lw9ot>div#tetName span{color:#536471}.r-kemksi>div#tetName span,.r-yfoy6g>div#tetName span{color:#6e767d}.tetBtn.nitter{border:rgba(0,0,0,0)}.Button--primary{border-color:#1da1f2;box-shadow:#1da1f2 0px 0px 0px 1px}.r-tetTD{border-radius:14px;background-color:#15202b}.r-tetTD#tetSelector.Button--primary:hover{border-color:#1da1f2;box-shadow:#1da1f2 0px 0px 0px 1px}.r-tetTD#tetSelector.Button--primary:hover #tetName span{color:#1da1f2}.r-tetTD #tetName span{color:#8899a6}.prf-header>div>.tet.tet-td{color:#fff !important}.tet-td{color:#8899a6}.tet-td#tetName{color:#1da1f2 !important}.tet-td#tetName span{color:inherit !important}.tet-td .tet-svg{fill:#1da1f2}.tet-border-black{border-color:#000}.r-9ilb82{color:#6e767d}.r-1kqtdi0{border-color:#2f3336}.r-p1n3y5{border-color:#1d9bf0 !important}.r-1q3imqu{background-color:#1a91da}.r-13gxpu9{color:#1d9bf0}.r-13gxpu9#tetName{color:#1d9bf0 !important}.r-13gxpu9#tetName span{color:inherit !important}.r-13gxpu9 .tet-svg{fill:#1d9bf0}.r-v6khid{border-color:#ffd400 !important}.r-61mi1v{color:#ffd400}.r-61mi1v#tetName{color:#ffd400 !important}.r-61mi1v#tetName span{color:inherit !important}.r-61mi1v .tet-svg{fill:#ffd400}.r-1kplyi6{background-color:#e69c1c}.r-1iofnty{border-color:#f91880 !important}.r-daml9f{color:#f91880}.r-daml9f#tetName{color:#f91880 !important}.r-daml9f#tetName span{color:inherit !important}.r-daml9f .tet-svg{fill:#f91880}.r-1ucxkr8{background-color:#ca2055}.r-njt2r9{background-color:#865dca}.r-hy56xe{border-color:#7856ff !important}.r-xfsgu1{color:#7856ff}.r-xfsgu1#tetName{color:#7856ff !important}.r-xfsgu1#tetName span{color:inherit !important}.r-xfsgu1 .tet-svg{fill:#7856ff}.tet-122hu{background-color:#dc541f}.r-1xl5njo{border-color:#ff7a00 !important}.r-1qkqhnw{color:#ff7a00}.r-1qkqhnw#tetName{color:#ff7a00 !important}.r-1qkqhnw#tetName span{color:inherit !important}.r-1qkqhnw .tet-svg{fill:#ff7a00}.r-zx61xx{background-color:#15ac59}.r-5ctkeg{border-color:#00ba7c !important}.r-nw8l94{color:#00ba7c}.r-nw8l94#tetName{color:#00ba7c !important}.r-nw8l94#tetName span{color:inherit !important}.r-nw8l94 .tet-svg{fill:#00ba7c}.r-yfoy6g{background-color:#15202b}.r-14lw9ot{background-color:#fff}.r-kemksi{background-color:#000}.r-18jsvk2{color:#0f1419 !important}.tweetdeck:not(.tetswitch){background-color:#1da1f2;color:#fff}.tweetdeck:not(.tetswitch)#tetName{color:#1da1f2}.tweetdeck:not(.tetswitch)#tetName span{color:inherit !important}.tweetdeck:not(.tetswitch) .tet-svg{fill:#1da1f2}.r-demo{border-style:solid !important;border-radius:16px !important;border-width:1px !important}.r-jwli3a{color:#fff !important}.tetNitterHover{background-color:#ff6c60}.tetNitter{border-color:#ffaca0 !important;box-shadow:#ffaca0 0px 0px 0px 1px !important}.btNav:not(#tetNT) .tet-icon-info.nitter,.btNav:not(#tetNT) .tetBtn.nitter{color:#fff;background-color:#ff6c60}h1.tetNTextColor{color:#888889}.nitter:not(.tetswitch,.tetBtn){border-color:#ff6c60;background-color:#0f0f0f}.nitter:not(.tetswitch,.tetBtn) div#tetName span{color:#ff6c60}input.tetNTextColor,select.tetNTextColor,div.tetNTextColor,svg.tetNTextColor,label.tetNTextColor>span{color:#f8f8f2}.tetNText,.tetNText span{color:#ff6c60 !important}.tetNBackground{background-color:#161616}#tetNI{color:#fff}#tetAvatar{background-color:rgba(0,0,0,0)}.tet-st0{fill:#ea4335}.tet-st1{fill:#4285f4}.tet-st2{fill:#34a853}.tet-st3{fill:#fbbc05}.tet-flex,.btNav,#tetadvanced,#tetadvanced>.tetBackground,.tet-txt,.r-demo,.tet-main{position:relative;display:flex;align-items:stretch;box-sizing:border-box;flex-direction:column}.btNav,.txt-header,.tet-av,.tetAlertBtns>div{align-items:center !important}#tetName,.r-demo,#tetadvanced,.tetAlertTxt,.tet-header{cursor:default}.txt-header,.tetAlertBtns,.r-demo,.tet-av,.r-hover,[id=apifield]{outline-style:none !important}.tet-dc,.tet-at,div.tetAlertTxt,.tet-info,.btNav label,.tetAlertBtns>div,#tetSelector>select{font-size:15px !important}.tet-at>span:first-child,h1.tetAlertTxt,.tetAlertBtns>div{font-weight:700 !important}.tet,#tetDemo,.tet-dc,.tet-at,.tethelper-info,div.tetAlertTxt,.tet-info,.tet-icon-info,#tweet-text,#tetSelector>#tetName{font-weight:400}.tet,#tetDemo,.tetswitch>label,#tetSelector>#tetName{line-height:16px}.tetAlertBtns>div>span,#tetMenuButton>svg,.txt-header,.tetadvanced-icon,.tet-at{max-width:100%}.tet-at{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tet-dc,.tet-at,.tet-header,#tetSelector>#tetName,#tetSelector>select{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}.tet,#tweet-text,.tetAlertBtns>div,.tet-main{font-family:"TwitterChirp",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}div.tetAlertTxt,.tet-info,.tet-dc,.tet-at,.tethelper-info,.tetAlertBtns>div,#tetSelector>select{line-height:20px}.tetAvatarFrame,#tetAvatar,.tet-main,.tet-containter,.tet-av,div.tetAlertTxt{width:100%}.tetAvatarFrame,#tetAvatar{align-items:stretch;border:0px solid #000;box-sizing:border-box;display:flex;flex-direction:column;margin:0px;min-height:0px;min-width:0px;padding:0px}#tetSelector{min-width:0px;overflow-wrap:break-word}#tetSelector #tetName{position:absolute;min-width:inherit;overflow-wrap:inherit}.tet,.tet-info,#tweet-text{margin-top:1% !important}#tweet-text,.tet-demoframe{position:relative}.tet-header,.tet-icon-container,.tetadvanced-icon-container,.tetAlertBtns>div,.tetAlertTxt{text-align:center}.tet-help-container a,.tet-icon-container,#tetDemo,.tet{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content}.tet{flex-wrap:wrap;font-size:13px;overflow-wrap:break-word;height:-webkit-min-content;height:-moz-min-content;height:min-content;display:flex;-webkit-user-select:none !important;-moz-user-select:none !important;-ms-user-select:none !important;user-select:none !important}.tetAvatarFrame{padding-bottom:100%;position:absolute;top:0px;right:0px;left:0px;bottom:0px}.tetAvatarFrame #tetAvatar{background-size:cover;background-repeat:no-repeat;background-position:center center;z-index:-1;height:100%;position:absolute}.tet-main{padding:0px 32px 32px 32px !important;display:flex;flex-direction:column}.tet-header{min-width:0px;white-space:normal;display:grid;padding:0px 32px;margin:32px 0px 12px 0px}.tet-header .tet-info-name{line-height:28px;font-size:23px;font-weight:800}.tetConfirmation{padding:8px 32px 16px 32px !important;border-radius:16px;top:50%;left:50%;transform:translate(-50%, -50%);position:fixed !important;z-index:10000 !important}.tetConfirmation .tetAlertTxt{align-content:center;display:grid;margin:0px !important}.tetConfirmation h1.tetAlertTxt{line-height:24px;font-size:20px;min-width:0px}.tetConfirmation div.tetAlertTxt{min-width:0px}.tetConfirmation .tetAlertBtns{margin:2% 0px 2% 0px;white-space:nowrap;transition-property:background-color,box-shadow;transition-duration:.2s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-color:rgba(0,0,0,0);overflow:hidden;border-width:1px;border-style:solid}.tetConfirmation .tetAlertBtns span{line-height:inherit !important;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border:0px solid #000;box-sizing:border-box;display:inline;margin:0px;padding:0px}.tetConfirmation .tetAlertBtns span>span{border:0px solid #000;box-sizing:border-box;display:inline;margin:0px;padding:0px}#tetadvanced{border-radius:16px}#tetadvanced>div{border-radius:16px;flex-grow:1;flex-shrink:1}.btNav:not(.mobile) [id=tetForm]{min-width:600px !important}[id=tetForm]{border-radius:16px;flex-shrink:1;position:relative;overflow:hidden}[id=tetForm] .tet-containter.tet-fg{margin-left:auto;margin-right:auto}#tetadvanced{max-width:90vw;max-height:90vh;min-width:500px;min-height:100px;flex-shrink:1;margin-left:1%;margin-right:1%}.tet-container{overflow:auto !important}.tetadvanced-container section.tetcheckbox>label,.tetadvanced-container section.tetselect{display:flex;justify-content:space-between;padding:.5em}.tetadvanced-container section.tetcheckbox>label{cursor:pointer}.tetadvanced-container .tetswitch{position:relative;width:38px;border-radius:20px;-webkit-user-select:none !important;-moz-user-select:none !important;-ms-user-select:none !important;user-select:none !important;margin:5px}.tetadvanced-container .tetswitch>input{display:none}.tetadvanced-container .tetswitch>label{display:block;overflow:hidden;cursor:pointer;height:16px;padding:0;border-radius:20px;border:1px solid #000;background-color:#464646}.tetadvanced-container .tetswitch>label:before{content:"";display:block;width:20px;height:20px;margin:-2px;background:#dadce0;position:absolute;top:0;right:20px;border-radius:20px}.tetadvanced-container .tetswitch>input:checked+label{margin-left:0}.tetadvanced-container .tetswitch>input:checked+label:before{right:0px}.btNav span,#tweet-text span,#tetMenuButton span{color:inherit;font:inherit;font-family:"TwitterChirp",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif !important;white-space:inherit;overflow-wrap:break-word}.rm,#tetMenuButton.mobile,option[disabled=""],div:not(.mini)>#tetSVG,div.mini>span{display:none !important;visibility:hidden !important}.tetFreeze{overflow:hidden !important;-ms-scroll-chaining:none !important;overscroll-behavior:none !important}#tetMenuButton{z-index:10;width:8vw;height:auto;position:fixed;top:65%;left:0px}#tetMenuButton.tetTD{left:90% !important;top:0% !important}#tetMenuButton>svg{position:relative;height:1.25em;fill:currentcolor;margin-right:12px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;right:35% !important}.tetBtn{list-style:none;text-align:inherit;text-decoration:none;border-radius:15px;justify-content:center;text-align:center;display:flex !important;font-family:inherit !important;font-size:20px !important;font-weight:bold !important;padding:0px !important;outline:none !important}.tetBtn.mini{border:rgba(0,0,0,0) !important;background:rgba(0,0,0,0) !important}.tetBtn,[id=tet],.tet{cursor:pointer !important}.tet.tet-td{display:inherit;font-size:inherit !important;font-weight:inherit !important;line-height:inherit !important;padding-bottom:4px !important}[id=tet]{justify-items:center}[id=apifield]{width:auto !important;margin:2% 6% 0px 6% !important}[id=apifield],#tetName,#tetSelector>select{padding-left:2% !important}[id=apifield],#tetSelector{align-items:stretch;display:grid;border-style:solid;border-radius:4px;border-width:1px}.tet-main #tetSelector,section.tetcheckbox{margin:2% 6% 0px 6%}#tetSelector>select{text-align:left;padding-top:12px;padding-right:0px;padding-bottom:0px;cursor:pointer;border-radius:0px;margin:0px;-webkit-appearance:none;-moz-appearance:none;appearance:none}[id=tetReset]{margin:2% 25% 0px 25%}.r-demo{margin:0px 32px 0px 32px !important;padding:12px 0px 12px 0px !important;overflow:hidden;flex-direction:row !important}.r-demo .tet-av{position:relative;margin:2px 12px 0px 12px !important;flex-basis:48px;height:48px;overflow:hidden;display:block;z-index:0}.r-demo .tet-av svg{fill:currentColor}.r-demo .tet-txt{flex-basis:0px;flex-grow:1;justify-content:center}.r-demo .tet-txt .txt-header{display:flex;margin-bottom:2px;justify-content:space-between;flex-direction:row;flex-shrink:1}.r-demo .tet-txt .txt-header .tet-at{display:flex;min-width:0px;max-width:inherit !important;white-space:normal !important}.r-demo .tet-txt .txt-header .tet-at>span:last-child{margin-left:4px}#tetDemo{margin:4px 0px 0px 0px;font-size:13px;flex-wrap:wrap;min-width:0px;display:flex !important}.btNav{-webkit-user-select:none !important;-moz-user-select:none !important;-ms-user-select:none !important;user-select:none !important;justify-content:center !important;flex-direction:row !important;top:0px !important}.btNav a,.btNav :link{text-decoration:none !important}.btNav a:hover,.btNav :link:hover{text-decoration:none !important}.btNav,.navbackground{position:fixed !important;width:100vw;height:100vh}.navbackground{top:0;left:0}.navbackground.warn{z-index:10 !important}.tet-icon-container,.tetadvanced-icon-container{cursor:pointer;display:inline-flex;position:absolute;bottom:10px;border-radius:9999px;z-index:1}.tet-icon-container{height:35px;right:25px}.tet-icon-container .tet-icon-info{color:#fff;display:inline;width:35px;height:35px;line-height:35px;border-radius:inherit;font-family:"fontello";font-size:23px}.tet-icon-container .tet-icon-info:hover{color:unset !important}.tet-icon-container .tet-help-container{position:static;border-style:solid;border-width:2px;border-radius:inherit;line-height:35px;font-size:16px;font-weight:normal;text-decoration:none;margin-left:10px}.tet-icon-container .tet-help-container a{display:inline-block;margin-left:10px;margin-right:10px}.tetadvanced-icon-container{left:10px;width:28px;height:28px}.tetadvanced-icon-container .tetadvanced-icon{height:1.75rem;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;position:relative;fill:currentcolor;border-radius:inherit;display:inline-block}.mini{min-height:3% !important;overflow:hidden;background:rgba(0,0,0,0);border-color:rgba(0,0,0,0)}.r-hover{-webkit-text-decoration-line:underline !important;text-decoration-line:underline !important}[id=tweet-text]{font-size:23px !important;line-height:28px !important}.tet-help-info{color:unset}#tetNI{margin:0px 10% 0px 10%}div.css-18t94o4.r-6koalj.r-1w6e6rj.r-37j5jr.r-n6v787.r-16dba41.r-1cwl3u0.r-14gqq1x.r-bcqeeo.r-qvutc0{width:-webkit-fit-content !important;width:-moz-fit-content !important;width:fit-content !important}.prf-header>div>.tet{display:inline-block !important;width:100% !important}select.tetTextColor{height:auto !important}.tet-favicon{width:1em;height:1em;padding-left:.2rem}[id=tet-ltg],[id=tet-ltgl],[id=tet-ltglg]{font-style:normal;font-family:inherit}[id=tet-ltg],[id=tet-ltglg]{font-weight:normal}[id=tet-ltg]{font-size:10.5833px;line-height:1.25;letter-spacing:0px;word-spacing:0px;white-space:pre;fill-opacity:1;stroke:none}[id=tet-ltgl]{font-variant:normal;font-weight:bold;font-stretch:normal}[id=tet-ltglg]{font-size:43.3964px;line-height:1.25;letter-spacing:0px;word-spacing:0px;fill-opacity:1;stroke:none;stroke-width:1.08492}[id=tet-ltglgp]{stroke-width:1.08492}`;
  129. const nitterCSS = `[id=tetNT] .tetBackground{border-color:var(--border_grey)}[id=tetNT] .tetNitter[id=tetSelector]:hover{border-color:var(--accent_border) !important;box-shadow:var(--accent_border) !important}[id=tetNT] .tetNitter[id=tetSelector]:hover [id=tetName] span{color:var(--fg_dark)}[id=tetNT] h1.tetNTextColor{color:var(--grey)}[id=tetNT] .nitter:not(.tetswitch,.tetBtn){background-color:var(--bg_color)}[id=tetNT] .nitter:not(.tetswitch,.tetBtn) div[id=tetName]{color:var(--fg_dark)}[id=tetNT] .tetBtn.nitter:not(.tet-29u,.tet-186u,.tet-122u,.tet-120u,.tet-249u,.tet-255u){color:var(--fg_color);background-color:var(--fg_dark)}[id=tetNT] input.tetNTextColor,[id=tetNT] select.tetNTextColor,[id=tetNT] div.tetNTextColor,[id=tetNT] svg.tetNTextColor,[id=tetNT] label.tetNTextColor>span{color:var(--fg_color)}[id=tetNT] .tetNText,[id=tetNT] .tetNText span{color:var(--fg_dark) !important}[id=tetNT] .tetNBackground{background-color:var(--bg_panel)}.tetNitterHover{background-color:var(--fg_dark)}[id=tetBTD] .tweetdeck:not(.tetswitch){background-color:var(--btd-accent-color)}[id=tetBTD] .r-tetTD{background-color:var(--btd-theme-background) !important}[id=tetBTD] .r-tetTD[id=tetSelector].Button--primary:hover{border-color:#1da1f2;box-shadow:#1da1f2 0px 0px 0px 1px}[id=tetBTD] .r-tetTD[id=tetSelector].Button--primary:hover [id=tetName] span{color:#1da1f2}[id=tetBTD] .r-tetBTD{background-color:var(--btd-theme-background) !important}[id=tetBTD] .r-tetBTD [id=tetName] span{color:var(--btd-accent-color)}.tetNText .tet-svg{fill:var(--fg_dark)}`;
  130. const debugToggle = false;
  131. const ghCDN = 'https://cdn.jsdelivr.net/gh';
  132. let languages = {
  133. en: {
  134. sel: `English (en)`,
  135. tw: `Translate with`,
  136. lg: `Language`,
  137. tr: `Translator`,
  138. ds: `Display`,
  139. menu: `Menu`,
  140. ao: `Auto`,
  141. th: `Theme`,
  142. df: `Default`,
  143. di: `Dim`,
  144. lo: `Lights out`,
  145. col: `Color`,
  146. cb: `Blue`,
  147. cy: `Yellow`,
  148. cr: `Red`,
  149. cp: `Purple`,
  150. co: `Orange`,
  151. cg: `Green`,
  152. t: `Text`,
  153. i: `Icon`,
  154. res: `Restore to Defaults`,
  155. l: `Loading`,
  156. quest: {
  157. head: `Are you sure?`,
  158. body: `Website will be reloaded.`,
  159. yes: `Yes`,
  160. no: `No`,
  161. },
  162. },
  163. zh: {
  164. sel: `中文 (zh)`,
  165. tw: `翻译与`,
  166. lg: `语种`,
  167. tr: `译者`,
  168. ds: `显示`,
  169. menu: `菜单`,
  170. ao: `自动的`,
  171. th: `主题`,
  172. df: `默认情况下`,
  173. di: `凹陷`,
  174. lo: `熄灯`,
  175. col: `颜色`,
  176. cb: `蓝色`,
  177. cy: `黄色`,
  178. cr: `红色`,
  179. cp: `紫色`,
  180. co: `橙色`,
  181. cg: `绿色`,
  182. t: `案文`,
  183. i: `图标`,
  184. res: `恢复`,
  185. l: `Loading`,
  186. quest: {
  187. head: `你确定吗?`,
  188. body: `网站将被重新加载`,
  189. yes: `是的`,
  190. no: `不确定`,
  191. },
  192. },
  193. bg: {
  194. sel: `Български (bg)`,
  195. tw: `Преведете с`,
  196. lg: `Език`,
  197. tr: `Преводач`,
  198. ds: `Показване на`,
  199. menu: `Меню`,
  200. ao: `Автоматичен`,
  201. th: `Тема`,
  202. df: `По подразбиране`,
  203. di: `Dim`,
  204. lo: `Изгасяне на осветлението`,
  205. col: `Цвят`,
  206. cb: `Синьо`,
  207. cy: `Жълто`,
  208. cr: `Червено`,
  209. cp: `Лилаво`,
  210. co: `Оранжево`,
  211. cg: `Зелено`,
  212. t: `Текст`,
  213. i: `Икона`,
  214. res: `Възстановявам`,
  215. l: `Loading`,
  216. quest: {
  217. head: `Сигурни ли сте?`,
  218. body: `Уебсайтът ще бъде презареден.`,
  219. yes: `Да`,
  220. no: `Не`,
  221. },
  222. },
  223. cs: {
  224. sel: esky (cs)`,
  225. tw: `Přeložit pomocí`,
  226. lg: `Jazyk`,
  227. tr: `Překladatel`,
  228. ds: `Zobrazit`,
  229. menu: `Nabídka`,
  230. ao: `Automatické`,
  231. th: `Téma`,
  232. df: `Výchozí`,
  233. di: `Dim`,
  234. lo: `Zhasnout světla`,
  235. col: `Barva`,
  236. cb: `Modrá`,
  237. cy: lutá`,
  238. cr: ervená`,
  239. cp: `Fialová`,
  240. co: `Oranžová`,
  241. cg: `Zelená`,
  242. t: `Text`,
  243. i: `Ikona`,
  244. res: `Obnovit`,
  245. l: `Loading`,
  246. quest: {
  247. head: `Jste si jistý?`,
  248. body: `Webové stránky budou znovu načteny.`,
  249. yes: `Ano`,
  250. no: `Ne`,
  251. },
  252. },
  253. da: {
  254. sel: `Dansk (da)`,
  255. tw: `Oversæt med`,
  256. lg: `Sprog`,
  257. tr: `Oversætter`,
  258. ds: `Vis`,
  259. menu: `Menu`,
  260. ao: `Automatisk`,
  261. th: `Tema`,
  262. df: `Standard`,
  263. di: `Dim`,
  264. lo: `Lyset slukkes`,
  265. col: `Farve`,
  266. cb: `Blå`,
  267. cy: `Gul`,
  268. cr: `Rød`,
  269. cp: `Lilla`,
  270. co: `Orange`,
  271. cg: `Grøn`,
  272. t: `Tekst`,
  273. i: `Ikon`,
  274. res: `Genskabe`,
  275. l: `Loading`,
  276. quest: {
  277. head: `Er du sikker?`,
  278. body: `Hjemmesiden vil blive genindlæst.`,
  279. yes: `Ja`,
  280. no: `Nej`,
  281. },
  282. },
  283. et: {
  284. sel: `Eesti (et)`,
  285. tw: `Tõlge koos`,
  286. lg: `Keel`,
  287. tr: `Tõlkija`,
  288. ds: `Kuva`,
  289. menu: `Menüü`,
  290. ao: `Automaatne`,
  291. th: `Teema`,
  292. df: `Vaikimisi`,
  293. di: `Dim`,
  294. lo: `Valgus välja lülitatud`,
  295. col: `Värv`,
  296. cb: `Sinine`,
  297. cy: `Kollane`,
  298. cr: `Punane`,
  299. cp: `Lilla`,
  300. co: `Oranž`,
  301. cg: `Roheline`,
  302. t: `Tekst`,
  303. i: `Ikoon`,
  304. res: `Taastada`,
  305. l: `Loading`,
  306. quest: {
  307. head: `Oled sa kindel?`,
  308. body: `Veebileht laaditakse uuesti.`,
  309. yes: `Jah`,
  310. no: `Ei`,
  311. },
  312. },
  313. fi: {
  314. sel: `Suomalainen (fi)`,
  315. tw: `Käännä kanssa`,
  316. lg: `Kieli`,
  317. tr: `Kääntäjä`,
  318. ds: `Näytä`,
  319. menu: `Valikko`,
  320. ao: `Automaattinen`,
  321. th: `Teema`,
  322. df: `Oletus`,
  323. di: `Dim`,
  324. lo: `Valot pois päältä`,
  325. col: `Väri`,
  326. cb: `Sininen`,
  327. cy: `Keltainen`,
  328. cr: `Punainen`,
  329. cp: `Violetti`,
  330. co: `Oranssi`,
  331. cg: `Vihreä`,
  332. t: `Teksti`,
  333. i: `Kuvake`,
  334. res: `Palauta`,
  335. l: `Loading`,
  336. quest: {
  337. head: `Oletko varma?`,
  338. body: `Sivusto ladataan uudelleen.`,
  339. yes: `Kyllä`,
  340. no: `Ei`,
  341. },
  342. },
  343. el: {
  344. sel: `Ελληνική (el)`,
  345. tw: `Μεταφράστε με`,
  346. lg: `Γλώσσα`,
  347. tr: `Μεταφραστής`,
  348. ds: `Εμφάνιση`,
  349. menu: `Μενού`,
  350. ao: `Αυτόματο`,
  351. th: `Θέμα`,
  352. df: `Προεπιλογή`,
  353. di: `Dim`,
  354. lo: `Σβήνει τα φώτα`,
  355. col: `Χρώμα`,
  356. cb: `Μπλε`,
  357. cy: `Κίτρινο`,
  358. cr: `Κόκκινο`,
  359. cp: `Μωβ`,
  360. co: `Πορτοκαλί`,
  361. cg: `Πράσινο`,
  362. t: `Κείμενο`,
  363. i: `Εικονίδιο`,
  364. res: `Επαναφορά`,
  365. l: `Loading`,
  366. quest: {
  367. head: `Είσαι σίγουρος;`,
  368. body: ιστοσελίδα θα επαναφορτωθεί.`,
  369. yes: `Ναι`,
  370. no: `Όχι`,
  371. },
  372. },
  373. hu: {
  374. sel: `Magyar (hu)`,
  375. tw: `Fordítson a`,
  376. lg: `Nyelv`,
  377. tr: `Fordító`,
  378. ds: `Megjelenítés`,
  379. menu: `Menü`,
  380. ao: `Automatikus`,
  381. th: `Téma`,
  382. df: `Alapértelmezett`,
  383. di: `Dim`,
  384. lo: `Fények kikapcsolva`,
  385. col: `Szín`,
  386. cb: `Kék`,
  387. cy: `Sárga`,
  388. cr: `Piros`,
  389. cp: `Lila`,
  390. co: `Narancs`,
  391. cg: `Zöld`,
  392. t: `Szöveg`,
  393. i: `Ikon`,
  394. res: `Visszaállítása`,
  395. l: `Loading`,
  396. quest: {
  397. head: `Biztos vagy benne?`,
  398. body: `A weboldal újratöltődik.`,
  399. yes: `Igen`,
  400. no: `Nem`,
  401. },
  402. },
  403. lv: {
  404. sel: `Latviešu (lv)`,
  405. tw: `Tulkot ar`,
  406. lg: `Valoda`,
  407. tr: `Tulkotājs`,
  408. ds: `Displejs`,
  409. menu: `Izvēlne`,
  410. ao: `Automātiskais`,
  411. th: `Tēma`,
  412. df: `Noklusējuma`,
  413. di: `Dim`,
  414. lo: `Izslēgt gaismu`,
  415. col: `Krāsa`,
  416. cb: `Zils`,
  417. cy: `Dzeltens`,
  418. cr: `Sarkans`,
  419. cp: `Violeta`,
  420. co: `Oranža`,
  421. cg: `Zaļš`,
  422. t: `Teksts`,
  423. i: `Ikona`,
  424. res: `Atjaunot`,
  425. l: `Loading`,
  426. quest: {
  427. head: `Vai esat pārliecināts?`,
  428. body: `Tīmekļa vietne tiks ielādēta no jauna.`,
  429. yes: `Jā`,
  430. no: `Nē`,
  431. },
  432. },
  433. lt: {
  434. sel: `Lietuvių kalba (lt)`,
  435. tw: `Išversti su`,
  436. lg: `Kalba`,
  437. tr: `Vertėjas`,
  438. ds: `Rodyti`,
  439. menu: `Meniu`,
  440. ao: `Automatinis`,
  441. th: `Tema`,
  442. df: `Numatytoji`,
  443. di: `Dim`,
  444. lo: `Išjungti šviesą`,
  445. col: `Spalva`,
  446. cb: `Mėlyna`,
  447. cy: `Geltona`,
  448. cr: `Raudona`,
  449. cp: `Violetinė`,
  450. co: `Oranžinė`,
  451. cg: alia`,
  452. t: `Tekstas`,
  453. i: `Ikona`,
  454. res: `Atkurti`,
  455. l: `Loading`,
  456. quest: {
  457. head: `Ar tikrai?`,
  458. body: `Svetainė bus iš naujo įkelta.`,
  459. yes: `Taip`,
  460. no: `Ne`,
  461. },
  462. },
  463. ro: {
  464. sel: `Românesc (ro)`,
  465. tw: `Tradu cu`,
  466. lg: `Limba`,
  467. tr: `Traducător`,
  468. ds: `Afișați`,
  469. menu: `Meniu`,
  470. ao: `Automat`,
  471. th: `Tema`,
  472. df: `Implicit`,
  473. di: `Dim`,
  474. lo: `Stinge lumina`,
  475. col: `Culoare`,
  476. cb: `Albastru`,
  477. cy: `Galben`,
  478. cr: `Roșu`,
  479. cp: `Violet`,
  480. co: `Portocaliu`,
  481. cg: `Verde`,
  482. t: `Text`,
  483. i: `Icoană`,
  484. res: `Restaurați`,
  485. l: `Loading`,
  486. quest: {
  487. head: `Ești sigur?`,
  488. body: `Site-ul va fi reîncărcat.`,
  489. yes: `Da`,
  490. no: `Nu`,
  491. },
  492. },
  493. sk: {
  494. sel: `Slovenská (sk)`,
  495. tw: `Preložiť s`,
  496. lg: `Jazyk`,
  497. tr: `Prekladateľ`,
  498. ds: `Zobraziť`,
  499. menu: `Ponuka`,
  500. ao: `Automatické`,
  501. th: `Téma`,
  502. df: `Predvolené nastavenie`,
  503. di: `Dim`,
  504. lo: `Zhasnuté svetlá`,
  505. col: `Farba`,
  506. cb: `Modrá`,
  507. cy: ltá`,
  508. cr: ervená`,
  509. cp: `Fialová`,
  510. co: `Oranžová`,
  511. cg: `Zelená`,
  512. t: `Text`,
  513. i: `Ikona`,
  514. res: `Obnovenie`,
  515. l: `Loading`,
  516. quest: {
  517. head: `Ste si istý?`,
  518. body: `Webová stránka bude znovu načítaná.`,
  519. yes: no`,
  520. no: `Nie`,
  521. },
  522. },
  523. sl: {
  524. sel: `Slovenski (sl)`,
  525. tw: `Prevedi z`,
  526. lg: `Jezik`,
  527. tr: `Prevajalec`,
  528. ds: `Prikaži`,
  529. menu: `Meni`,
  530. ao: `Samodejno`,
  531. th: `Tema`,
  532. df: `Privzeto`,
  533. di: `Dim`,
  534. lo: `Ugasne luči`,
  535. col: `Barva`,
  536. cb: `Modra`,
  537. cy: `Rumena`,
  538. cr: `Rdeča`,
  539. cp: `Vijolična`,
  540. co: `Oranžna`,
  541. cg: `Zelena`,
  542. t: `Besedilo`,
  543. i: `Ikona`,
  544. res: `Obnovitev`,
  545. l: `Loading`,
  546. quest: {
  547. head: `Ste prepričani?`,
  548. body: `Spletna stran bo ponovno naložena.`,
  549. yes: `Da`,
  550. no: `Ne`,
  551. },
  552. },
  553. sv: {
  554. sel: `Svenska (sv)`,
  555. tw: versätt med`,
  556. lg: `Språk`,
  557. tr: versättare`,
  558. ds: `Visa`,
  559. menu: `Meny`,
  560. ao: `Automatisk`,
  561. th: `Tema`,
  562. df: `Standard`,
  563. di: `Dim`,
  564. lo: `Ljuset släcks`,
  565. col: `Färg`,
  566. cb: `Blå`,
  567. cy: `Gul`,
  568. cr: `Röd`,
  569. cp: `Lila`,
  570. co: `Orange`,
  571. cg: `Grön`,
  572. t: `Text`,
  573. i: `Ikon`,
  574. res: terställ`,
  575. l: `Loading`,
  576. quest: {
  577. head: r du säker?`,
  578. body: `Webbplatsen kommer att laddas om.`,
  579. yes: `Ja`,
  580. no: `Nej`,
  581. },
  582. },
  583. nl: {
  584. sel: `Nederlands (nl)`,
  585. tw: `Vertaal met`,
  586. lg: `Taal`,
  587. tr: `Vertaler`,
  588. ds: `Weergave`,
  589. menu: `Menu`,
  590. ao: `Automatisch`,
  591. th: `Thema`,
  592. df: `Standaard`,
  593. di: `Dimmen`,
  594. lo: `Licht uit`,
  595. col: `Kleur`,
  596. cb: `Blauw`,
  597. cy: `Geel`,
  598. cr: `Rood`,
  599. cp: `Paars`,
  600. co: `Oranje`,
  601. cg: `Groen`,
  602. t: `Tekst`,
  603. i: `Icoon`,
  604. res: `Herstel`,
  605. l: `Loading`,
  606. quest: {
  607. head: `Ben je zeker?`,
  608. body: `De website wordt opnieuw geladen.`,
  609. yes: `Ja`,
  610. no: `Nee`,
  611. },
  612. },
  613. fr: {
  614. sel: `Français (fr)`,
  615. tw: `Traduire avec`,
  616. lg: `Langue`,
  617. tr: `Traducteur`,
  618. ds: `Afficher`,
  619. menu: `Menu`,
  620. ao: `Automatique`,
  621. th: `Thème`,
  622. df: `Défaut`,
  623. di: `Dim`,
  624. lo: `Extinction des lumières`,
  625. col: `Couleur`,
  626. cb: `Bleu`,
  627. cy: `Jaune`,
  628. cr: `Rouge`,
  629. cp: `Violet`,
  630. co: `Orange`,
  631. cg: `Vert`,
  632. t: `Texte`,
  633. i: `Icône`,
  634. res: `Restaurer`,
  635. l: `Loading`,
  636. quest: {
  637. head: `Vous êtes sûr ?`,
  638. body: `Le site web va être rechargé.`,
  639. yes: `Oui`,
  640. no: `Non`,
  641. },
  642. },
  643. de: {
  644. sel: `Deutsch (de)`,
  645. tw: bersetzen mit`,
  646. lg: `Sprache`,
  647. tr: bersetzer`,
  648. ds: `Anzeige`,
  649. menu: `Menü`,
  650. ao: `Automatisch`,
  651. th: `Thema`,
  652. df: `Standard`,
  653. di: `Dimmen`,
  654. lo: `Licht aus`,
  655. col: `Farbe`,
  656. cb: `Blau`,
  657. cy: `Gelb`,
  658. cr: `Rot`,
  659. cp: `Lila`,
  660. co: `Orange`,
  661. cg: `Grün`,
  662. t: `Text`,
  663. i: `Icon`,
  664. res: `Wiederherstellen`,
  665. l: `Loading`,
  666. quest: {
  667. head: `Sind Sie sicher?`,
  668. body: `Die Website wird neu geladen.`,
  669. yes: `Ja`,
  670. no: `Nein`,
  671. },
  672. },
  673. it: {
  674. sel: `Italiano (it)`,
  675. tw: `Tradurre con`,
  676. lg: `Lingua`,
  677. tr: `Traduttore`,
  678. ds: `Visualizza`,
  679. menu: `Menu`,
  680. ao: `Automatico`,
  681. th: `Tema`,
  682. df: `Default`,
  683. di: `Dim`,
  684. lo: `Luci spente`,
  685. col: `Colore`,
  686. cb: `Blu`,
  687. cy: `Giallo`,
  688. cr: `Rosso`,
  689. cp: `Viola`,
  690. co: `Arancione`,
  691. cg: `Verde`,
  692. t: `Testo`,
  693. i: `Icona`,
  694. res: `Ripristinare`,
  695. l: `Loading`,
  696. quest: {
  697. head: `Sei sicuro?`,
  698. body: `Il sito sarà ricaricato.`,
  699. yes: `Sì`,
  700. no: `No`,
  701. },
  702. },
  703. ja: {
  704. sel: `日本語 (ja)`,
  705. tw: `で翻訳する`,
  706. lg: `言語`,
  707. tr: `翻訳者`,
  708. ds: `ディスプレイ`,
  709. menu: `メニュー`,
  710. ao: `自動`,
  711. th: `テーマ`,
  712. df: `デフォルト`,
  713. di: `暗い`,
  714. lo: `消灯`,
  715. col: `カラー`,
  716. cb: `青`,
  717. cy: `黄`,
  718. cr: `赤`,
  719. cp: `紫`,
  720. co: `オレンジ`,
  721. cg: `グリーン`,
  722. t: `テキスト`,
  723. i: `アイコン`,
  724. res: `リストア`,
  725. l: `Loading`,
  726. quest: {
  727. head: `本当にいいの?`,
  728. body: `ウェブサイトが再読み込みされます。`,
  729. yes: `はい`,
  730. no: `いいえ`,
  731. },
  732. },
  733. pl: {
  734. sel: `Polski (pl)`,
  735. tw: `Tłumaczenie za pomocą`,
  736. lg: `Język`,
  737. tr: `Tłumacz`,
  738. ds: `Wyświetlacz`,
  739. menu: `Menu`,
  740. ao: `Automatyczny`,
  741. th: `Motyw`,
  742. df: `Domyślnie`,
  743. di: ciemniaj`,
  744. lo: `Nie świeci się`,
  745. col: `Kolor`,
  746. cb: `Niebieski`,
  747. cy: `Żółty`,
  748. cr: `Czerwony`,
  749. cp: `Purpurowy`,
  750. co: `Pomarańczowy`,
  751. cg: `Zielony`,
  752. t: `Tekst`,
  753. i: `Ikona`,
  754. res: `Przywróć`,
  755. l: `Loading`,
  756. quest: {
  757. head: `Czy jesteś pewien?`,
  758. body: `Strona zostanie przeładowana.`,
  759. yes: `Tak`,
  760. no: `Nie`,
  761. },
  762. },
  763. pt: {
  764. sel: `Português (pt)`,
  765. tw: `Traduzir com`,
  766. lg: `Idioma`,
  767. tr: `Tradutora`,
  768. ds: `Mostrar`,
  769. menu: `Menu`,
  770. ao: `Automático`,
  771. th: `Tema`,
  772. df: `Por defeito`,
  773. di: `Dim`,
  774. lo: `Luzes apagadas`,
  775. col: `Cor`,
  776. cb: `Azul`,
  777. cy: `Amarelo`,
  778. cr: `Vermelho`,
  779. cp: `Púrpura`,
  780. co: `Laranja`,
  781. cg: `Verde`,
  782. t: `Texto`,
  783. i: cone`,
  784. res: `Restaurar`,
  785. l: `Loading`,
  786. quest: {
  787. head: `Tem a certeza?`,
  788. body: `O website será carregado de novo.`,
  789. yes: `Sim`,
  790. no: `Não`,
  791. },
  792. },
  793. ru: {
  794. sel: `Russisch (ru)`,
  795. tw: `Перевод с`,
  796. lg: `Язык`,
  797. tr: `Переводчик`,
  798. ds: `Показать`,
  799. menu: `Меню`,
  800. ao: `Автоматический`,
  801. th: `Тема`,
  802. df: `По умолчанию`,
  803. di: `Приглушить`,
  804. lo: `Выключить свет`,
  805. col: `Цвет`,
  806. cb: `Синий`,
  807. cy: `Желтый`,
  808. cr: `Красный`,
  809. cp: `Фиолетовый`,
  810. co: `Оранжевый`,
  811. cg: `Зеленый`,
  812. t: `Текст`,
  813. i: `иконка`,
  814. res: `Восстановить`,
  815. l: `Loading`,
  816. quest: {
  817. head: `Вы уверены?`,
  818. body: `Сайт будет перезагружен.`,
  819. yes: `Да`,
  820. no: `Нет`,
  821. },
  822. },
  823. es: {
  824. sel: `Español (es)`,
  825. tw: `Traducir con`,
  826. lg: `Idioma`,
  827. tr: `Traductor`,
  828. ds: `Mostrar`,
  829. menu: `Menú`,
  830. ao: `Automático`,
  831. th: `Tema`,
  832. df: `Por defecto`,
  833. di: `Atenuar`,
  834. lo: `Luces apagadas`,
  835. col: `Colores`,
  836. cb: `Azul`,
  837. cy: `Amarillo`,
  838. cr: `Rojo`,
  839. cp: `Púrpura`,
  840. co: `Naranja`,
  841. cg: `Verde`,
  842. t: `Texto`,
  843. i: `Icono`,
  844. res: `Restaurar`,
  845. l: `Loading`,
  846. quest: {
  847. head: `¿Está seguro?`,
  848. body: `El sitio web será recargado.`,
  849. yes: `Sí`,
  850. no: `No`,
  851. },
  852. },
  853. };
  854.  
  855. let userjs = (self.userjs = {});
  856.  
  857. // Skip text/plain documents.
  858. if (
  859. (document instanceof HTMLDocument ||
  860. (document instanceof XMLDocument && document.createElement('div') instanceof HTMLDivElement)) &&
  861. /^image\/|^text\/plain/.test(document.contentType || '') === false &&
  862. (self.userjs instanceof Object === false || userjs.UserJS !== true)
  863. ) {
  864. userjs = self.userjs = { UserJS: true };
  865. }
  866.  
  867. let dLng = 'en';
  868. let cfg = {};
  869. let lng = {};
  870. let cBG = 'rgba(91, 112, 131, 0.4)';
  871. let cColor = 'r-p1n3y5 r-1bih22f';
  872. let cHover = 'r-1q3imqu';
  873. let cText = 'r-jwli3a';
  874. let cTheme = 'r-kemksi';
  875. let cSub = 'r-13gxpu9';
  876.  
  877. const normalizeTarget = (target) => {
  878. if (typeof target === 'string') {
  879. return Array.from(document.querySelectorAll(target));
  880. }
  881. if (target instanceof Element) {
  882. return [target];
  883. }
  884. if (target === null) {
  885. return [];
  886. }
  887. if (Array.isArray(target)) {
  888. return target;
  889. }
  890. return Array.from(target);
  891. };
  892.  
  893. const SafeAnimationFrame = class {
  894. constructor(callback) {
  895. this.fid = this.tid = undefined;
  896. this.callback = callback;
  897. }
  898. start(delay) {
  899. if (delay === undefined) {
  900. if (this.fid === undefined) {
  901. this.fid = requestAnimationFrame(() => {
  902. this.onRAF();
  903. });
  904. }
  905. if (this.tid === undefined) {
  906. this.tid = setTimeout(() => {
  907. this.onSTO();
  908. }, 20000);
  909. }
  910. return;
  911. }
  912. if (this.fid === undefined && this.tid === undefined) {
  913. this.tid = setTimeout(() => {
  914. this.macroToMicro();
  915. }, delay);
  916. }
  917. }
  918. clear() {
  919. if (this.fid !== undefined) {
  920. cancelAnimationFrame(this.fid);
  921. this.fid = undefined;
  922. }
  923. if (this.tid !== undefined) {
  924. clearTimeout(this.tid);
  925. this.tid = undefined;
  926. }
  927. }
  928. macroToMicro() {
  929. this.tid = undefined;
  930. this.start();
  931. }
  932. onRAF() {
  933. if (this.tid !== undefined) {
  934. clearTimeout(this.tid);
  935. this.tid = undefined;
  936. }
  937. this.fid = undefined;
  938. this.callback();
  939. }
  940. onSTO() {
  941. if (this.fid !== undefined) {
  942. cancelAnimationFrame(this.fid);
  943. this.fid = undefined;
  944. }
  945. this.tid = undefined;
  946. this.callback();
  947. }
  948. };
  949.  
  950. class dom {
  951. static attr(target, attr, value = undefined) {
  952. for (const elem of normalizeTarget(target)) {
  953. if (value === undefined) {
  954. return elem.getAttribute(attr);
  955. }
  956. if (value === null) {
  957. elem.removeAttribute(attr);
  958. } else {
  959. elem.setAttribute(attr, value);
  960. }
  961. }
  962. }
  963.  
  964. static create(a) {
  965. if (typeof a === 'string') {
  966. return document.createElement(a);
  967. }
  968. }
  969.  
  970. static text(target, text) {
  971. const targets = normalizeTarget(target);
  972. if (text === undefined) {
  973. return targets.length !== 0 ? targets[0].textContent : undefined;
  974. }
  975. for (const elem of targets) {
  976. elem.textContent = text;
  977. }
  978. }
  979. }
  980.  
  981. dom.cl = class {
  982. static add(target, name) {
  983. if (Array.isArray(name)) {
  984. for (const elem of normalizeTarget(target)) {
  985. elem.classList.add(...name);
  986. }
  987. } else {
  988. for (const elem of normalizeTarget(target)) {
  989. elem.classList.add(name);
  990. }
  991. }
  992. }
  993.  
  994. static remove(target, name) {
  995. if (Array.isArray(name)) {
  996. for (const elem of normalizeTarget(target)) {
  997. elem.classList.remove(...name);
  998. }
  999. } else {
  1000. for (const elem of normalizeTarget(target)) {
  1001. elem.classList.remove(name);
  1002. }
  1003. }
  1004. }
  1005.  
  1006. static toggle(target, name, state) {
  1007. let r;
  1008. for (const elem of normalizeTarget(target)) {
  1009. r = elem.classList.toggle(name, state);
  1010. }
  1011. return r;
  1012. }
  1013.  
  1014. static has(target, name) {
  1015. for (const elem of normalizeTarget(target)) {
  1016. if (elem.classList.contains(name)) {
  1017. return true;
  1018. }
  1019. }
  1020. return false;
  1021. }
  1022. };
  1023.  
  1024. dom.root = document.querySelector(':root');
  1025. dom.html = document.documentElement;
  1026. dom.head = document.head;
  1027. dom.body = document.body;
  1028. dom.search = document || dom.root || dom.html || dom.head || dom.body;
  1029.  
  1030. // const NOOPFUNC = () => {};
  1031. const nitterURL = 'https://raw.githubusercontent.com/wiki/zedeus/nitter/Instances.md';
  1032. const hasOwn = Object.hasOwn || Object.prototype.hasOwnProperty.call;
  1033. const cfgDefault = {
  1034. debug: debugToggle,
  1035. lang: dLng,
  1036. translator: 'deepl',
  1037. display: 'text + icon',
  1038. colors: 'auto',
  1039. theme: 'auto',
  1040. delay: 'none',
  1041. sitetheme: true,
  1042. dms: true,
  1043. tweets: true,
  1044. bios: true,
  1045. api: {
  1046. deepl: '',
  1047. google: '',
  1048. libre: '',
  1049. translate: '',
  1050. yandex: '',
  1051. version: 'api-free'
  1052. },
  1053. url: {
  1054. bing: 'https://www.bing.com',
  1055. bingIT: '',
  1056. deepl: 'https://www.deepl.com',
  1057. deeplIT: 'https://api.deepl.com',
  1058. google: 'https://translate.google.com',
  1059. googleIT: 'https://translation.googleapis.com',
  1060. libre: 'https://translate.argosopentech.com/translate',
  1061. lingva: 'https://lingva.ml',
  1062. mymemory: 'https://mymemory.translated.net',
  1063. mymemoryIT: 'https://api.mymemory.translated.net',
  1064. translate: 'https://www.translate.com',
  1065. translateIT: 'https://api.translate.com/translate/v1/mt',
  1066. yandex: 'https://translate.yandex.com',
  1067. yandexIT: 'https://translate.api.cloud.yandex.net/translate/v2/translate'
  1068. },
  1069. nitterInstances: []
  1070. };
  1071. const topDOM = window.self === window.top;
  1072. const win = self ?? window;
  1073. const doc = document;
  1074. const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
  1075. const domURL = new URL(location);
  1076. const UA = navigator.userAgent;
  1077. const isMobile = /Mobile|Tablet/.test(UA); // /Mobi/.test(UA);
  1078. const isGM = typeof GM !== 'undefined';
  1079. /**
  1080. * Object is Null
  1081. * @param {Object} obj - Object
  1082. * @returns {boolean} Returns if statement true or false
  1083. */
  1084. const isNull = (obj) => {
  1085. return Object.is(obj, null) || Object.is(obj, undefined);
  1086. };
  1087. /**
  1088. * Object is Blank
  1089. * @param {(Object|Object[]|string)} obj - Array, Set, Object or String
  1090. * @returns {boolean} Returns if statement true or false
  1091. */
  1092. const isBlank = (obj) => {
  1093. const objExec = /\[object (.+)\]/.exec(Object.prototype.toString.call(obj));
  1094. if (objExec.length === 0) {
  1095. return false;
  1096. }
  1097. const objStr = objExec[1];
  1098. return (
  1099. (/string/i.test(objStr) && Object.is(obj.trim(), '')) ||
  1100. (/map|set/i.test(objStr) && Object.is(obj.size, 0)) ||
  1101. (Array.isArray(obj) && Object.is(obj.length, 0)) ||
  1102. (/object/i.test(objStr) &&
  1103. typeof obj.entries !== 'function' &&
  1104. Object.is(Object.keys(obj).length, 0))
  1105. );
  1106.  
  1107. // return (
  1108. // (typeof obj === 'string' && Object.is(obj.trim(), '')) ||
  1109. // ((obj instanceof Map || obj instanceof Set) && Object.is(obj.size, 0)) ||
  1110. // (Array.isArray(obj) && Object.is(obj.length, 0)) ||
  1111. // (obj instanceof Object &&
  1112. // typeof obj.entries !== 'function' &&
  1113. // Object.is(Object.keys(obj).length, 0))
  1114. // );
  1115. };
  1116. /**
  1117. * Object is Empty
  1118. * @param {(Object|Object[]|string)} obj - Array, object or string
  1119. * @returns {boolean} Returns if statement true or false
  1120. */
  1121. const isEmpty = (obj) => {
  1122. return isNull(obj) || isBlank(obj);
  1123. };
  1124. /**
  1125. * Prefix for document.querySelectorAll()
  1126. * @param {Object} element - Elements for query selection
  1127. * @param {Object} [root=document] - Root selector Element
  1128. * @returns {Object} Returns root.querySelectorAll(element)
  1129. */
  1130. const qsA = (element, root) => {
  1131. try {
  1132. root = root || dom.search;
  1133. return root.querySelectorAll(element);
  1134. } catch (ex) {
  1135. return console.error(ex);
  1136. }
  1137. };
  1138. /**
  1139. * Prefix for document.querySelector()
  1140. * @param {Object} element - Element for query selection
  1141. * @param {Object} [root=document] - Root selector Element
  1142. * @returns {Object} Returns root.querySelector(element)
  1143. */
  1144. const qs = (element, root) => {
  1145. try {
  1146. root = root || dom.search;
  1147. return root.querySelector(element);
  1148. } catch (ex) {
  1149. return console.error(ex);
  1150. }
  1151. };
  1152. /**
  1153. * Prefix for document.querySelector() w/ Promise
  1154. * @param {Object} element - Element for query selection
  1155. * @param {Object} [root=document] - Root selector Element
  1156. * @returns {Object} Returns root.querySelector(element)
  1157. */
  1158. const query = (element, root) => {
  1159. root = root || dom.search;
  1160. if (!isNull(root.querySelector(element))) {
  1161. return Promise.resolve(root.querySelector(element));
  1162. }
  1163. const loop = async () => {
  1164. while (isNull(root.querySelector(element))) {
  1165. // await new Promise((resolve) => requestAnimationFrame(resolve));
  1166. await new Promise((resolve) => {
  1167. const queryTimer = new SafeAnimationFrame(resolve);
  1168. queryTimer.start(1);
  1169. });
  1170. }
  1171. return root.querySelector(element);
  1172. };
  1173. return Promise.any([loop(), delay(5000).then(() => Promise.reject('Unable to locate element'))]);
  1174. };
  1175. /**
  1176. * Add Event Listener
  1177. * @param {Object} root - Selected Element
  1178. * @param {string} type - root Event Listener
  1179. * @param {Function} callback - Callback function
  1180. * @param {Object} [options={}] - (Optional) Options
  1181. * @returns {Object} Returns selected Element
  1182. */
  1183. const ael = (root, type, callback, options = {}) => {
  1184. try {
  1185. root = root || dom.search;
  1186. if (isMobile && type === 'click') {
  1187. type = 'mouseup';
  1188. root.addEventListener('touchstart', callback);
  1189. root.addEventListener('touchend', callback);
  1190. }
  1191. if (type === 'fclick') {
  1192. type = 'click';
  1193. }
  1194. return root.addEventListener(type, callback, options);
  1195. } catch (ex) {
  1196. return err(ex);
  1197. }
  1198. };
  1199. /**
  1200. * Form Attributes of Element
  1201. * @param {Object} elt - Element
  1202. * @param {string} cname - (Optional) Element class name
  1203. * @param {Object} [attrs={}] - (Optional) Element attributes
  1204. * @returns {Object} Returns created Element
  1205. */
  1206. const formAttrs = (el, cname, attrs = {}) => {
  1207. try {
  1208. if (!isEmpty(cname)) {
  1209. el.className = cname;
  1210. }
  1211. if (!isEmpty(attrs)) {
  1212. for (const key in attrs) {
  1213. if (key === 'dataset') {
  1214. for (const key2 in attrs[key]) {
  1215. el[key][key2] = attrs[key][key2];
  1216. }
  1217. } else if (key === 'click') {
  1218. ael(el, 'click', attrs[key]);
  1219. } else if (key === 'mouseenter') {
  1220. ael(el, 'mouseenter', attrs[key]);
  1221. } else if (key === 'mouseleave') {
  1222. ael(el, 'mouseleave', attrs[key]);
  1223. } else if (key === 'container') {
  1224. if (typeof key === 'function') {
  1225. key();
  1226. }
  1227. } else {
  1228. el[key] = attrs[key];
  1229. }
  1230. }
  1231. }
  1232. return el;
  1233. } catch (ex) {
  1234. err(ex);
  1235. return el;
  1236. }
  1237. };
  1238. /**
  1239. * Create/Make Element
  1240. * @param {string} element - Element to create
  1241. * @param {string} cname - (Optional) Element class name
  1242. * @param {Object} [attrs={}] - (Optional) Element attributes
  1243. * @returns {Object} Returns created Element
  1244. */
  1245. const make = (element, cname, attrs = {}) => {
  1246. let el;
  1247. try {
  1248. el = dom.create(element);
  1249. return formAttrs(el, cname, attrs);
  1250. } catch (ex) {
  1251. err(ex);
  1252. return el;
  1253. }
  1254. };
  1255. /**
  1256. * Returns the cookie with the given name,
  1257. * or undefined if not found
  1258. * @source {@link https://javascript.info/cookie#getcookie-name}
  1259. */
  1260. const getCookie = (name) => {
  1261. let matches = doc.cookie.match(
  1262. new RegExp('(?:^|; )' + name.replace(/([.$?*|{}()[\]\\/+^])/g, '\\$1') + '=([^;]*)')
  1263. );
  1264. return matches ? decodeURIComponent(matches[1]) : false;
  1265. };
  1266. /**
  1267. * Inject CSS (Cascading Style Sheet Document) into document.head
  1268. * @param {string} css - CSS to inject
  1269. * @param {string} [name = 'CSS'] - (optional) Name of stylesheet (af-*)
  1270. * @param {Object} root - (optional) Custom document.head path
  1271. * @return {HTMLStyleElement} Style element
  1272. */
  1273. const loadCSS = async (css, name = 'CSS', root = document) => {
  1274. let sty;
  1275. try {
  1276. const head = Object.is(root, doc.head) ? root : qs('head', root || dom.search);
  1277. if (isBlank(css)) {
  1278. throw new Error('loadCSS', `Contains empty CSS string { ${name} }`);
  1279. }
  1280. if (!head) {
  1281. throw new Error('loadCSS', `Unable to locate head Element { ${head} }`);
  1282. }
  1283. sty = make('style', '', {
  1284. dataset: {
  1285. insertedBy: 'external-translator',
  1286. role: name
  1287. }
  1288. });
  1289. for (const s of qsA('head > style', root || dom.search)) {
  1290. if (!s.dataset) {
  1291. continue;
  1292. }
  1293. if (!s.dataset.role) {
  1294. continue;
  1295. }
  1296. if (Object.is(s.dataset.role, sty.dataset.role)) {
  1297. return s;
  1298. }
  1299. }
  1300. sty.textContent = css;
  1301. if (!isEmpty(root.shadowRoot)) {
  1302. root.shadowRoot.appendChild(sty);
  1303. } else {
  1304. head.appendChild(sty);
  1305. }
  1306. return sty;
  1307. } catch (ex) {
  1308. err(ex);
  1309. }
  1310. };
  1311. const controller = new AbortController();
  1312. const signal = controller.signal;
  1313. const TET = {
  1314. /**
  1315. * Get Value
  1316. * @param {string} key - Key to get the value of
  1317. * @param {Object} def - Fallback default value of key
  1318. * @returns {Object} Value or default value of key
  1319. * @link https://violentmonkey.github.io/api/gm/#gm_getvalue
  1320. * @link https://developer.mozilla.org/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
  1321. */
  1322. getValue(key, def = {}) {
  1323. try {
  1324. const params = JSON.stringify(def);
  1325. if (isGM) {
  1326. return JSON.parse(GM_getValue(key, params));
  1327. }
  1328. return window.localStorage.getItem(`TET-${key}`)
  1329. ? JSON.parse(window.localStorage.getItem(`TET-${key}`))
  1330. : def;
  1331. } catch (ex) {
  1332. err(ex);
  1333. }
  1334. },
  1335. /**
  1336. * Get info of script
  1337. * @returns {Object} Script info
  1338. * @link https://violentmonkey.github.io/api/gm/#gm_info
  1339. */
  1340. info: isGM
  1341. ? GM_info
  1342. : {
  1343. script: {
  1344. icon: '',
  1345. name: 'External Translator',
  1346. namespace: 'External Translator',
  1347. updateURL: 'https://github.com/magicoflolis/twitter-translator',
  1348. version: 'Bookmarklet'
  1349. }
  1350. },
  1351. /**
  1352. * Open a new window
  1353. * @param {string} url - URL of webpage to open
  1354. * @param {object} params - GM parameters
  1355. * @returns {object} GM_openInTab object with Window object as a fallback
  1356. * @link https://violentmonkey.github.io/api/gm/#gm_openintab
  1357. * @link https://developer.mozilla.org/docs/Web/API/Window/open
  1358. */
  1359. openInTab(
  1360. url,
  1361. params = {
  1362. active: true,
  1363. insert: true
  1364. },
  1365. features
  1366. ) {
  1367. if (!isGM && isBlank(params)) {
  1368. params = '_blank';
  1369. }
  1370. if (features) {
  1371. return win.open(url, params, features);
  1372. }
  1373. return isGM ? GM_openInTab(url, params) : win.open(url, params);
  1374. },
  1375. /**
  1376. * Set clipboard
  1377. * @param {string} txt - Text to copy
  1378. * @returns {Promise} Copies text to clipboard with GM as a fallback
  1379. * @link https://developer.mozilla.org/docs/Web/API/Clipboard/writeText
  1380. * @link https://violentmonkey.github.io/api/gm/#gm_setclipboard
  1381. */
  1382. // async setClipboard(txt, type = 'text/plain') {
  1383. // try {
  1384. // return new Promise((resolve, reject) => {
  1385. // return navigator.clipboard.writeText(txt).then(resolve, reject);
  1386. // });
  1387. // } catch (ex) {
  1388. // err(`[Clipboard] Failed to copy: ${ex}`);
  1389. // if (isGM) {
  1390. // return Promise.resolve(GM_setClipboard(txt, type));
  1391. // }
  1392. // }
  1393. // },
  1394. /**
  1395. * Set value
  1396. * @param {string} key - Key to set the value of
  1397. * @param {Object} v - Value of key
  1398. * @returns {Promise} Saves key to either GM managed storage or webpages localstorage
  1399. * @link https://violentmonkey.github.io/api/gm/#gm_setvalue
  1400. * @link https://developer.mozilla.org/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API
  1401. */
  1402. setValue(key, v) {
  1403. return new Promise((resolve) => {
  1404. v = typeof v !== 'string' ? JSON.stringify(v ?? {}) : v;
  1405. if (isGM) {
  1406. resolve(GM_setValue(key, v));
  1407. } else {
  1408. resolve(window.localStorage.setItem(`TET-${key}`, v));
  1409. }
  1410. });
  1411. },
  1412. xmlRequest: isGM
  1413. ? GM_xmlhttpRequest
  1414. : () => {
  1415. return {};
  1416. },
  1417. /**
  1418. * Fetch a URL with fetch API as fallback
  1419. *
  1420. * When GM is supported, makes a request like XMLHttpRequest, with some special capabilities, not restricted by same-origin policy
  1421. * @param {string} url - The URL to fetch
  1422. * @param {string} method - Fetch method
  1423. * @param {string} responseType - Response type
  1424. * @param {Object} data - Fetch parameters
  1425. * @param {boolean} forcefetch - Force use fetch API
  1426. * @returns {*} Fetch results
  1427. * @link https://violentmonkey.github.io/api/gm/#gm_xmlhttprequest
  1428. * @link https://developer.mozilla.org/docs/Web/API/Fetch_API
  1429. */
  1430. fetchURL(url = '', method = 'GET', responseType = 'json', data = {}, forcefetch = false) {
  1431. return new Promise((resolve, reject) => {
  1432. const params = {
  1433. method: method.toLocaleUpperCase(),
  1434. ...data
  1435. };
  1436. if (isGM && !forcefetch) {
  1437. if (params.credentials) {
  1438. Object.assign(params, {
  1439. anonymous: false
  1440. });
  1441. if (Object.is(params.credentials, 'omit')) {
  1442. Object.assign(params, {
  1443. anonymous: true
  1444. });
  1445. }
  1446. delete params.credentials;
  1447. }
  1448. } else {
  1449. if (params.onprogress) {
  1450. delete params.onprogress;
  1451. }
  1452. }
  1453. if (responseType.match(/buffer/gi)) {
  1454. fetch(url, {
  1455. signal,
  1456. ...params
  1457. })
  1458. .then((response) => {
  1459. if (!response.ok) reject(response);
  1460. resolve(response.arrayBuffer());
  1461. })
  1462. .catch(reject);
  1463. } else if (isGM && !forcefetch) {
  1464. TET.xmlRequest({
  1465. url,
  1466. responseType: responseType.toLocaleLowerCase(),
  1467. ...params,
  1468. onerror: reject,
  1469. onload: (r) => {
  1470. if (r.status !== 200) reject(`${r.status} ${url}`);
  1471. if (responseType.match(/basic/gi)) resolve(r);
  1472. resolve(r.response);
  1473. }
  1474. });
  1475. } else {
  1476. fetch(url, {
  1477. signal,
  1478. ...params
  1479. })
  1480. .then((response) => {
  1481. if (!response.ok) reject(response);
  1482. if (responseType.match(/json/gi)) {
  1483. resolve(response.json());
  1484. } else if (responseType.match(/text/gi)) {
  1485. resolve(response.text());
  1486. } else if (responseType.match(/blob/gi)) {
  1487. resolve(response.blob());
  1488. } else if (responseType.match(/document/gi)) {
  1489. const data = new DOMParser().parseFromString(response.text(), 'text/html');
  1490. resolve(data);
  1491. }
  1492. resolve(response);
  1493. })
  1494. .catch(reject);
  1495. }
  1496. });
  1497. }
  1498. };
  1499. /** element, mouseenterFn, mouseleaveFn */
  1500. const mouseEvents = (elms, enter, leave) => {
  1501. leave = leave ?? enter;
  1502. if (typeof elms === 'string') {
  1503. query(elms).then(() => {
  1504. for (const e of normalizeTarget(elms)) {
  1505. ael(e, 'mouseenter', enter);
  1506. ael(e, 'mouseleave', leave);
  1507. }
  1508. });
  1509. } else {
  1510. for (const e of elms) {
  1511. ael(e, 'mouseenter', enter);
  1512. ael(e, 'mouseleave', leave);
  1513. }
  1514. }
  1515. };
  1516. const defaultDesc = "Pretend I'm a foreign language.";
  1517. const lh = domURL.host;
  1518. const find = {
  1519. logout: !getCookie('twid'),
  1520. nitter:
  1521. /nitter|nittr|nttr|twitr|bird|hyper/.test(lh) ||
  1522. lh === 'twitter.076.ne.jp' ||
  1523. lh === 'twitter.censors.us',
  1524. twitter: lh === 'twitter.com' || lh === 'mobile.twitter.com',
  1525. tweetdeck: lh === 'tweetdeck.twitter.com',
  1526. twitlonger: /twitlonger/.test(lh),
  1527. remover: /begin_password_reset|account|logout|login|signin|signout/.test(domURL.pathname)
  1528. };
  1529. const lngFN = () => {
  1530. for (const key in languages) {
  1531. if (typeof win.navigator.languages !== 'undefined') {
  1532. for (const l of win.navigator.languages) {
  1533. if (l !== key) continue;
  1534. dLng = l;
  1535. break;
  1536. }
  1537. } else {
  1538. dLng = win.navigator.language ?? qs('html').lang;
  1539. break;
  1540. }
  1541. }
  1542. };
  1543. /** Favicons
  1544. * Each converted to "Data URI" as to prevent blocking.
  1545. * Direct Links
  1546. * azure: 'https://azurecomcdn.azureedge.net/cvt-a8c88a5179d0dccbd8e4f14c3cca7706721477d322eb184796320391845f73d9/images/icon/favicon.ico',
  1547. * bing: 'https://www.bing.com/th?id=OTT.7A274AA188550691D09FA80F322A58D2&pid=Trans',
  1548. * deepl: 'https://static.deepl.com/img/favicon/favicon_16.png',
  1549. * gCloud: 'https://www.gstatic.com/devrel-devsite/prod/v48d5b7fe78425d6a73163cf28706f05fb6b7cff97bdc98bbcd2f38818604a511/cloud/images/favicons/onecloud/favicon.ico',
  1550. * google: 'https://ssl.gstatic.com/translate/favicon.ico',
  1551. * libre: 'https://github.com/LibreTranslate/LibreTranslate/tree/main/app/static',
  1552. * lingva: 'https://github.com/thedaviddelta/lingva-translate/tree/main/public',
  1553. * mymemory: 'https://mymemory.translated.net/public/img/favicon-16x16.png',
  1554. * translate: 'https://www.translate.com/next/images/favicon/favicon.svg',
  1555. * yandex: 'https://translate.yandex.com/icons/favicon.ico',
  1556. */
  1557. const iconData = {
  1558. cache: new Map(),
  1559. sources: {
  1560. azure: `${ghCDN}/magicoflolis/twitter-translator/dist/icons/azure.ico`,
  1561. bing: `${ghCDN}/magicoflolis/twitter-translator/dist/icons/bing.svg`,
  1562. deepl: `${ghCDN}/magicoflolis/twitter-translator/dist/icons/deepl.png`,
  1563. gCloud: `${ghCDN}/magicoflolis/twitter-translator/dist/icons/googlecloud.ico`,
  1564. google: `${ghCDN}/magicoflolis/twitter-translator/dist/icons/google.ico`,
  1565. libre: `${ghCDN}/magicoflolis/twitter-translator/dist/icons/libre.ico`,
  1566. lingva: `${ghCDN}/magicoflolis/twitter-translator/dist/icons/lingva.png`,
  1567. mymemory: `${ghCDN}/magicoflolis/twitter-translator/dist/icons/mymemory.png`,
  1568. translate: `${ghCDN}/magicoflolis/twitter-translator/dist/icons/translate.svg`,
  1569. yandex: `${ghCDN}/magicoflolis/twitter-translator/dist/icons/yandex.ico`
  1570. },
  1571. async fn() {
  1572. const toDataURL = (str) => {
  1573. return new Promise((resolve) => {
  1574. TET.fetchURL(str, 'GET', 'blob').then((data) => {
  1575. const reader = new FileReader();
  1576. reader.readAsDataURL(data);
  1577. reader.onloadend = () => {
  1578. resolve(reader.result);
  1579. };
  1580. });
  1581. });
  1582. };
  1583. const makeImg = async (str) => {
  1584. try {
  1585. return await new Promise((resolve) => {
  1586. toDataURL(str).then((data) => {
  1587. const img = new Image();
  1588. dom.cl.add(img, 'tet-favicon');
  1589. img.src = data;
  1590. img.onload = () => resolve(img.outerHTML);
  1591. img.onerror = (ex) => {
  1592. err(ex);
  1593. resolve(`<img class="tet-favicon" src="${data}"/>`);
  1594. };
  1595. });
  1596. });
  1597. } catch (ex) {
  1598. return err(ex);
  1599. }
  1600. };
  1601. for (const key in this.sources) {
  1602. try {
  1603. const imgPreview = await makeImg(this.sources[key]);
  1604. this.cache.set(key, imgPreview);
  1605. } catch (ex) {
  1606. err('iconData.fn()', key, ex);
  1607. }
  1608. }
  1609. }
  1610. };
  1611. const halt = (e) => {
  1612. e.preventDefault();
  1613. e.stopPropagation();
  1614. };
  1615. const save = () => {
  1616. try {
  1617. TET.setValue('Config', cfg);
  1618. } catch (ex) {
  1619. err(ex);
  1620. }
  1621. };
  1622. /**
  1623. * @param {Node} element
  1624. * @param {MutationCallback} callback
  1625. * @param {MutationObserverInit} options
  1626. */
  1627. const observe = (element, callback, options = { subtree: true, childList: true }) => {
  1628. const observer = new MutationObserver(callback);
  1629. callback([], observer);
  1630. observer.observe(element, options);
  1631. return observer;
  1632. };
  1633. const nav = make('div', 'navbackground rm');
  1634. const tetConfirm = make('div', 'tetConfirmation tetBackground rm', {
  1635. innerHTML: `<h1 class="tetConfirmTxt tetTextColor"><span>${languages.en.quest.head}</span></h1>
  1636. <div class="tetConfirmTxt tetTextColor"><span>${languages.en.quest.body}</span></div>
  1637. <div class="tetConfirmBtns confirm tetBtn" style="background-color: rgb(239, 243, 244);" data-testid="confirmationSheetConfirm">
  1638. <div style="color: rgb(15, 20, 25);"><span><span class="tet-confirm">${languages.en.quest.yes}</span></span></div>
  1639. </div>
  1640. <div class="tetConfirmBtns deny tetDisplayColor tetBtn" data-testid="confirmationSheetCancel">
  1641. <div style="color: rgb(239, 243, 244);"><span><span class="tet-deny">${languages.en.quest.no}</span></span></div>
  1642. </div>`
  1643. });
  1644. const tetHeader = make('div', 'tet-header tetTextColor', {
  1645. innerHTML: `<span class="tet-info-name">${TET.info.script.name} Settings</span><span class="tetTextColor tet-info">v${TET.info.script.version}</span>`
  1646. });
  1647. const tetMain = make('div', 'tet-main', {
  1648. innerHTML: `<div class="r-demo tetBackground">
  1649. <div class="tet-av">
  1650. <div class="tetAvatarFrame">
  1651. </div>
  1652. </div>
  1653. <div class="tet-txt">
  1654. <div class="txt-header">
  1655. <div class="tet-at tetTextColor"><span>${
  1656. TET.info.script.name
  1657. }</span><span class="tetTextColor">@for_lollipops</span></div>
  1658. </div>
  1659. <div class="tetTextColor tet-dc"><span class="tet-demotext">${
  1660. isGM ? defaultDesc : 'ERROR Unable to resolve GM_ or GM. objects'
  1661. }</span></div>
  1662. <div id="tetDemo" class="tetSub"></div>
  1663. </div>
  1664. </div>
  1665. <div id="tetSelector" class="tetBackground">
  1666. <div id="tetName" class="tetTextColor"><span>${languages.en.lg}</span></div>
  1667. <select id="languages" name="languages" class="tetTextColor">
  1668. <option class="tetBackground" value="en">${languages.en.sel}</option>
  1669. <option class="tetBackground" value="es">${languages.es.sel}</option>
  1670. <option class="tetBackground" value="ja">${languages.ja.sel}</option>
  1671. <option class="tetBackground" value="ru">${languages.ru.sel}</option>
  1672. <option class="tetBackground" value="zh">${languages.zh.sel}</option>
  1673. <option class="tetBackground" value="bg">${languages.bg.sel}</option>
  1674. <option class="tetBackground" value="cs">${languages.cs.sel}</option>
  1675. <option class="tetBackground" value="da">${languages.da.sel}</option>
  1676. <option class="tetBackground" value="de">${languages.de.sel}</option>
  1677. <option class="tetBackground" value="el">${languages.el.sel}</option>
  1678. <option class="tetBackground" value="et">${languages.et.sel}</option>
  1679. <option class="tetBackground" value="fi">${languages.fi.sel}</option>
  1680. <option class="tetBackground" value="fr">${languages.fr.sel}</option>
  1681. <option class="tetBackground" value="hu">${languages.hu.sel}</option>
  1682. <option class="tetBackground" value="it">${languages.it.sel}</option>
  1683. <option class="tetBackground" value="lv">${languages.lv.sel}</option>
  1684. <option class="tetBackground" value="lt">${languages.lt.sel}</option>
  1685. <option class="tetBackground" value="nl">${languages.nl.sel}</option>
  1686. <option class="tetBackground" value="pl">${languages.pl.sel}</option>
  1687. <option class="tetBackground" value="pt">${languages.pt.sel}</option>
  1688. <option class="tetBackground" value="ro">${languages.ro.sel}</option>
  1689. <option class="tetBackground" value="sk">${languages.sk.sel}</option>
  1690. <option class="tetBackground" value="sl">${languages.sl.sel}</option>
  1691. <option class="tetBackground" value="sv">${languages.sv.sel}</option>
  1692. </select>
  1693. </div>
  1694. <div id="tetSelector" class="tetBackground">
  1695. <div id="tetName" class="tetTextColor"><span>${languages.en.tr}</span></div>
  1696. <select id="translator" name="translator" class="tetTextColor">
  1697. <optgroup class="tetBackground" label="External Translators ⤴">
  1698. <option class="tetBackground" value="bing">Bing Translate</option>
  1699. <option class="tetBackground" value="deepl">DeepL Translator ✨</option>
  1700. <option class="tetBackground" value="google">Google Translate</option>
  1701. <option class="tetBackground" value="lingva">Lingva Translate</option>
  1702. <option class="tetBackground" value="mymemory">MyMemory</option>
  1703. <option class="tetBackground" value="translate">Translate.com</option>
  1704. <option class="tetBackground" value="yandex">Yandex Translator</option>
  1705. </optgroup>
  1706. <optgroup class="tetBackground" label="Internal Translators ⤵">
  1707. <option class="tetBackground" value="bingIT">Azure Cognitive Services</option>
  1708. <option class="tetBackground" value="deeplIT">DeepL</option>
  1709. <option class="tetBackground" value="googleIT">Google Cloud</option>
  1710. <option class="tetBackground" value="libre">LibreTranslate</option>
  1711. <option class="tetBackground" value="lingvaIT">Lingva Translate ✨</option>
  1712. <option class="tetBackground" value="mymemoryIT">MyMemory</option>
  1713. <option class="tetBackground" value="translateIT">Translation API</option>
  1714. <option class="tetBackground" value="yandexIT">Yandex Translate API</option>
  1715. </optgroup>
  1716. </select>
  1717. </div>
  1718. <div id="tetSelector" class="tetBackground">
  1719. <div id="tetName" class="tetTextColor"><span>${languages.en.ds}</span></div>
  1720. <select id="display" name="display" class="tetTextColor">
  1721. <option class="tetBackground" value="text + icon">Text + Icon</option>
  1722. <option class="tetBackground" value="text">${languages.en.t}</option>
  1723. <option class="tetBackground" value="icon">${languages.en.i}</option>
  1724. </select>
  1725. </div>
  1726. <div id="tetSelector" class="tetBackground">
  1727. <div id="tetName" class="tetTextColor"><span>${languages.en.col}</span></div>
  1728. <select id="colorselect" name="colorselect" class="tetTextColor">
  1729. <optgroup class="tetBackground" label="Twitter">
  1730. <option class="tetBackground" value="tet-29u">${languages.en.cb}</option>
  1731. <option class="tetBackground" value="tet-186u">${languages.en.cg}</option>
  1732. <option class="tetBackground" value="tet-122u">${languages.en.co}</option>
  1733. <option class="tetBackground" value="tet-120u">${languages.en.cp}</option>
  1734. <option class="tetBackground" value="tet-249u">${languages.en.cr}</option>
  1735. <option class="tetBackground" value="tet-255u">${languages.en.cy}</option>
  1736. <optgroup class="tetBackground" label="Misc">
  1737. <option class="tetBackground" value="auto">${languages.en.ao}</option>
  1738. <option class="tetBackground" value="nitter">Nitter</option>
  1739. <option class="tetBackground" value="tweetdeck">TweetDeck</option>
  1740. </optgroup>
  1741. </select>
  1742. </div>
  1743. <div id="tetSelector" class="tetBackground">
  1744. <div id="tetName" class="tetTextColor"><span>${languages.en.th}</span></div>
  1745. <select id="theme" name="theme" class="tetTextColor">
  1746. <optgroup class="tetBackground" label="Twitter">
  1747. <option class="tetBackground" value="twdef">${languages.en.df}</option>
  1748. <option class="tetBackground" value="twdim">${languages.en.di}</option>
  1749. <option class="tetBackground" value="twlo">${languages.en.lo}</option>
  1750. </optgroup>
  1751. <optgroup class="tetBackground" label="Misc">
  1752. <option class="tetBackground" value="auto">${languages.en.ao}</option>
  1753. <option class="tetBackground" value="nitter">Nitter</option>
  1754. <option class="tetBackground" value="tweetdeck">TweetDeck</option>
  1755. </optgroup>
  1756. </select>
  1757. </div>
  1758. <input id="apifield" type="password" name="apikey" placeholder="PASTE API KEY" class="tetTextColor tetBackground tetFields deepl">
  1759. <div id="tetSelector" class="tetBackground tetFields deepl">
  1760. <div id="tetName"><span>Version</span></div>
  1761. <select id="api-version" name="api-version" class="tetTextColor">
  1762. <option class="tetBackground" value="api-free">Free</option>
  1763. <option class="tetBackground" value="api-pro">Pro</option>
  1764. </select>
  1765. </div>
  1766. <input id="apifield" type="url" name="apikey" placeholder="(OPTIONAL) PASTE URL" class="tetTextColor tetBackground tet-url">
  1767. <input id="apifield" type="password" name="apikey" placeholder="(OPTIONAL) PASTE API KEY" class="tetTextColor tetBackground tetFields libre">
  1768. <input id="apifield" type="url" name="apikey" placeholder="PASTE URL" class="tetTextColor tetBackground tetFields libre">
  1769. <input id="apifield" type="password" name="apikey" placeholder="PASTE FOLDER ID" class="tetTextColor tetBackground tetFields yandex">
  1770. <input id="apifield" type="password" name="apikey" placeholder="PASTE API KEY" class="tetTextColor tetBackground tetFields translate">
  1771. <input id="apifield" type="url" name="apikey" placeholder="PASTE URL" class="tetTextColor tetBackground tetFields lingva">
  1772. <input id="apifield" type="password" name="apikey" placeholder="PASTE API KEY" class="tetTextColor tetBackground tetFields google">
  1773. <input id="apifield" type="password" name="apikey" placeholder="PASTE API KEY" class="tetTextColor tetBackground tetFields bing">
  1774. <div id="tetReset" class="tetDisplayColor tetBtn">Defaults</div>`
  1775. });
  1776. const tetForm = make('div', 'tetBackground rm', { id: 'tetForm' });
  1777. const tetAdv = make('div', 'rm', {
  1778. id: 'tetadvanced',
  1779. innerHTML: `<div class="tetBackground">
  1780. <div class="tet-header tetTextColor">
  1781. <span class="tet-info-name">Advanced Config</span>
  1782. <span></span>
  1783. </div>
  1784. <div class="tet-main tet-container tetadvanced-container">
  1785. <div id="tetSelector" class="tetBackground">
  1786. <div id="tetName"><span>Delay Injection</span></div>
  1787. <select id="delayInject" name="delayInject" class="tetTextColor">
  1788. <option class="tetBackground" value="none">0ms (${languages.en.df})</option>
  1789. <option class="tetBackground" value="500">500ms</option>
  1790. <option class="tetBackground" value="1000">1000ms</option>
  1791. <option class="tetBackground" value="1500">1500ms</option>
  1792. <option class="tetBackground" value="2000">2000ms</option>
  1793. <option class="tetBackground" value="2500">2500ms</option>
  1794. <option class="tetBackground" value="3000">3000ms</option>
  1795. <option class="tetBackground" value="3500">3500ms</option>
  1796. <option class="tetBackground" value="4000">4000ms</option>
  1797. <option class="tetBackground" value="4000">4500ms</option>
  1798. <option class="tetBackground" value="5000">5000ms</option>
  1799. </select>
  1800. </div>
  1801. <section class="tetcheckbox">
  1802. <label class="tetTextColor">
  1803. <span>Debug</span>
  1804. <div class="tetswitch tetDisplayColor">
  1805. <input type="checkbox" name="debug" id="debug" />
  1806. <label for="debug"></label>
  1807. </div>
  1808. </label>
  1809. </section>
  1810. <section class="tetcheckbox tet-ac">
  1811. <label class="tetTextColor">
  1812. <span>Bios</span>
  1813. <div class="tetswitch tetDisplayColor">
  1814. <input type="checkbox" name="tetbio" id="tetbio" />
  1815. <label for="tetbio"></label>
  1816. </div>
  1817. </label>
  1818. </section>
  1819. <section class="tetcheckbox tet-ac tetmsg">
  1820. <label class="tetTextColor">
  1821. <span>Direct Messages</span>
  1822. <div class="tetswitch tetDisplayColor">
  1823. <input type="checkbox" name="dmsg" id="dmsg" />
  1824. <label for="dmsg"></label>
  1825. </div>
  1826. </label>
  1827. </section>
  1828. <section class="tetcheckbox tet-ac">
  1829. <label class="tetTextColor">
  1830. <span>Tweets + Replies</span>
  1831. <div class="tetswitch tetDisplayColor">
  1832. <input type="checkbox" name="tetctw" id="tetctw" />
  1833. <label for="tetctw"></label>
  1834. </div>
  1835. </label>
  1836. </section>
  1837. <section class="tetcheckbox tetst">
  1838. <label class="tetTextColor">
  1839. <span>Website Theme</span>
  1840. <div class="tetswitch tetDisplayColor">
  1841. <input type="checkbox" name="sitetheme" id="sitetheme" />
  1842. <label for="sitetheme"></label>
  1843. </div>
  1844. </label>
  1845. </section>
  1846. <div id="tetNI" class="tetDisplayColor tetBtn">Fetch Latest Nitter Instances</div>
  1847. </div>
  1848. </div>`
  1849. });
  1850. const tetAdvC = make('div', 'rm tetadvanced-icon-container', {
  1851. innerHTML:
  1852. '<svg viewBox="0 0 24 24" class="tetadvanced-icon tetTextColor"><g><path d="M12 8.21c-2.09 0-3.79 1.7-3.79 3.79s1.7 3.79 3.79 3.79 3.79-1.7 3.79-3.79-1.7-3.79-3.79-3.79zm0 6.08c-1.262 0-2.29-1.026-2.29-2.29S10.74 9.71 12 9.71s2.29 1.026 2.29 2.29-1.028 2.29-2.29 2.29z"></path><path d="M12.36 22.375h-.722c-1.183 0-2.154-.888-2.262-2.064l-.014-.147c-.025-.287-.207-.533-.472-.644-.286-.12-.582-.065-.798.115l-.116.097c-.868.725-2.253.663-3.06-.14l-.51-.51c-.836-.84-.896-2.154-.14-3.06l.098-.118c.186-.222.23-.523.122-.787-.11-.272-.358-.454-.646-.48l-.15-.014c-1.18-.107-2.067-1.08-2.067-2.262v-.722c0-1.183.888-2.154 2.064-2.262l.156-.014c.285-.025.53-.207.642-.473.11-.27.065-.573-.12-.795l-.094-.116c-.757-.908-.698-2.223.137-3.06l.512-.512c.804-.804 2.188-.865 3.06-.14l.116.098c.218.184.528.23.79.122.27-.112.452-.358.477-.643l.014-.153c.107-1.18 1.08-2.066 2.262-2.066h.722c1.183 0 2.154.888 2.262 2.064l.014.156c.025.285.206.53.472.64.277.117.58.062.794-.117l.12-.102c.867-.723 2.254-.662 3.06.14l.51.512c.836.838.896 2.153.14 3.06l-.1.118c-.188.22-.234.522-.123.788.112.27.36.45.646.478l.152.014c1.18.107 2.067 1.08 2.067 2.262v.723c0 1.183-.888 2.154-2.064 2.262l-.155.014c-.284.024-.53.205-.64.47-.113.272-.067.574.117.795l.1.12c.756.905.696 2.22-.14 3.06l-.51.51c-.807.804-2.19.864-3.06.14l-.115-.096c-.217-.183-.53-.23-.79-.122-.273.114-.455.36-.48.646l-.014.15c-.107 1.173-1.08 2.06-2.262 2.06zm-3.773-4.42c.3 0 .593.06.87.175.79.328 1.324 1.054 1.4 1.896l.014.147c.037.4.367.7.77.7h.722c.4 0 .73-.3.768-.7l.014-.148c.076-.842.61-1.567 1.392-1.892.793-.33 1.696-.182 2.333.35l.113.094c.178.148.366.18.493.18.206 0 .4-.08.546-.227l.51-.51c.284-.284.305-.73.048-1.038l-.1-.12c-.542-.65-.677-1.54-.352-2.323.326-.79 1.052-1.32 1.894-1.397l.155-.014c.397-.037.7-.367.7-.77v-.722c0-.4-.303-.73-.702-.768l-.152-.014c-.846-.078-1.57-.61-1.895-1.393-.326-.788-.19-1.678.353-2.327l.1-.118c.257-.31.236-.756-.048-1.04l-.51-.51c-.146-.147-.34-.227-.546-.227-.127 0-.315.032-.492.18l-.12.1c-.634.528-1.55.67-2.322.354-.788-.327-1.32-1.052-1.397-1.896l-.014-.155c-.035-.397-.365-.7-.767-.7h-.723c-.4 0-.73.303-.768.702l-.014.152c-.076.843-.608 1.568-1.39 1.893-.787.326-1.693.183-2.33-.35l-.118-.096c-.18-.15-.368-.18-.495-.18-.206 0-.4.08-.546.226l-.512.51c-.282.284-.303.73-.046 1.038l.1.118c.54.653.677 1.544.352 2.325-.327.788-1.052 1.32-1.895 1.397l-.156.014c-.397.037-.7.367-.7.77v.722c0 .4.303.73.702.768l.15.014c.848.078 1.573.612 1.897 1.396.325.786.19 1.675-.353 2.325l-.096.115c-.26.31-.238.756.046 1.04l.51.51c.146.147.34.227.546.227.127 0 .315-.03.492-.18l.116-.096c.406-.336.923-.524 1.453-.524z"></path></g></svg>',
  1853. click: () => {
  1854. dom.cl.add(qs('.tet-help-container'), 'rm');
  1855. dom.cl.toggle(qs('[id="tetadvanced"]'), 'rm');
  1856. }
  1857. });
  1858. const tetAdvI = make('div', 'rm tet-icon-container', {
  1859. innerHTML: `<a class="tet-icon-info tetDisplayColor" title="Help">?</a>
  1860. <div class="rm tetBackground tet-help-container">
  1861. <a class="tet-help-info tetTextColor" href="${TET.info.script.namespace}" target="_blank">Visit GitHub ⤴</a>
  1862. </div>`
  1863. });
  1864. const mkMenuSVG = () => {
  1865. const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  1866. const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
  1867. const p = document.createElementNS('http://www.w3.org/2000/svg', 'path');
  1868. dom.attr(
  1869. p,
  1870. 'd',
  1871. 'M12 2C6.486 2 2 6.486 2 12s4.486 10 10 10 10-4.486 10-10S17.514 2 12 2zm8.472 9.442c-.242.19-.472.368-.63.486-.68-1.265-1.002-1.78-1.256-2.007-.163-.145-.37-.223-.78-.375-.367-.136-1.482-.55-1.65-.85-.087-.153.136-.602.23-.793.088-.177.164-.33.196-.497.123-.646-.33-1.146-.728-1.59-.066-.072-.153-.17-.23-.26.335-.12.862-.26 1.42-.384 1.95 1.448 3.26 3.704 3.428 6.272zm-9.788-7.83c.076.25.145.5.182.678-.255.15-.663.363-.96.52-.262.136-.522.273-.738.392-.247.137-.442.234-.6.313-.347.174-.598.3-.833.553-.068.073-.26.278-1.02 1.886l-1.79-.656c1.293-1.94 3.362-3.31 5.76-3.685zM12 20.5c-4.687 0-8.5-3.813-8.5-8.5 0-1.197.25-2.335.7-3.37.47.182 1.713.66 2.75 1.035-.107.336-.245.854-.26 1.333-.03.855.502 1.7.562 1.792.053.08.12.15.2.207.303.21.687.5.827.616.063.343.166 1.26.23 1.833.144 1.266.175 1.48.24 1.65.005.012.514 1.188 1.315 1.188.576-.003.673-.206 1.855-2.688.244-.512.45-.95.513-1.058.1-.144.597-.61.87-.83.55-.442.76-1.82.413-2.682-.335-.83-1.92-2.08-2.5-2.195-.17-.033-.43-.04-.953-.053-.497-.01-1.25-.028-1.536-.09-.098-.024-.314-.094-.605-.196.32-.668.627-1.28.71-1.4.05-.052.168-.112.408-.234.17-.086.383-.192.653-.34.208-.116.458-.247.71-.38 1.168-.612 1.484-.8 1.658-1.082.11-.177.263-.44-.04-1.544 1.042.027 2.038.24 2.955.61-.89.32-1.024.595-1.106.77-.367.784.256 1.475.667 1.93.096.107.24.268.32.38l-.017.036c-.234.472-.67 1.35-.196 2.194.406.72 1.384 1.13 2.437 1.52.134.05.25.092.33.126.16.208.496.79 1 1.735l.154.285c.078.14.33.505.842.505.167 0 .363-.04.59-.137.032-.013.083-.035.18-.094C19.72 17.405 16.22 20.5 12 20.5zm-3.812-9.45c.01-.285.102-.646.184-.907l.027.006c.397.09 1.037.11 1.83.13.32.006.59.008.615 0 .326.143 1.355 1 1.483 1.31.113.28.05.812-.034 1.01-.233.197-.845.735-1.085 1.078-.093.13-.212.373-.64 1.274-.133.276-.313.654-.488 1.013-.026-.225-.054-.472-.08-.686-.225-2.003-.273-2.22-.42-2.445-.05-.078-.202-.31-1.135-.973-.117-.213-.268-.564-.26-.813z'
  1872. );
  1873. g.append(p);
  1874. dom.attr(svg, 'viewBox', '0 0 24 24');
  1875. dom.attr(svg, 'width', '1em');
  1876. dom.attr(svg, 'height', '1em');
  1877. dom.attr(svg, 'id', 'tetSVG');
  1878. dom.cl.add(svg, 'tetTextColor');
  1879. svg.append(g);
  1880. return svg;
  1881. };
  1882. const menuSvg = mkMenuSVG();
  1883. const menuSpan = make('span', '', { innerHTML: languages.en.menu });
  1884. const tetMenuButton = make('div', 'mini tetDisplayColor tetBtn', {
  1885. id: 'tetMenuButton',
  1886. title: languages.en.menu,
  1887. click: (e) => {
  1888. dom.cl.remove([nav, tetForm, tetAdvI, tetAdvC], 'rm');
  1889. dom.attr(btNav, 'style', 'z-index: 10000 !important');
  1890. dom.cl.toggle(e.target, 'mini');
  1891. dom.cl.add(dom.html, 'tetFreeze');
  1892. },
  1893. onmouseenter: (e) => {
  1894. dom.cl.toggle(e.target, cHover);
  1895. dom.attr(menuSvg, 'style', 'display: none;');
  1896. dom.cl.toggle(e.target, 'mini');
  1897. },
  1898. onmouseleave: (e) => {
  1899. dom.cl.toggle(e.target, cHover);
  1900. dom.attr(menuSvg, 'style', 'display: inline;');
  1901. dom.cl.toggle(e.target, 'mini');
  1902. delay(5000).then(() => dom.attr(menuSvg, 'style', 'display: none;'));
  1903. }
  1904. });
  1905. const btNav = make('div', 'btNav', {
  1906. id: 'tetTW',
  1907. role: 'dialog',
  1908. style: 'z-index: -1 !important;'
  1909. });
  1910. // Couldn't figure out how to make my own
  1911. // invalid_chars from https://gf.qytechs.cn/scripts/423001
  1912. const invalid_chars = {
  1913. '\\': '\',
  1914. '/': '/',
  1915. '|': '|',
  1916. '<': '<',
  1917. '>': '>',
  1918. ':': ':',
  1919. '*': '*',
  1920. '?': '?',
  1921. '"': '"',
  1922. '🔞': '',
  1923. '#': ''
  1924. };
  1925. const elmFN = (elem, encode = true) => {
  1926. // const txtFilter = /[\p{Alpha}\p{M}\p{Nd}\p{Pc}\p{Join_C}\p{Po}\p{So}\p{Sc}\d]/gu.exec(dom.text(elem));
  1927. const txtFilter =
  1928. dom.text(elem).match(/[\p{Alpha}\p{M}\p{Nd}\p{Pc}\p{Join_C}\p{Po}\p{So}\p{Sc}\d]/gu) || [];
  1929. let content = '';
  1930. for (const key of txtFilter) {
  1931. content += key.replace(/[\\/|<>*?:#"]/g, (v) => invalid_chars[v]);
  1932. }
  1933. if (encode) {
  1934. return encodeURIComponent(content);
  1935. }
  1936. return content;
  1937. };
  1938. const langChange = (lchange) => {
  1939. info('Updating language');
  1940. let cfglng = cfg.lang ?? 'en';
  1941. if (lchange) {
  1942. lng = {};
  1943. cfglng = lchange ?? cfglng;
  1944. }
  1945. for (const key in languages) {
  1946. if (key !== cfglng) continue;
  1947. if (!hasOwn(lng, key)) {
  1948. lng[key] = languages[key];
  1949. } else if (key === 'quest') {
  1950. for (const key3 in languages[key]) {
  1951. if (!hasOwn(lng[key], key3)) {
  1952. lng[key][key3] = languages[key][key3];
  1953. }
  1954. }
  1955. }
  1956. }
  1957. lng[cfglng]['ti'] = `${lng[cfglng]['t']} + ${lng[cfglng]['i']}`;
  1958. dbg('Language:', lng);
  1959. };
  1960. //#region Site n Menu Fn
  1961. const ignoreTags = new Set(['br', 'head', 'link', 'meta', 'script', 'style']);
  1962. const obi = (onDOMCreated, onDOMChanged) => {
  1963. let removedNodes = false;
  1964. let domLayoutObserver;
  1965.  
  1966. const addedNodes = [];
  1967. const addedNodeLists = [];
  1968. const removedNodeLists = [];
  1969. const safeObserverHandler = () => {
  1970. let i = addedNodeLists.length;
  1971. // eslint-disable-next-line no-plusplus
  1972. while (i--) {
  1973. const nodeList = addedNodeLists[i];
  1974. let iNode = nodeList.length;
  1975. // eslint-disable-next-line no-plusplus
  1976. while (iNode--) {
  1977. const node = nodeList[iNode];
  1978. if (node.nodeType !== 1) {
  1979. continue;
  1980. }
  1981. if (ignoreTags.has(node.localName)) {
  1982. continue;
  1983. }
  1984. if (node.parentElement === null) {
  1985. continue;
  1986. }
  1987. addedNodes.push(node);
  1988. }
  1989. }
  1990. addedNodeLists.length = 0;
  1991. i = removedNodeLists.length;
  1992. // eslint-disable-next-line no-plusplus
  1993. while (i-- && removedNodes === false) {
  1994. const nodeList = removedNodeLists[i];
  1995. let iNode = nodeList.length;
  1996. // eslint-disable-next-line no-plusplus
  1997. while (iNode--) {
  1998. if (nodeList[iNode].nodeType !== 1) {
  1999. continue;
  2000. }
  2001. removedNodes = true;
  2002. break;
  2003. }
  2004. }
  2005. removedNodeLists.length = 0;
  2006. if (addedNodes.length === 0 && removedNodes === false) {
  2007. return;
  2008. }
  2009. if (typeof onDOMChanged === 'function' || onDOMChanged instanceof Function) {
  2010. onDOMChanged(addedNodes, removedNodes);
  2011. }
  2012. addedNodes.length = 0;
  2013. removedNodes = false;
  2014. };
  2015. const observerHandler = (mutations) => {
  2016. let i = mutations.length;
  2017. while (i--) {
  2018. const mutation = mutations[i];
  2019. let nodeList = mutation.addedNodes;
  2020. if (nodeList.length !== 0) {
  2021. addedNodeLists.push(nodeList);
  2022. }
  2023. nodeList = mutation.removedNodes;
  2024. if (nodeList.length !== 0) {
  2025. removedNodeLists.push(nodeList);
  2026. }
  2027. }
  2028. if (addedNodeLists.length !== 0 || removedNodeLists.length !== 0) {
  2029. safeObserverHandler();
  2030. }
  2031. };
  2032. const startObserver = () => {
  2033. if (domLayoutObserver !== undefined) {
  2034. return;
  2035. }
  2036. domLayoutObserver = new MutationObserver(observerHandler);
  2037. domLayoutObserver.observe(document, {
  2038. childList: true,
  2039. subtree: true
  2040. });
  2041. };
  2042. if (typeof onDOMCreated === 'function' || onDOMCreated instanceof Function) {
  2043. onDOMCreated();
  2044. }
  2045. startObserver();
  2046. };
  2047. async function configDisplay() {
  2048. const getIcon = (icon) => {
  2049. const resp = iconData.cache.get(icon);
  2050. return isEmpty(resp) ? '' : resp;
  2051. };
  2052. return new Promise((resolve) => {
  2053. const dis = cfg.display;
  2054. const tra = cfg.translator;
  2055. if (!dis) throw new Error(`cfg.display is undefined ${dis}`);
  2056. if (dis === 'text + icon') {
  2057. tra.match(/lingva/gi)
  2058. ? resolve(`Lingva Translate ${getIcon('lingva')}`)
  2059. : tra.match(/libre/gi)
  2060. ? resolve(`LibreTranslate ${getIcon('libre')}`)
  2061. : tra == 'bingIT'
  2062. ? resolve(`Azure Cognitive Services ${getIcon('azure')}`)
  2063. : tra == 'bing'
  2064. ? resolve(`Bing ${getIcon('bing')}`)
  2065. : tra == 'googleIT'
  2066. ? resolve(`Google Cloud ${getIcon('gCloud')}`)
  2067. : tra == 'google'
  2068. ? resolve(`Google ${getIcon('google')}`)
  2069. : tra.match(/mymemory/gi)
  2070. ? resolve(`MyMemory ${getIcon('mymemory')}`)
  2071. : tra.match(/translate/gi)
  2072. ? resolve(`Translate.com ${getIcon('translate')}`)
  2073. : tra.match(/yandex/gi)
  2074. ? resolve(`Yandex ${getIcon('yandex')}`)
  2075. : resolve(`DeepL ${getIcon('deepl')}`);
  2076. } else if (dis === 'icon') {
  2077. tra.match(/lingva/gi)
  2078. ? resolve(getIcon('lingva'))
  2079. : tra.match(/libre/gi)
  2080. ? resolve(getIcon('libre'))
  2081. : tra == 'bingIT'
  2082. ? resolve(getIcon('azure'))
  2083. : tra == 'bing'
  2084. ? resolve(getIcon('bing'))
  2085. : tra == 'googleIT'
  2086. ? resolve(getIcon('gCloud'))
  2087. : tra == 'google'
  2088. ? resolve(getIcon('google'))
  2089. : tra.match(/mymemory/gi)
  2090. ? resolve(getIcon('mymemory'))
  2091. : tra.match(/translate/gi)
  2092. ? resolve(getIcon('translate'))
  2093. : tra.match(/yandex/gi)
  2094. ? resolve(getIcon('yandex'))
  2095. : resolve(getIcon('deepl'));
  2096. } else {
  2097. tra.match(/lingva/gi)
  2098. ? resolve('Lingva Translate')
  2099. : tra.match(/libre/gi)
  2100. ? resolve('LibreTranslate')
  2101. : tra == 'bingIT'
  2102. ? resolve('Azure Cognitive Services')
  2103. : tra == 'bing'
  2104. ? resolve('Bing')
  2105. : tra == 'googleIT'
  2106. ? resolve('Google Cloud')
  2107. : tra == 'google'
  2108. ? resolve('Google')
  2109. : tra.match(/mymemory/gi)
  2110. ? resolve('MyMemory')
  2111. : tra.match(/translate/gi)
  2112. ? resolve('Translate.com')
  2113. : tra.match(/yandex/gi)
  2114. ? resolve('Yandex')
  2115. : resolve('DeepL');
  2116. }
  2117. })
  2118. .then((display) => {
  2119. const tw = lng[cfg.lang ?? 'en'].tw;
  2120. qs('#tetDemo').innerHTML = `${tw} ${display}`;
  2121. if (!qs('.tet')) return;
  2122. for (const t of qsA('.tet')) {
  2123. t.innerHTML = `${tw} ${display}`;
  2124. }
  2125. })
  2126. .catch(err);
  2127. }
  2128. const translate = async (elem, btnDiv, srcLang = 'auto', content = '') => {
  2129. const tr = cfg.translator;
  2130. if (elem.parentElement.contains(btnDiv)) {
  2131. dom.cl.toggle(btnDiv, 'rm');
  2132. return 'Already exists';
  2133. }
  2134. if (tr.match(/IT|libre/gi)) {
  2135. elem.innerHTML = `${lng[cfg.lang].l}...`;
  2136. if (tr.match(/lingva/gi)) {
  2137. return TET.fetchURL(`${cfg.url.lingva}/api/v1/${srcLang}/${cfg.lang}/${content}`);
  2138. } else if (tr.match(/libre/gi)) {
  2139. return TET.fetchURL(cfg.url.libre, 'POST', {
  2140. body: JSON.stringify({
  2141. q: content,
  2142. source: srcLang,
  2143. target: cfg.lang,
  2144. format: 'text',
  2145. api_key: cfg.api.libre
  2146. })
  2147. });
  2148. } else if (tr.match(/bing/gi)) {
  2149. return 'Work in progress';
  2150. } else if (tr.match(/google/gi)) {
  2151. return TET.fetchURL(
  2152. `${cfg.url[tr]}/language/translate/v2?q=${content}&target=${cfg.lang}&source=${srcLang}&key=${cfg.api.google}`
  2153. )
  2154. } else if (tr.match(/mymemory/gi)) {
  2155. return TET.fetchURL(`${cfg.url[tr]}/get?q=${content}&langpair=${srcLang}|${cfg.lang}`)
  2156. } else if (tr.match(/translate/gi)) {
  2157. await TET.fetchURL('https://api.translate.com/translate/v1/login', 'POST', {
  2158. body: JSON.stringify({
  2159. email: srcLang,
  2160. password: cfg.lang
  2161. })
  2162. })
  2163. return TET.fetchURL(cfg.url[tr], 'POST', {
  2164. body: JSON.stringify({
  2165. text: content,
  2166. source_language: srcLang,
  2167. translation_language: cfg.lang
  2168. })
  2169. })
  2170. } else if (tr.match(/yandex/gi)) {
  2171. return TET.fetchURL(cfg.url[tr], 'POST', {
  2172. body: JSON.stringify({
  2173. sourceLanguageCode: srcLang,
  2174. targetLanguageCode: cfg.lang,
  2175. format: 'string',
  2176. texts: [content],
  2177. folderId: cfg.api.yandex
  2178. })
  2179. })
  2180. } else if (tr.match(/deepl/gi)) {
  2181. return TET.fetchURL(
  2182. `https://${
  2183. cfg.api.version.match(/pro/gi) ? 'api' : 'api-free'
  2184. }.deepl.com/v2/translate?auth_key=${cfg.api.deepl}&text=${content}&target_lang=${
  2185. cfg.lang
  2186. }`
  2187. )
  2188. }
  2189. return 'Unable to locate selected translator';
  2190. }
  2191. if (tr.match(/lingva/gi)) {
  2192. return `${cfg.url[tr]}/${srcLang}/${cfg.lang}/${content}`;
  2193. } else if (tr.match(/bing/gi)) {
  2194. return `${cfg.url[tr]}/translator/?text=${content}&from=${srcLang}&to=${cfg.lang}`;
  2195. } else if (tr.match(/google/gi)) {
  2196. return `${cfg.url[tr]}/?q=${content}&sl=${srcLang}&tl=${cfg.lang}`;
  2197. } else if (tr.match(/mymemory/gi)) {
  2198. return `${cfg.url[tr]}/${cfg.lang}/${srcLang}/${cfg.lang}/${content}`;
  2199. } else if (tr.match(/translate/gi)) {
  2200. return `${cfg.url[tr]}/machine-translation#${srcLang}/${cfg.lang}/${content}`;
  2201. } else if (tr.match(/yandex/gi)) {
  2202. return `${cfg.url[tr]}/?lang=${srcLang}-${cfg.lang}&text=${content}`;
  2203. } else if (tr.match(/deepl/gi)) {
  2204. return `${cfg.url[tr]}/translator#${srcLang}/${cfg.lang}/${content}`;
  2205. }
  2206. return 'Unable to locate selected translator';
  2207. }
  2208. /** Src Element, Src Language, Src Content, Inject Mode */
  2209. function handleButton(source, srcLang = 'auto', content = '', mode = 'append', extras = {}) {
  2210. mode = isEmpty(mode) ? 'append' : mode;
  2211. srcLang = isEmpty(srcLang) ? 'auto' : srcLang;
  2212. const ntStyle = 'margin: 0px 0px 0px 58px !important; padding: .75em;';
  2213. const btnDiv = make('div', `tetTextColor ${cText}`, { id: 'tweet-text' });
  2214. const btnSpan = make('span');
  2215. btnDiv.append(btnSpan);
  2216. const tetBtn = make('div', `tet ${cSub}`, {
  2217. mouseenter: (e) => dom.cl.add(e.target, 'r-hover'),
  2218. mouseleave: (e) => dom.cl.remove(e.target, 'r-hover'),
  2219. onclick: (e) => {
  2220. halt(e);
  2221. if (e.target.innerHTML.match(/error/i)) {
  2222. e.target.remove();
  2223. btnDiv.remove();
  2224. }
  2225. // let tr = cfg.translator;
  2226. // const findTR = () => {
  2227. // if (e.target.parentElement.contains(btnDiv)) {
  2228. // dom.cl.toggle(btnDiv, 'rm');
  2229. // return 'Already exists';
  2230. // }
  2231. // return new Promise((resolve, reject) => {
  2232. // if (tr.match(/IT|libre/gi)) {
  2233. // e.target.innerHTML = `${lng[cfg.lang].l}...`;
  2234. // if (tr.match(/lingva/gi)) {
  2235. // resolve(TET.fetchURL(`${cfg.url.lingva}/api/v1/${srcLang}/${cfg.lang}/${content}`));
  2236. // } else if (tr.match(/libre/gi)) {
  2237. // resolve(
  2238. // TET.fetchURL(cfg.url.libre, 'POST', {
  2239. // body: JSON.stringify({
  2240. // q: content,
  2241. // source: srcLang,
  2242. // target: cfg.lang,
  2243. // format: 'text',
  2244. // api_key: cfg.api.libre
  2245. // })
  2246. // })
  2247. // );
  2248. // } else if (tr.match(/bing/gi)) {
  2249. // reject('Work in progress');
  2250. // } else if (tr.match(/google/gi)) {
  2251. // resolve(
  2252. // TET.fetchURL(
  2253. // `${cfg.url[tr]}/language/translate/v2?q=${content}&target=${cfg.lang}&source=${srcLang}&key=${cfg.api.google}`
  2254. // )
  2255. // );
  2256. // } else if (tr.match(/mymemory/gi)) {
  2257. // resolve(
  2258. // TET.fetchURL(`${cfg.url[tr]}/get?q=${content}&langpair=${srcLang}|${cfg.lang}`)
  2259. // );
  2260. // } else if (tr.match(/translate/gi)) {
  2261. // resolve(
  2262. // TET.fetchURL('https://api.translate.com/translate/v1/login', 'POST', {
  2263. // body: JSON.stringify({
  2264. // email: srcLang,
  2265. // password: cfg.lang
  2266. // })
  2267. // }).then(() => {
  2268. // TET.fetchURL(cfg.url[tr], 'POST', {
  2269. // body: JSON.stringify({
  2270. // text: content,
  2271. // source_language: srcLang,
  2272. // translation_language: cfg.lang
  2273. // })
  2274. // });
  2275. // })
  2276. // );
  2277. // } else if (tr.match(/yandex/gi)) {
  2278. // resolve(
  2279. // TET.fetchURL(cfg.url[tr], 'POST', {
  2280. // body: JSON.stringify({
  2281. // sourceLanguageCode: srcLang,
  2282. // targetLanguageCode: cfg.lang,
  2283. // format: 'string',
  2284. // texts: [content],
  2285. // folderId: cfg.api.yandex
  2286. // })
  2287. // })
  2288. // );
  2289. // } else if (tr.match(/deepl/gi)) {
  2290. // resolve(
  2291. // TET.fetchURL(
  2292. // `https://${
  2293. // cfg.api.version.match(/pro/gi) ? 'api' : 'api-free'
  2294. // }.deepl.com/v2/translate?auth_key=${cfg.api.deepl}&text=${content}&target_lang=${
  2295. // cfg.lang
  2296. // }`
  2297. // )
  2298. // );
  2299. // }
  2300. // reject('Unable to locate selected translator');
  2301. // }
  2302. // if (tr.match(/lingva/gi)) {
  2303. // resolve(`${cfg.url[tr]}/${srcLang}/${cfg.lang}/${content}`);
  2304. // } else if (tr.match(/bing/gi)) {
  2305. // resolve(`${cfg.url[tr]}/translator/?text=${content}&from=${srcLang}&to=${cfg.lang}`);
  2306. // } else if (tr.match(/google/gi)) {
  2307. // resolve(`${cfg.url[tr]}/?q=${content}&sl=${srcLang}&tl=${cfg.lang}`);
  2308. // } else if (tr.match(/mymemory/gi)) {
  2309. // resolve(`${cfg.url[tr]}/${cfg.lang}/${srcLang}/${cfg.lang}/${content}`);
  2310. // } else if (tr.match(/translate/gi)) {
  2311. // resolve(`${cfg.url[tr]}/machine-translation#${srcLang}/${cfg.lang}/${content}`);
  2312. // } else if (tr.match(/yandex/gi)) {
  2313. // resolve(`${cfg.url[tr]}/?lang=${srcLang}-${cfg.lang}&text=${content}`);
  2314. // } else if (tr.match(/deepl/gi)) {
  2315. // resolve(`${cfg.url[tr]}/translator#${srcLang}/${cfg.lang}/${content}`);
  2316. // }
  2317. // reject('Unable to locate selected translator');
  2318. // });
  2319. // };
  2320. // findTR()
  2321. translate(e.target, btnDiv, srcLang, content).then((r) => {
  2322. configDisplay();
  2323. if (typeof r === 'string') {
  2324. if (r.match(/already exists/i)) return;
  2325. return TET.openInTab(r);
  2326. }
  2327. const resp = () => {
  2328. for (const k in r) {
  2329. return k.includes('translation')
  2330. ? r.translation
  2331. : k.includes('responseData')
  2332. ? r.responseData.translatedText
  2333. : k.includes('data')
  2334. ? r.data.translations[0].translatedText ?? r.data.translation
  2335. : k.includes('translatedText')
  2336. ? r.translatedText
  2337. : k.includes('translations')
  2338. ? r.translations[0].text
  2339. : r;
  2340. }
  2341. };
  2342. btnSpan.innerHTML = resp();
  2343. if (!e.target.parentElement.contains(btnDiv)) {
  2344. e.target.after(btnDiv);
  2345. }
  2346. })
  2347. .catch((ex) => {
  2348. err(ex);
  2349. btnSpan.innerHTML += `---> ${JSON.stringify(ex, null, ' ')}`;
  2350. if (!e.target.parentElement.contains(btnDiv)) e.target.after(btnDiv);
  2351. e.target.innerHTML = 'Encounted an Error';
  2352. });
  2353. },
  2354. ...extras
  2355. });
  2356.  
  2357. /append|after|before|prepend/i.test(mode)
  2358. ? source[mode](tetBtn)
  2359. : mode === 'afterend'
  2360. ? source.insertAdjacentHTML('afterend', tetBtn)
  2361. : mode === 'tdTweet'
  2362. ? source.after(tetBtn)
  2363. : mode === 'tdBio'
  2364. ? source.after(tetBtn)
  2365. : mode === 'nitter'
  2366. ? (source.after(tetBtn), dom.attr([tetBtn, btnDiv], 'style', ntStyle))
  2367. : mode.prepend(tetBtn);
  2368.  
  2369. configDisplay();
  2370. }
  2371. //#endregion
  2372.  
  2373. //#region Sites
  2374. const trigDelay = (callback) => {
  2375. if (cfg.delay === 'none') {
  2376. callback();
  2377. return;
  2378. }
  2379. delay(cfg.delay).then(callback);
  2380. };
  2381. const site = {
  2382. nitter() {
  2383. const twtFN = () => {
  2384. for (const tc of qsA('.tweet-content')) {
  2385. if (
  2386. !tc.parentElement.parentElement.nextElementSibling ||
  2387. !tc.parentElement.parentElement.nextElementSibling.className.includes('tet')
  2388. ) {
  2389. const c = elmFN(tc);
  2390. handleButton(tc.parentElement.parentElement, 'auto', c, 'nitter');
  2391. }
  2392. }
  2393. };
  2394. trigDelay(twtFN);
  2395. },
  2396. tweetdeck(elem) {
  2397. try {
  2398. const twtFN = () => {
  2399. const item = qs('p.js-tweet-text', elem);
  2400. if (item.lang) {
  2401. if (item.lang.includes(languages[cfg.lang ?? 'en']) && !item.nextElementSibling) return;
  2402. if (!item.nextElementSibling) return;
  2403. if (!item.nextElementSibling.className.includes('js-translate-call-to-action')) return;
  2404. if (!item.nextElementSibling.nextElementSibling) return;
  2405. if (item.nextElementSibling.nextElementSibling.className.includes('tet')) return;
  2406. const c = elmFN(item);
  2407. handleButton(item.nextElementSibling, item.lang, c, 'tdTweet');
  2408. } else {
  2409. if (!item.nextElementSibling) return;
  2410. if (item.nextElementSibling.className.includes('tet')) return;
  2411. const c = elmFN(item);
  2412. handleButton(item, 'auto', c, 'tdTweet');
  2413. }
  2414. // for (const item of qsA('p.js-tweet-text', elem)) {
  2415. // if (item.lang) {
  2416. // if (item.lang.includes(languages[cfg.lang ?? 'en']) && !item.nextElementSibling)
  2417. // continue;
  2418. // if (!item.nextElementSibling) continue;
  2419. // if (!item.nextElementSibling.className.includes('js-translate-call-to-action'))
  2420. // continue;
  2421. // if (!item.nextElementSibling.nextElementSibling) continue;
  2422. // if (item.nextElementSibling.nextElementSibling.className.includes('tet')) continue;
  2423. // elmFN(item).then((c) => {
  2424. // handleButton(item.nextElementSibling, item.lang, c, 'tdTweet');
  2425. // });
  2426. // } else {
  2427. // if (!item.nextElementSibling) continue;
  2428. // if (item.nextElementSibling.className.includes('tet')) continue;
  2429. // elmFN(item).then((c) => {
  2430. // handleButton(item, 'auto', c, 'tdTweet');
  2431. // });
  2432. // }
  2433. // }
  2434. };
  2435. trigDelay(twtFN);
  2436. } catch (ex) {
  2437. err(ex);
  2438. }
  2439. },
  2440. twitlonger() {
  2441. const content = qs('p#posttext').innerText;
  2442. const source = qs('.actions.text-right');
  2443. const twtFN = () => {
  2444. if (source && !qs('.tet')) {
  2445. handleButton(source, 'auto', content, 'prepend');
  2446. }
  2447. };
  2448. trigDelay(twtFN);
  2449. },
  2450. twitter(elem) {
  2451. const twtFN = () => {
  2452. if (typeof elem === 'string') {
  2453. for (const e of qsA(elem)) {
  2454. const lang = elem.lang || elem.lng;
  2455. if (elem.dataset.testid === 'tweetText' && isEmpty(lang)) continue;
  2456. if (lang === 'zxx') continue;
  2457. if (lang === 'qme') continue;
  2458. if (lang === cfg.lang) continue;
  2459. const tweetContainer = e;
  2460. if (e.nextElementSibling) {
  2461. if (
  2462. e.nextElementSibling.className.includes('css-901oao') &&
  2463. !e.nextElementSibling.nextElementSibling
  2464. ) {
  2465. const c = elmFN(tweetContainer);
  2466. !tweetContainer.lang || tweetContainer.lang === ''
  2467. ? handleButton(tweetContainer.parentElement, 'auto', c)
  2468. : handleButton(tweetContainer.parentElement, tweetContainer.lang, c);
  2469. }
  2470. if (e.nextElementSibling.className.includes('tet')) {
  2471. const c = elmFN(tweetContainer);
  2472. !tweetContainer.lang || tweetContainer.lang === ''
  2473. ? handleButton(tweetContainer.parentElement, 'auto', c)
  2474. : handleButton(tweetContainer.parentElement, tweetContainer.lang, c);
  2475. }
  2476. }
  2477. }
  2478. return;
  2479. }
  2480. const c = elmFN(elem);
  2481. const lang = elem.lang || elem.lng;
  2482. if (lang === 'zxx') return;
  2483. if (lang === 'qme') return;
  2484. if (lang === cfg.lang) return;
  2485. handleButton(elem.parentElement, lang, c, 'append', {
  2486. style:
  2487. dom.attr(elem.parentElement, 'role') === 'presentation'
  2488. ? `color: ${getComputedStyle(elem).getPropertyValue('color')};`
  2489. : ''
  2490. });
  2491. };
  2492. trigDelay(twtFN);
  2493. },
  2494. async inject() {
  2495. info('Site:', lh);
  2496. if (find.tweetdeck) {
  2497. const onDOMChanged = (addedNodes) => {
  2498. if (isBlank(addedNodes)) {
  2499. return;
  2500. }
  2501. for (const node of addedNodes) {
  2502. for (const elem of qsA('p.prf-bio', node)) {
  2503. const twtFN = () => {
  2504. if (elem && !elem.nextElementSibling.className.includes('tet')) {
  2505. handleButton(elem, 'auto', elem.innerText, 'tdBio');
  2506. }
  2507. };
  2508. trigDelay(twtFN);
  2509. }
  2510. for (const elem of qsA('div.tweet-detail', node)) {
  2511. this.tweetdeck(elem);
  2512. }
  2513. for (const elem of qsA('div.message-detail', node)) {
  2514. this.tweetdeck(elem);
  2515. }
  2516. }
  2517. };
  2518. obi(null, onDOMChanged);
  2519. } else if (find.twitter) {
  2520. const onDOMChanged = (addedNodes) => {
  2521. if (isBlank(addedNodes)) {
  2522. return;
  2523. }
  2524. for (const node of addedNodes) {
  2525. if (node.matches('.r-1pi2tsx.r-13qz1uu')) {
  2526. if (
  2527. /logout|login|signin|signout|profile|keyboard_shortcuts|display|video|photo|compose/.test(
  2528. location.pathname
  2529. )
  2530. ) {
  2531. info('Hiding menu');
  2532. dom.attr(tetMenuButton, 'style', 'z-index: -1 !important;');
  2533. }
  2534. }
  2535. for (const elem of qsA('div.r-nsbfu8 > .r-1s2bzr4 > div.css-901oao', node)) {
  2536. if (dom.cl.has(elem, 'tetInj')) continue;
  2537. if (elem.parentElement.contains(qs('.tet'))) continue;
  2538. dom.cl.add(elem, 'tetInj')
  2539. const hoverFN = () => {
  2540. handleButton(elem.lastElementChild, 'auto', elmFN(elem, false), 'after');
  2541. };
  2542. delay(250).then(() => {
  2543. trigDelay(hoverFN);
  2544. });
  2545. }
  2546. if (cfg.bios) {
  2547. for (const elem of qsA('div[data-testid="UserDescription"]', node)) {
  2548. this.twitter(elem);
  2549. }
  2550. }
  2551. }
  2552. const tweets = addedNodes.filter((node) => !isEmpty(node.getAttribute('data-testid')));
  2553. if (isBlank(tweets)) {
  2554. return;
  2555. }
  2556. for (const node of tweets) {
  2557. for (const elem of qsA('div[data-testid="tweetText"]', node)) {
  2558. this.twitter(elem);
  2559. }
  2560. }
  2561. tweets.length = 0;
  2562. };
  2563. obi(null, onDOMChanged);
  2564. } else if (find.twitlonger) {
  2565. await query('[id="postcontent"]');
  2566. this.twitlonger();
  2567. }
  2568. const nitterObserver = () => {
  2569. let preElement = '';
  2570. const bioFN = () => {
  2571. if (!qs('.profile-bio').contains(qs('.tet'))) {
  2572. const c = elmFN(qs('div.profile-bio > p'));
  2573. handleButton(qs('div.profile-bio > p').parentElement, 'auto', c);
  2574. }
  2575. };
  2576. observe(doc.body, (mutations) => {
  2577. for (const mutation of mutations) {
  2578. for (const node of mutation.addedNodes) {
  2579. if (!(node instanceof HTMLElement)) continue;
  2580. if (cfg.bios) {
  2581. for (const elm of qsA('div.profile-bio > p', node)) {
  2582. if (elm.innerText === preElement) continue;
  2583. preElement = elm.innerText;
  2584. trigDelay(bioFN);
  2585. break;
  2586. }
  2587. }
  2588. if (cfg.tweets) {
  2589. qsA('div.tweet-body', node).forEach(() => delay(250).then(() => this.nitter()));
  2590. }
  2591. }
  2592. }
  2593. });
  2594. this.nitter();
  2595. };
  2596. if (!isBlank(cfg.nitterInstances)) {
  2597. dbg('Finding Nitter instance...', cfg.nitterInstances);
  2598. for (const key of cfg.nitterInstances) {
  2599. const instance = key.url.slice(8);
  2600. if (lh === instance) {
  2601. nitterObserver();
  2602. break;
  2603. }
  2604. }
  2605. } else if (find.nitter) nitterObserver();
  2606. }
  2607. };
  2608. //#endregion
  2609.  
  2610. async function Menu() {
  2611. try {
  2612. // doc.body.appendChild(btNav); doc.body.appendChild(tetMenuButton);
  2613. const selLG = qs('select#languages');
  2614. const selCS = qs('select#colorselect');
  2615. const selTH = qs('select#theme');
  2616. const selTR = qs('select#translator');
  2617. const selDS = qs('select#display');
  2618. const selDI = qs('select#delayInject');
  2619. const libre = qsA('input.libre');
  2620. const lingva = qs('input.lingva');
  2621. const dlAPI = qs('input.deepl');
  2622. const goAPI = qs('input.google');
  2623. const selAPI = qs('select#api-version');
  2624. const autoColor = async () => {
  2625. if (find.twitter) {
  2626. if (find.logout) {
  2627. return 'rgb(29, 155, 240)';
  2628. } else {
  2629. const sb = await query('a[href="/compose/tweet"]');
  2630. const bgColor = getComputedStyle(sb).getPropertyValue('background-color');
  2631. return bgColor == 'rgb(29, 155, 240)'
  2632. ? 'tet-29u'
  2633. : bgColor == 'rgb(255, 212, 0)'
  2634. ? 'tet-255u'
  2635. : bgColor == 'rgb(249, 24, 128)'
  2636. ? 'tet-249u'
  2637. : bgColor == 'rgb(120, 86, 255)'
  2638. ? 'tet-120u'
  2639. : bgColor == 'rgb(255, 122, 0)'
  2640. ? 'tet-122u'
  2641. : bgColor == 'rgb(0, 186, 124)'
  2642. ? 'tet-186u'
  2643. : bgColor;
  2644. }
  2645. } else if (find.tweetdeck) {
  2646. cHover = 'r-hoverTD';
  2647. cColor = 'Button--primary';
  2648. cSub = 'tet-td';
  2649. return 'tweetdeck';
  2650. } else if (find.twitlonger) {
  2651. return 'tet-29u';
  2652. }
  2653. cHover = 'tetNitterHover';
  2654. cColor = 'tetNitter';
  2655. cSub = 'tetNText';
  2656. return 'nitter';
  2657. };
  2658. dlAPI.value = cfg.api.deepl ?? cfgDefault.api.deepl;
  2659. libre[0].value = cfg.api.libre ?? cfgDefault.api.libre;
  2660. libre[1].value = cfg.url.libre ?? cfgDefault.url.libre;
  2661. lingva.value = cfg.url.lingva ?? cfgDefault.url.lingva;
  2662. goAPI.value = cfg.api.google ?? cfgDefault.api.google;
  2663. selAPI.value = cfg.api.version;
  2664. selLG.value = cfg.lang ?? 'en';
  2665. let v = lng[selLG.value ?? cfg.lang ?? 'en'];
  2666. selCS.value = /auto/.test(cfg.colors) ? 'auto' : cfg.colors;
  2667. if (selCS.value === '') selCS.value = 'auto';
  2668. selTH.value = /auto/.test(cfg.theme) ? 'auto' : cfg.theme;
  2669. selTR.value = cfg.translator;
  2670. selDS.value = cfg.display;
  2671. selDI.value = cfg.delay;
  2672. qs('input#debug').checked = cfg.debug;
  2673. qs('input#dmsg').checked = cfg.dms;
  2674. qs('input#tetbio').checked = cfg.bios;
  2675. qs('input#tetctw').checked = cfg.tweets;
  2676. qs('input#sitetheme').checked = cfg.sitetheme;
  2677. qs('.tet-url').value = cfg.url[selTR.value];
  2678. const TETLanguageChange = (m) => {
  2679. v = lng[m] ?? v;
  2680. tetMenuButton.setAttribute('title', v.menu);
  2681. tetMenuButton.children[1].innerText = v.menu;
  2682. qs('select#languages').previousElementSibling.children[0].innerText = v.lg;
  2683. qs('select#translator').previousElementSibling.children[0].innerText = v.tr;
  2684. qs('select#display').previousElementSibling.children[0].innerText = v.ds;
  2685. qs('select#theme').previousElementSibling.children[0].innerText = v.th;
  2686. qs('select#colorselect').previousElementSibling.children[0].innerText = v.col;
  2687. qs('option[value="twdef"]').innerText = v.df;
  2688. qs('option[value="twdim"]').innerText = v.di;
  2689. qs('option[value="twlo"]').innerText = v.lo;
  2690. for (const o of qsA('option[value="auto"]')) {
  2691. o.innerText = v.ao;
  2692. }
  2693. qs('option[value="tet-29u"]').innerText = v.cb;
  2694. qs('option[value="tet-255u"]').innerText = v.cy;
  2695. qs('option[value="tet-249u"]').innerText = v.cr;
  2696. qs('option[value="tet-120u"]').innerText = v.cp;
  2697. qs('option[value="tet-122u"]').innerText = v.co;
  2698. qs('option[value="tet-186u"]').innerText = v.cg;
  2699. qs('option[value="text + icon"]').innerText = v.ti;
  2700. qs('option[value="text"]').innerText = v.t;
  2701. qs('option[value="icon"]').innerText = v.i;
  2702. qs('#tetReset').innerText = v.res;
  2703. qs('h1.tetConfirmTxt > span').innerText = v.quest.head;
  2704. qs('div.tetConfirmTxt > span').innerText = v.quest.body;
  2705. qs('.tet-confirm').innerText = v.quest.yes;
  2706. qs('.tet-deny').innerText = v.quest.no;
  2707. qs('#delayInject > option[value="none"]').innerText = `0ms (${v.df})`;
  2708. configDisplay();
  2709. };
  2710. const demoUpdate = (txt) => (qs('.tet-demotext').innerText = txt);
  2711. const translatorSwap = (elem) => {
  2712. for (const i of qsA('.tetFields')) {
  2713. if (dom.cl.has(i, elem)) {
  2714. dom.attr(i, 'style', 'display: inline;');
  2715. } else {
  2716. dom.attr(i, 'style', 'display: none;');
  2717. }
  2718. }
  2719. };
  2720. const TETMenuUpdate = (cSel, type) => {
  2721. if (type === 'theme') {
  2722. cTheme = '';
  2723. cText = '';
  2724. cBG = '';
  2725. cSel == 'twdef'
  2726. ? ((cTheme = 'r-14lw9ot'), (cBG = 'rgba(0, 0, 0, 0.4)'), (cText = 'r-18jsvk2'))
  2727. : cSel == 'twdim'
  2728. ? ((cTheme = 'r-yfoy6g'), (cBG = 'rgba(91, 112, 131, 0.4)'), (cText = 'r-jwli3a'))
  2729. : cSel == 'nitter'
  2730. ? ((cTheme = 'nitter'), (cBG = 'rgba(0, 0, 0, 0.4)'), (cText = 'tetNTextColor'))
  2731. : cSel == 'btd'
  2732. ? ((cTheme = 'r-tetBTD'), (cBG = 'rgba(0, 0, 0, 0.4)'), (cText = 'r-jwli3a'))
  2733. : cSel == 'tweetdeck'
  2734. ? ((cTheme = 'r-tetTD'), (cBG = 'rgba(0, 0, 0, 0.4)'), (cText = 'r-jwli3a'))
  2735. : ((cTheme = 'r-kemksi'), (cBG = 'rgba(91, 112, 131, 0.4)'), (cText = 'r-jwli3a'));
  2736. return;
  2737. } else if (type === 'colors') {
  2738. cHover = '';
  2739. cColor = '';
  2740. cSub = '';
  2741. return cSel == 'tet-29u'
  2742. ? ((cHover = 'r-1q3imqu'), (cColor = 'r-p1n3y5 r-1bih22f'), (cSub = 'r-13gxpu9'))
  2743. : cSel == 'nitter'
  2744. ? ((cHover = 'tetNitterHover'), (cColor = 'tetNitter'), (cSub = 'tetNText'))
  2745. : cSel == 'btd'
  2746. ? ((cHover = 'r-hoverTD'), (cColor = 'Button--primary'), (cSub = 'tet-btd'))
  2747. : cSel == 'tweetdeck'
  2748. ? ((cHover = 'r-hoverTD'), (cColor = 'Button--primary'), (cSub = 'tet-td'))
  2749. : cSel == 'tet-255u'
  2750. ? ((cHover = 'r-1kplyi6'), (cColor = 'r-v6khid r-cdj8wb'), (cSub = 'r-61mi1v'))
  2751. : cSel == 'tet-249u'
  2752. ? ((cHover = 'r-1ucxkr8'), (cColor = 'r-1iofnty r-jd07pc'), (cSub = 'r-daml9f'))
  2753. : cSel == 'tet-120u'
  2754. ? ((cHover = 'r-njt2r9'), (cColor = 'r-hy56xe r-11mmphe'), (cSub = 'r-xfsgu1'))
  2755. : cSel == 'tet-122u'
  2756. ? ((cHover = 'tet-122hu'), (cColor = 'r-1xl5njo r-b8m25f'), (cSub = 'r-1qkqhnw'))
  2757. : cSel == 'tet-186u'
  2758. ? ((cHover = 'r-zx61xx'), (cColor = 'r-5ctkeg r-1cqwhho'), (cSub = 'r-nw8l94'))
  2759. : ((cHover = 'r-1q3imqu'), (cColor = 'r-p1n3y5 r-1bih22f'), (cSub = 'r-13gxpu9'));
  2760. } else if (type == 'translator') {
  2761. qs('.tet-url').setAttribute('style', 'display: inline;');
  2762. return cSel == 'bingIT'
  2763. ? translatorSwap('bing')
  2764. : cSel == 'googleIT'
  2765. ? translatorSwap('google')
  2766. : cSel == 'deeplIT'
  2767. ? translatorSwap('deepl')
  2768. : cSel == 'translateIT'
  2769. ? (translatorSwap('translate'),
  2770. qs('.tet-url').setAttribute('style', 'display: none;'))
  2771. : cSel == 'yandexIT'
  2772. ? (translatorSwap('yandex'), qs('.tet-url').setAttribute('style', 'display: none;'))
  2773. : cSel == 'libre'
  2774. ? (translatorSwap('libre'), qs('.tet-url').setAttribute('style', 'display: none;'))
  2775. : cSel == 'lingva' || cSel == 'lingvaIT'
  2776. ? (translatorSwap('lingva'), qs('.tet-url').setAttribute('style', 'display: none;'))
  2777. : translatorSwap('all');
  2778. }
  2779. };
  2780. const autoTheme = (elem) => {
  2781. const getTheme = () => {
  2782. if (find.twitter) {
  2783. const bgColor = getComputedStyle(doc.body).getPropertyValue('background-color');
  2784. return bgColor.includes('rgb(255, 255, 255)')
  2785. ? 'twdef'
  2786. : bgColor.includes('rgb(21, 32, 43)')
  2787. ? 'twdim'
  2788. : bgColor.includes('rgb(0, 0, 0)')
  2789. ? 'twlo'
  2790. : bgColor;
  2791. } else if (find.tweetdeck) {
  2792. cBG = 'rgba(0, 0, 0, 0.4)';
  2793. cText = 'r-jwli3a';
  2794. cHover = 'r-hoverTD';
  2795. cColor = 'Button--primary';
  2796. cSub = 'tet-td';
  2797. cTheme = 'r-tetTD';
  2798. return 'tweetdeck';
  2799. } else if (find.twitlonger) {
  2800. cTheme = 'r-14lw9ot';
  2801. cBG = 'rgba(0, 0, 0, 0.4)';
  2802. cText = 'r-18jsvk2';
  2803. return 'twdef';
  2804. }
  2805. cBG = 'rgba(0, 0, 0, 0.4)';
  2806. cTheme = 'nitter';
  2807. cText = 'tetNTextColor';
  2808. return 'nitter';
  2809. }
  2810. const aTheme = /auto/.test(elem.value) ? getTheme() : elem.value;
  2811. TETMenuUpdate(aTheme, 'theme');
  2812. return getTheme();
  2813. };
  2814. const tetAdmin = () => {
  2815. if (domURL.search.match(/tetopen/gi)) {
  2816. dom.cl.remove(
  2817. [nav, qs('[id="tetForm"]'), qs('.tet-icon-container'), qs('.tetadvanced-icon-container')],
  2818. 'rm'
  2819. );
  2820. dom.attr(btNav, 'style', 'z-index: 10000 !important');
  2821. dom.cl.toggle(tetMenuButton, 'mini');
  2822. dom.cl.add(dom.html, 'tetFreeze');
  2823. }
  2824. };
  2825. if (!isBlank(domURL.search)) tetAdmin();
  2826. //#region Nitter/TweetDeck/Twitlonger
  2827. if (find.twitter) {
  2828. ael(win, 'popstate', () => {
  2829. dom.attr(tetMenuButton, 'style', '');
  2830.  
  2831. dom.cl.remove('.tetBackground', cTheme);
  2832. dom.cl.remove('.tetTextColor', cText);
  2833. autoTheme(selTH);
  2834. dom.cl.add('.tetBackground', cTheme);
  2835. dom.cl.add('.tetTextColor', cText);
  2836. });
  2837. dom.cl.remove('.tetst', 'rm');
  2838. const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  2839. const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
  2840. const p = document.createElementNS('http://www.w3.org/2000/svg', 'path');
  2841. dom.attr(
  2842. p,
  2843. 'd',
  2844. 'M23.643 4.937c-.835.37-1.732.62-2.675.733.962-.576 1.7-1.49 2.048-2.578-.9.534-1.897.922-2.958 1.13-.85-.904-2.06-1.47-3.4-1.47-2.572 0-4.658 2.086-4.658 4.66 0 .364.042.718.12 1.06-3.873-.195-7.304-2.05-9.602-4.868-.4.69-.63 1.49-.63 2.342 0 1.616.823 3.043 2.072 3.878-.764-.025-1.482-.234-2.11-.583v.06c0 2.257 1.605 4.14 3.737 4.568-.392.106-.803.162-1.227.162-.3 0-.593-.028-.877-.082.593 1.85 2.313 3.198 4.352 3.234-1.595 1.25-3.604 1.995-5.786 1.995-.376 0-.747-.022-1.112-.065 2.062 1.323 4.51 2.093 7.14 2.093 8.57 0 13.255-7.098 13.255-13.254 0-.2-.005-.402-.014-.602.91-.658 1.7-1.477 2.323-2.41z'
  2845. );
  2846. g.append(p);
  2847. dom.attr(svg, 'viewBox', '0 0 24 24');
  2848. dom.cl.add(svg, 'tetSub');
  2849. svg.append(g);
  2850. qs('.tetAvatarFrame').parentElement.append(svg);
  2851. } else {
  2852. if (cfg.nitterInstances.length > 0) {
  2853. dbg('Finding Nitter instance...', cfg.nitterInstances);
  2854. dom.cl.add(qs('.tetmsg'), 'rm');
  2855. for (const key of cfg.nitterInstances) {
  2856. const instance = key.url.slice(8);
  2857. if (lh === instance) {
  2858. dom.attr(btNav, 'id', 'tetNT');
  2859. query('link[rel="icon"]').then((l) => {
  2860. qs(
  2861. '.tetAvatarFrame'
  2862. ).innerHTML = `<div id="tetAvatar" style="background-image: url(${l.href}) !important;"></div>`;
  2863. });
  2864. break;
  2865. }
  2866. }
  2867. } else if (find.nitter) {
  2868. dom.cl.add(qs('.tetmsg'), 'rm');
  2869. dom.attr(btNav, 'id', 'tetNT');
  2870. query('link[rel="icon"]').then((l) => {
  2871. qs(
  2872. '.tetAvatarFrame'
  2873. ).innerHTML = `<div id="tetAvatar" style="background-image: url(${l.href}) !important;"></div>`;
  2874. });
  2875. }
  2876. if (find.twitlonger) {
  2877. dom.cl.add('.tet-ac', 'rm');
  2878. query('link[rel="shortcut icon"]').then((l) => {
  2879. qs(
  2880. '.tetAvatarFrame'
  2881. ).innerHTML = `<div id="tetAvatar" style="background-image: url(${l.href}) !important;"></div>`;
  2882. });
  2883. }
  2884. if (find.tweetdeck) {
  2885. dom.cl.add('.tet-ac', 'rm');
  2886. dom.cl.add(tetMenuButton, 'tetTD');
  2887. const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  2888. const g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
  2889. const p = document.createElementNS('http://www.w3.org/2000/svg', 'path');
  2890. dom.attr(
  2891. p,
  2892. 'd',
  2893. 'M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z'
  2894. );
  2895. g.append(p);
  2896. dom.attr(svg, 'viewBox', '0 0 24 24');
  2897. dom.cl.add(svg, 'tetSub');
  2898. svg.append(g);
  2899. qs('.tetAvatarFrame').parentElement.append(svg);
  2900.  
  2901. // query('link[rel="shortcut icon"]').then((l) => {
  2902. // qs(
  2903. // '.tetAvatarFrame'
  2904. // ).innerHTML = `<div id="tetAvatar" style="background-image: url(${l.href}) !important;"></div>`;
  2905. // });
  2906. }
  2907. if (cfg.sitetheme) {
  2908. if (find.tweetdeck) {
  2909. dom.attr(btNav, 'id', 'tetBTD');
  2910. query('body.btd-loaded').then(() => loadCSS(nitterCSS, 'nitter'));
  2911. } else {
  2912. loadCSS(nitterCSS, 'nitter');
  2913. }
  2914. }
  2915. }
  2916. //#endregion
  2917. dom.attr(nav, 'style', `background-color:${cBG}`);
  2918. TETMenuUpdate(selTR.value, 'translator');
  2919. dom.cl.remove('.tetBackground', [autoTheme(selTH), cTheme]);
  2920. dom.cl.add('.tetBackground', cTheme);
  2921. dom.cl.remove('.tetTextColor', cText);
  2922. dom.cl.add('.tetTextColor', cText);
  2923. autoColor().then((color) => {
  2924. cfg.colors = (/auto/.test(selCS.value) ? color : selCS.value).trim();
  2925. TETMenuUpdate(cfg.colors, 'colors');
  2926. dom.cl.remove('.tetDisplayColor', [color, cfg.colors]);
  2927. dom.cl.add('.tetDisplayColor', cfg.colors);
  2928. dom.cl.remove('.tetSub', cSub);
  2929. dom.cl.add('.tetSub', cSub);
  2930. cfg.colors = /auto/.test(selCS.value) ? 'auto' : selCS.value;
  2931. });
  2932. if (qs('.tet')) {
  2933. dom.cl.remove('.tet', cSub);
  2934. dom.cl.add('.tet', cSub);
  2935. }
  2936. ael(nav, 'click', (e) => {
  2937. dom.cl.add(
  2938. [
  2939. e.target,
  2940. tetConfirm,
  2941. qs('[id="tetadvanced"]'),
  2942. qs('.tet-help-container'),
  2943. qs('[id="tetForm"]'),
  2944. qs('.tet-icon-container'),
  2945. qs('.tetadvanced-icon-container')
  2946. ],
  2947. 'rm'
  2948. );
  2949. dom.cl.remove(dom.html, 'tetFreeze');
  2950. dom.attr(btNav, 'style', 'z-index: -1 !important;');
  2951. dom.attr(menuSvg, 'style', 'display: inline;');
  2952. if (!dom.cl.has(tetMenuButton, 'mobile')) {
  2953. dom.attr(tetMenuButton, 'style', '');
  2954. dom.cl.add(tetMenuButton, 'mini');
  2955. }
  2956. dom.cl.remove(e.target, 'warn');
  2957. selLG.value !== 'en' ?? dLng !== 'en'
  2958. ? demoUpdate("Hey look I'm a foreign language.")
  2959. : demoUpdate(defaultDesc);
  2960. cfg.api.google = goAPI.value;
  2961. cfg.api.deepl = dlAPI.value;
  2962. cfg.api.libre = libre[0].value;
  2963. cfg.api.yandex = qs('input[type="password"].yandex').value;
  2964. cfg.url.libre = libre[1].value;
  2965. cfg.url.lingva = lingva.value;
  2966. cfg.url[selTR.value] = qs('.tet-url').value;
  2967. cfg.colors = selCS.value;
  2968. cfg.theme = selTH.value;
  2969. save();
  2970. delay(5000).then(() => dom.attr(menuSvg, 'style', 'display: none;'));
  2971. });
  2972. mouseEvents('div#tetSelector', (e) => {
  2973. halt(e);
  2974. const sColors = cColor.split(' ');
  2975. const sSubs = cSub.split(' ');
  2976. for (const i of sColors) {
  2977. if (e.target.classList.contains(i)) {
  2978. dom.cl.remove(e.target, i);
  2979. } else {
  2980. dom.cl.add(e.target, i);
  2981. }
  2982. }
  2983. for (const i of sSubs) {
  2984. if (e.target.children[0].classList.contains(i)) {
  2985. dom.cl.remove(e.target.children[0], i);
  2986. } else {
  2987. dom.cl.add(e.target.children[0], i);
  2988. }
  2989. }
  2990. });
  2991. ael(selTH, 'change', (e) => {
  2992. dom.cl.remove('.tetDisplayColor', cfg.colors);
  2993. dom.cl.remove('.tetBackground', cTheme);
  2994. dom.cl.remove('.tetTextColor', cText);
  2995. autoTheme(e.target);
  2996. dom.cl.add('.tetDisplayColor', cfg.colors);
  2997. dom.cl.add('.tetBackground', cTheme);
  2998. dom.cl.add('.tetTextColor', cText);
  2999. });
  3000. ael(selCS, 'change', (e) => {
  3001. const cSel = e.target.value;
  3002. dom.cl.remove('.tetDisplayColor', [cfg.colors, selCS.value]);
  3003. dom.cl.remove('.tetSub', cSub);
  3004. if (qs('.tet')) dom.cl.remove('.tet', cSub);
  3005. autoColor().then((color) => {
  3006. cfg.colors = /auto/.test(cSel) ? color : cSel;
  3007. TETMenuUpdate(cfg.colors, 'colors');
  3008. dom.cl.add('.tetDisplayColor', cfg.colors);
  3009. dom.cl.add('.tetSub', cSub);
  3010. if (qs('.tet')) dom.cl.add('.tet', cSub);
  3011. cfg.colors = /auto/.test(cSel) ? 'auto' : cSel;
  3012. });
  3013. });
  3014. ael(selLG, 'change', (e) => {
  3015. cfg.lang = e.target.value;
  3016. langChange(e.target.value);
  3017. TETLanguageChange(e.target.value);
  3018. });
  3019. ael(selTR, 'change', (e) => {
  3020. const cSel = e.target.value;
  3021. cfg.translator = cSel;
  3022. if (cSel === 'deeplIT') {
  3023. qs('.tet-url').value = `https://${
  3024. selAPI.value == 'api-pro' ? 'api' : 'api-free'
  3025. }.deepl.com`;
  3026. } else {
  3027. qs('.tet-url').value = cfg.url[cSel];
  3028. }
  3029. TETMenuUpdate(cSel, 'translator');
  3030. configDisplay();
  3031. });
  3032. ael(selDS, 'change', (e) => {
  3033. cfg.display = e.target.value;
  3034. configDisplay();
  3035. });
  3036. ael(selAPI, 'change', (e) => {
  3037. cfg.api.google = goAPI.value;
  3038. cfg.api.deepl = dlAPI.value;
  3039. cfg.api.libre = libre[0].value;
  3040. cfg.api.yandex = qs('input[type="password"].yandex').value;
  3041. cfg.url.libre = libre[1].value;
  3042. cfg.url.lingva = lingva.value;
  3043. cfg.api.version = e.target.value;
  3044. if (selTR.value === 'deeplIT') {
  3045. qs('.tet-url').value = `https://${
  3046. e.target.value == 'api-pro' ? 'api' : 'api-free'
  3047. }.deepl.com`;
  3048. } else {
  3049. qs('.tet-url').value = cfg.url[selTR.value];
  3050. }
  3051. });
  3052. ael(selDI, 'change', (e) => (cfg.delay = e.target.value));
  3053. ael(qs('input#debug'), 'change', (e) => (cfg.debug = e.target.checked));
  3054. ael(qs('input#dmsg'), 'change', (e) => (cfg.dms = e.target.checked));
  3055. ael(qs('input#tetbi'), 'change', (e) => (cfg.bios = e.target.checked));
  3056. ael(qs('input#tetctw'), 'change', (e) => (cfg.tweets = e.target.checked));
  3057. ael(qs('input#sitetheme'), 'change', (e) => (cfg.sitetheme = e.target.checked));
  3058. ael(qs('[id="tetReset"]'), 'click', () => {
  3059. dom.cl.remove(tetConfirm, 'rm');
  3060. dom.cl.add(nav, 'warn');
  3061. });
  3062. ael(qs('.tetConfirmBtns.confirm'), 'click', () => {
  3063. cfg = cfgDefault;
  3064. save();
  3065. delay(250).then(() => location.reload());
  3066. });
  3067. ael(qs('.tetConfirmBtns.deny'), 'click', () => {
  3068. dom.cl.add(tetConfirm, 'rm');
  3069. dom.cl.remove(nav, 'warn');
  3070. });
  3071. ael(qs('.tet-icon-info'), 'click', () => {
  3072. dom.cl.add('[id="tetadvanced"]', 'rm');
  3073. dom.cl.toggle('.tet-help-container', 'rm');
  3074. });
  3075. ael(qs('[id="tetNI"]'), 'click', async (e) => {
  3076. const pretxt = e.target.innerHTML;
  3077. e.target.innerHTML = `[TET] ${lng[cfg.lang].l}...`;
  3078. const str = await TET.fetchURL(nitterURL, 'GET', 'text');
  3079. const reg =
  3080. /\[[\w.]+\]\((https?:\/\/.+)\)\s+\|\s:white_check_mark:\s\|\s:white_check_mark:\s\|/g;
  3081. const lines = str
  3082. .split('\n')
  3083. .filter((line) =>
  3084. /\[[\w.]+\]\(https?:\/\/.+\)\s+\|\s:white_check_mark:\s\|\s:white_check_mark:\s\|/g.test(
  3085. line
  3086. )
  3087. )
  3088. .map((line) => {
  3089. const raw = reg.exec(line);
  3090. if (isEmpty(raw)) {
  3091. return '';
  3092. }
  3093. return raw[1];
  3094. })
  3095. .filter((line) => !isEmpty(line));
  3096. console.groupCollapsed(
  3097. '[%cTET%c] %cINF',
  3098. 'color: rgb(29, 155, 240);',
  3099. '',
  3100. 'color: rgb(255, 108, 96);',
  3101. 'Nitter Instances'
  3102. );
  3103. for (const line of lines) {
  3104. log(`// @match ${line}`);
  3105. }
  3106. console.groupEnd();
  3107. e.target.innerHTML = 'Open browsers dev tools to view list';
  3108. delay(5000).then(() => {
  3109. e.target.innerHTML = pretxt;
  3110. });
  3111. });
  3112. TETLanguageChange();
  3113. delay(5000).then(() => dom.attr(menuSvg, 'style', 'display: none;'));
  3114. info('Menu injection complete');
  3115. } catch (ex) {
  3116. err(ex);
  3117. }
  3118. }
  3119. //#region Initialize Userscript
  3120. const configSetup = () => {
  3121. try {
  3122. // Remove legacy config storage
  3123. if (isGM) {
  3124. if (!isNull(localStorage.getItem('cfg'))) {
  3125. localStorage.removeItem('cfg');
  3126. }
  3127. if (!isNull(localStorage.getItem('TETConfig'))) {
  3128. localStorage.removeItem('TETConfig');
  3129. }
  3130. }
  3131.  
  3132. cfg = TET.getValue('Config', cfgDefault);
  3133. for (const key in cfgDefault) {
  3134. if (!hasOwn(cfg, key)) {
  3135. cfg[key] = cfgDefault[key];
  3136. } else if (key === 'api') {
  3137. for (const key2 in cfgDefault[key]) {
  3138. if (!hasOwn(cfg[key], key2)) {
  3139. cfg[key][key2] = cfgDefault[key][key2];
  3140. }
  3141. }
  3142. } else if (key === 'url') {
  3143. for (const key2 in cfgDefault[key]) {
  3144. if (!hasOwn(cfg[key], key2)) {
  3145. cfg[key][key2] = cfgDefault[key][key2];
  3146. }
  3147. }
  3148. }
  3149. }
  3150. if (/tetdebug/gi.test(domURL.search)) {
  3151. cfg.debug = true;
  3152. save();
  3153. }
  3154. if (/tetrestore/gi.test(domURL.search)) {
  3155. cfg = cfgDefault;
  3156. save();
  3157. }
  3158.  
  3159. // info('Presetup complete + config loaded');
  3160. log('Config:', cfg);
  3161. lngFN();
  3162. langChange();
  3163. info('Starting Menu injection');
  3164. if (isMobile) {
  3165. tetMenuButton.classList.add('mobile');
  3166. btNav.classList.add('mobile');
  3167. }
  3168. doc.body.append(btNav, tetMenuButton);
  3169. Menu();
  3170. info('Starting content script injection');
  3171. site.inject();
  3172. } catch (ex) {
  3173. err(ex);
  3174. }
  3175. };
  3176. const onDomReady = () => {
  3177. if (isNull(dom.body)) {
  3178. dom.root = document.querySelector(':root');
  3179. dom.html = document.documentElement;
  3180. dom.head = document.head;
  3181. dom.body = document.body;
  3182. dom.search = document || dom.root || dom.html || dom.head || dom.body;
  3183. }
  3184. loadCSS(tetCSS, 'core');
  3185. configSetup();
  3186. };
  3187. //#endregion
  3188.  
  3189. //#region Console Logs
  3190. function dbg(...msg) {
  3191. if (!cfg.debug) return;
  3192. console.debug(
  3193. '[%cTET%c] %cDBG',
  3194. 'color: rgb(29, 155, 240);',
  3195. '',
  3196. 'color: rgb(255, 212, 0);',
  3197. ...msg
  3198. );
  3199. }
  3200. /** Error handling for UserScript */
  3201. function err(...msg) {
  3202. console.error(
  3203. '[%cTET%c] %cERROR',
  3204. 'color: rgb(29, 155, 240);',
  3205. '',
  3206. 'color: rgb(249, 24, 128);',
  3207. ...msg
  3208. );
  3209. }
  3210. /** Information handling for userscript */
  3211. function info(...msg) {
  3212. if (!cfg.debug) return;
  3213. console.info(
  3214. '[%cTET%c] %cINF',
  3215. 'color: rgb(29, 155, 240);',
  3216. '',
  3217. 'color: rgb(0, 186, 124);',
  3218. ...msg
  3219. );
  3220. }
  3221. function log(...msg) {
  3222. if (!cfg.debug) return;
  3223. console.log(
  3224. '[%cTET%c] %cLOG',
  3225. 'color: rgb(29, 155, 240);',
  3226. '',
  3227. 'color: rgb(255, 212, 0);',
  3228. ...msg
  3229. );
  3230. }
  3231. //#endregion
  3232.  
  3233. try {
  3234. if (typeof userjs === 'object' && userjs.UserJS && topDOM) {
  3235. if (find.twitter) {
  3236. if (location.pathname === '/' && find.logout) throw new Error('Must be login, canceling...');
  3237. if (find.remover) throw new Error('On blacklisted page, canceling...');
  3238. }
  3239. if (find.tweetdeck && find.logout) throw new Error('Must be login, canceling...');
  3240. tetForm.append(tetHeader, tetMain);
  3241. tetMenuButton.append(menuSvg, menuSpan);
  3242. btNav.append(nav, tetConfirm, tetForm, tetAdv, tetAdvC, tetAdvI);
  3243. iconData.fn();
  3244.  
  3245. const readyState = doc.readyState;
  3246. if (readyState === 'interactive' || readyState === 'complete') {
  3247. onDomReady();
  3248. } else {
  3249. ael(doc, 'DOMContentLoaded', onDomReady, { once: true });
  3250. }
  3251. }
  3252. } catch (ex) {
  3253. err(ex);
  3254. }
  3255.  
  3256. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址