ChatGPT Reîmprospătare Automată ↻

*ÎN SIGURANȚĂ* eliminați reinițializările de chat de 10 minute, erorile constante de rețea și verificările Cloudflare din ChatGPT.

Instalează acest script?
Script sugerat de autor

Poate îți va plăcea șiChatGPT Mod ecran lat 🖥️.

Instalează acest script
// ==UserScript==
// @name                ChatGPT Auto Refresh ↻
// @name:af             ChatGPT Auto Verfris ↻
// @name:am             የአቃጥል GPT ራስሀሽ ↻
// @name:ar             ChatGPT تحديث تلقائي ↻
// @name:az             ChatGPT Avtomatik Yenilə ↻
// @name:be             Аўтаматычнае абнаўленне ChatGPT ↻
// @name:bem            ChatGPT Auto Sintalula ↻
// @name:bg             Автоматично опресняване на ChatGPT ↻
// @name:bn             ChatGPT স্বয়ংক্রিয় রিফ্রেশ ↻
// @name:bo             ChatGPT རེའུ་མིན་པར་སྣོད་དང་ ↻
// @name:bs             ChatGPT Automatsko Osvježavanje ↻
// @name:ca             ChatGPT Actualització Automàtica ↻
// @name:ckb            ChatGPT نوێکردنهوهی خۆکار ↻
// @name:cs             ChatGPT Automatické obnovení ↻
// @name:cy             ChatGPT Adnewyddu Auto ↻
// @name:da             ChatGPT Automatisk Opdatering ↻
// @name:de             ChatGPT Automatisches Aktualisieren ↻
// @name:dv             ChatGPT އައްޗައިސް އަސްޓްރީ ↻
// @name:dz             ChatGPT རེའུ་མིན་པར་སྣོད་དང་ ↻
// @name:el             ChatGPT Αυτόματη Ανανέωση ↻
// @name:eo             ChatGPT Aŭtomata Refreŝigo ↻
// @name:es             ChatGPT Actualización Automática ↻
// @name:et             ChatGPT Automaatne Värskendamine ↻
// @name:eu             ChatGPT Automatikoki Freskatu ↻
// @name:fa             به روز رسانی خودکار ChatGPT ↻
// @name:fi             ChatGPT Automaattinen Päivitys ↻
// @name:fo             ChatGPT Auto Uppdatering ↻
// @name:fr             ChatGPT Actualisation Automatique ↻
// @name:fr-CA          ChatGPT Actualisation Automatique ↻
// @name:gd             ChatGPT Ath-bhualadh Aonaranach ↻
// @name:gl             ChatGPT Actualización Automática ↻
// @name:gu             ChatGPT સ્વચાલિત રિફ્રેશ ↻
// @name:haw            Hoʻonoho Hōʻike Auto ChatGPT ↻
// @name:he             רענון אוטומטי של ChatGPT ↻
// @name:hi             ChatGPT स्वचालित रीफ़्रेश ↻
// @name:hr             ChatGPT Automatsko Osvježavanje ↻
// @name:ht             ChatGPT Rafrechi Otomatik ↻
// @name:hu             ChatGPT Automatikus Frissítés ↻
// @name:hy             Ինքնաշխատ Թարմացում ChatGPT ↻
// @name:id             ChatGPT Pembaruan Otomatis ↻
// @name:is             ChatGPT Sjálfvirk Endurnýjun ↻
// @name:it             ChatGPT Aggiornamento Automatico ↻
// @name:ja             ChatGPT 自動更新 ↻
// @name:jv             Pembaruan Otomatis ChatGPT ↻
// @name:ka             ChatGPT ავტომატური განახლება ↻
// @name:kab            ChatGPT Akarẓim Aɣelnaw ↻
// @name:kk             ChatGPT Автоматты Жаңарту ↻
// @name:km             ChatGPT បន្ទាប់ពីបច្ចុប្បន្នភាព ↻
// @name:kn             ChatGPT ಸ್ವಯಂಚಾಲಿತ ರಿಫ್ರೆಶ್ ↻
// @name:ko             ChatGPT 자동 새로 고침 ↻
// @name:ky             ChatGPT Автоматтык Тазартуу ↻
// @name:la             ChatGPT Automatica Refectio ↻
// @name:lb             ChatGPT Automatescht Aktualiséieren ↻
// @name:lo             ChatGPT ປັບປຸງອັດຕະໂນມັດອັດຕະໂນມັດ ChatGPT ↻
// @name:lt             ChatGPT Automatinis Atnaujinimas ↻
// @name:lv             ChatGPT Automātiska Atsvaidzināšana ↻
// @name:mg             Fanavaozana Ankehitriny i ChatGPT ↻
// @name:mi             ChatGPT Whakahōu Aunoa ↻
// @name:mk             Автоматско освежување ChatGPT ↻
// @name:ml             ChatGPT ഓട്ടോ അപ്ഡേറ്റ് ↻
// @name:mn             ChatGPT Автоматаар Шинэчлэх ↻
// @name:ms             Penyegaran Auto ChatGPT ↻
// @name:mt             ChatGPT Rifreżġjar Awtomatiku ↻
// @name:my             ChatGPT အလိုအလျောက်ထပ်ဖြန် ↻
// @name:ne             ChatGPT आफ्नैजस्तै ताजा गर्नुहोस् ↻
// @name:nl             ChatGPT Automatische Vernieuwing ↻
// @name:no             ChatGPT Automatisk Oppdatering ↻
// @name:pa             ChatGPT ਆਟੋ ਰਿਫਰੈਸ਼ ↻
// @name:pap            ChatGPT Refreskamentu Automatico ↻
// @name:pl             ChatGPT Automatyczne Odświeżanie ↻
// @name:ps             د ChatGPT زما تازه کول ↻
// @name:pt             ChatGPT Atualização Automática ↻
// @name:pt-BR          ChatGPT Atualização Automática ↻
// @name:rn             ChatGPT Gushira Ubushyuhe ↻
// @name:ro             ChatGPT Reîmprospătare Automată ↻
// @name:ru             Автообновление ChatGPT ↻
// @name:sg             ChatGPT Rafraîchissement Auto ↻
// @name:si             ChatGPT ස්වයංක්රීය නැවතුම් ↻
// @name:sk             ChatGPT Automatické Obnovenie ↻
// @name:sl             ChatGPT Samodejna Osvežitev ↻
// @name:sm             ChatGPT Toeaina Auto Taulagaina ↻
// @name:sn             ChatGPT Rurefu Rakaita Zvakanaka ↻
// @name:so             ChatGPT Dib-u-helayna Xafiiska ↻
// @name:sr             ChatGPT Аутоматско Освежавање ↻
// @name:sv             ChatGPT Automatisk Uppdatering ↻
// @name:sw             ChatGPT Kupakia Moja kwa moja ↻
// @name:ta             ChatGPT தானியங்கி புதுப்பிப்பு ↻
// @name:te             ChatGPT ఆటో రిఫ్రెష్ ↻
// @name:tg             ChatGPT Таҷдиди худкори ChatGPT ↻
// @name:th             ChatGPT รีเฟรชอัตโนมัติ ↻
// @name:ti             ChatGPT ኣካውንታት እውነት ዓይኒ ↻
// @name:tk             ChatGPT Awtomatik Täzele ↻
// @name:tn             ChatGPT Tlhokomelo ya Moafrika ↻
// @name:to             ChatGPT Fakahā ʻihaotaha ↻
// @name:tpi            ChatGPT Awto Rifrehs ↻
// @name:tr             ChatGPT Otomatik Yenileme ↻
// @name:uk             Автоматичне Оновлення ChatGPT ↻
// @name:ur             خودکار تازہ کاری ChatGPT ↻
// @name:uz             ChatGPT Avtomatik Yangilash ↻
// @name:vi             ChatGPT Tự động Cập nhật ↻
// @name:xh             ChatGPT Ukunovusa Okuvela ↻
// @name:yi             ChatGPT אַטאַ אַקטואַליזירן ↻
// @name:zh             ChatGPT 自动刷新 ↻
// @name:zh-CN          ChatGPT 自动刷新 ↻
// @name:zh-HK          ChatGPT 自動刷新 ↻
// @name:zh-SG          ChatGPT 自动刷新 ↻
// @name:zh-TW          ChatGPT 自動刷新 ↻
// @name:zu             ChatGPT Ukusasaza Ngokuzenzakalelayo ↻
// @description         *SAFELY* eliminate 10-minute chat resets + constant network errors + Cloudflare checks from ChatGPT
// @description:af      *VEILIG* elimineer 10-minuut klets herstelling + aanhoudende netwerkfoute + Cloudflare-kontroles uit ChatGPT.
// @description:am      *ባርማ* ከChatGPT ውስጥ የ10 ደቂቃ መካከለኛ ገጽታ መድረስን፣ *በጭራቅ የሚከሰቱ አውታረ መረብ ስህተቶችን*እና ክላይንት ፓስያንት ምርመራዎችን ይወግዱ።
// @description:ar      *بأمان* احذف إعادة تعيين الدردشة لمدة 10 دقائق + *أخطاء الشبكة المستمرة* + فحوصات Cloudflare من ChatGPT.
// @description:az      *TƏHLÜKƏSİZ* 10 dəqiqəlik söhbət sıfırlamalarını, *davamlı şəbəkə xətalarını* və Cloudflare yoxlamalarını ChatGPT'dən çıxarın.
// @description:be      *БЯСПЕКА* выдаліце 10-хвілінныя перазагрузкі чата, *пастаянныя сеткавыя памылкі* і праверкі Cloudflare са ChatGPT.
// @description:bem     *UMULI* fyumbafye amafuula ya menso 10 + *aya makota yambi konse konse* nefimfi ifyakwa pantu + ifiletelwe ifyakwa Cloudflare ukufuma mu ChatGPT.
// @description:bg      *БЕЗОПАСНО* премахнете 10-минутни нулирания на чата, *постоянни мрежови грешки* и проверки на Cloudflare от ChatGPT.
// @description:bn      ChatGPT-এর থেকে ১০ মিনিটের চ্যাট রিসেট, *চিরস্থায়ী নেটওয়ার্ক ত্রুটি* এবং ক্লাউডফ্লেয়ার যাচাই-বাছাই সরিয়ে দিন *নিরাপদে*।
// @description:bo      *རྒྱབ་བཞིན་པའི་* ཟའ་གྲགས་10 སྐར་མ་གཞན་འགྱུར་འདོན་སྐབས་མེད་པ། *ངོས་འཛིན་ཡོད་པ་* Cloudflare་དྲི་ཞིམ་བཟོ་བའི་ཕྱིར་ ChatGPT་ནས་ཕྱི་ལོག །
// @description:bs      *SIGURNO* uklonite 10-minutna resetovanja četa, *konstantne greške mreže* i Cloudflare provjere iz ChatGPT.
// @description:ca      *SEGUR* elimineu els reajustaments de xat de 10 minuts + *errors de xarxa constants* i comprovacions de Cloudflare de ChatGPT.
// @description:ceb     *LUWAS* hika ang mga pag-reset sa pag-chat sa 10 ka minuto + *walay hunong nga mga sayop sa network* + mga pagsusi sa Cloudflare gikan sa ChatGPT.
// @description:ckb     *بەبێ پەیمانە* پشوودانی سنووری چاتی ١٠ خولەکی، *کێشەی شبکەیی ڕاستەوخۆ* و بڵاودەکردنەوەکانی Cloudflare لە ChatGPT دابڕۆ.
// @description:cs      *BEZPEČNĚ* odstraňte 10minutová obnovení chatu, *trvalé síťové chyby* a kontroly Cloudflare z ChatGPT.
// @description:cy      *YN DIOGEL* cael gwared â 10 munud ailosod sgwrs + *gwallau rhwydwaith parhaus* + gwiriadau Cloudflare o ChatGPT.
// @description:da      *SIKKERT* fjern 10-minutters chat-nulstillinger + *konstante netværksfejl* og Cloudflare-tjek fra ChatGPT.
// @description:de      *SICHER* entfernen Sie 10-Minuten-Chat-Zurücksetzungen + *kontinuierliche Netzwerkfehler* und Cloudflare-Überprüfungen aus ChatGPT.
// @description:dv      ChatGPT އިން ދޮގު ނަތީޖާ ގެ ގޮތުން ދިމާވާ މިނެޓުގެ އަޑުގަދަވުމުގެ ވަގުތު އަލުން ސެޓްކުރުން 10 ގެ އަދަދު އަނބުރާ ގެނެސްދިނުމާއެކު + *ތެރޭގައި ހުރި ނެޓްވޯކް މައްސަލަތަކާއި* ކްލައުޑްފްލެއަރގެ ޗެކްތައް ދޫކުރުން ބޭނުންވެއެވެ.
// @description:dz      *དགའ་བསྐྱིད་བཞུགས་བརྡ* མི་ཉུང་སྐར་མ་གི་ཟའ་གྲགས་རིམ་ལེབ་འགྱུར་བསྡད་མེད་པ། *ངོས་འཛིན་ཡོད་པ་* Cloudflare་བཤད་པ་བཟོ་བའི་ཕྱིར་ ChatGPT ནས་ཕྱི་ལོག །
// @description:el      *ΜΕ ΑΣΦΑΛΕΙΑ* εξαλείψτε τις επαναφορές συνομιλίας 10 λεπτών + *συνεχείς σφάλματα δικτύου* και ελέγχους Cloudflare από το ChatGPT.
// @description:eo      *SEKURE* forigu 10-minutajn babiletajajn rekomencigojn + *konstantajn reto-erarojn* kaj Cloudflare-kontrolojn de ChatGPT.
// @description:es      *SEGURO* elimine los reinicios de chat de 10 minutos + *errores de red constantes* y verificaciones de Cloudflare de ChatGPT.
// @description:et      *TURVALISELT* eemalda ChatGPT-st 10-minutilised vestluse lähtestamised + *püsivad võrguvead* ja Cloudflare'i kontrollid.
// @description:eu      *SEGUROA* kendu ChatGPT-tik 10 minutuko txat berrabiarazteak + *sareko akats etengabeak* eta Cloudflare egiaztapenak.
// @description:fa      *به طور ایمن* بازنشانی چت 10 دقیقه ای + *خطاهای مداوم شبکه* و بررسی های Cloudflare را از ChatGPT حذف کنید.
// @description:fi      *TURVALLISESTI* poista ChatGPT:stä 10 minuutin keskustelun nollaukset + *jatkuvat verkkovirheet* ja Cloudflare-tarkistukset.
// @description:fo      *TRYGT* strika 10 minuttir endursetan av samrøðum + *staðug netbrek* og Cloudflare-royndir frá ChatGPT.
// @description:fr      *EN TOUTE SÉCURITÉ* éliminez les réinitialisations de chat de 10 minutes + *les erreurs réseau constantes* et les vérifications Cloudflare de ChatGPT.
// @description:fr-CA   *EN TOUTE SÉCURITÉ* éliminez les réinitialisations de chat de 10 minutes + *les erreurs réseau constantes* et les vérifications Cloudflare de ChatGPT.
// @description:gd      *GU SÀBHALTE* thoir air falbh ath-shuidheachadh còmhraidh 10 mionaid + *mearachdan lìonraidh leantainneach* agus sgrùdaidhean Cloudflare à ChatGPT.
// @description:gl      *SEGURAMENTE* elimine os reinicios de conversa de 10 minutos + *erros de rede constantes* e verificacións de Cloudflare de ChatGPT.
// @description:gu      ChatGPT માંથી ૧૦ મિનિટના ચૅટ રીસેટ, *સ્થાયી નેટવર્ક ભૂલો* અને ક્લાઉડફ્લેર તપાસો *સુરક્ષિતપણે* દૂર કરો.
// @description:haw     *KUHIAO* wehe i ka hoʻomaʻemaʻe ʻana i nā hoʻouka hou ʻana o ka walaʻau no 10 minuke + mau ʻano hihia mau loa o ka nahenahe + nā hoʻokolokolo o Cloudflare, mai ke keʻena nei o ChatGPT.
// @description:he      *בטחון* הסירו איפוסי צ'אט של 10 דקות + *שגיאות רשת קבועות* ובדיקות קלאודפלייר מ-ChatGPT.
// @description:hi      ChatGPT से 10 मिनट के चैट रीसेट, *स्थायी नेटवर्क त्रुटियाँ* और क्लाउडफ़्लेयर जाँच को *सुरक्षित रूप से* हटाएं।
// @description:hr      *SIGURNO* uklonite 10-minutna resetiranja čavrljanja, *stalne mrežne pogreške* i Cloudflare provjere iz ChatGPT-a.
// @description:ht      *AN SEKIRITE,* elimine resè chat 10 minit yo, *erè sou rezo ki konstan* epitou tchèk Cloudflare nan ChatGPT.
// @description:hu      *BIZTONSÁGOSAN* távolítsa el a 10 perces csevegések visszaállításait, a *folyamatos hálózati hibákat* és a Cloudflare ellenőrzéseket a ChatGPT-ből.
// @description:hy      *ԱՆՎՏԱՆԳՈՒԹՅՈՒՆ ՀԱՍԿԱՑՈՒՄԸ`* հեռացնել 10 րոպեանոց չատի վերագործարկումները, *մշտական ցանցային սխալները* եւ Cloudflare ստուգումները ChatGPT-ից:
// @description:id      *AMAN* menghapus batas obrolan 10 menit, *kesalahan jaringan yang konstan*, dan pemeriksaan Cloudflare dari ChatGPT.
// @description:is      *ÖRUGGLEGA* fjarlægðu endurstillingu spjalls í 10 mínútur, *sífelldum netvillum* og Cloudflare prófanir úr ChatGPT.
// @description:it      *IN SICUREZZA* eliminare i reset della chat di 10 minuti, *gli errori di rete costanti* e i controlli Cloudflare da ChatGPT.
// @description:ja      ChatGPTから10分のチャットのリセット、*定常的なネットワークのエラー*、Cloudflareのチェックを*安全に*削除してください。
// @description:jv      *AMAN* busak wates obrolan 10 menit, *kesalahan jaringan sing konstan*, lan pemeriksaan Cloudflare saka ChatGPT.
// @description:ka      *უსაფრთხოდ* წაშალეთ 10 წუთიანი ჩეთის დაბრუნებები, *მუდმივი ქსელური შეცდომები* და Cloudflare შემოწმებები ChatGPT-დან.
// @description:kk      *ҚАУІПСІЗ* ChatGPT дан 10 минуттық чат қайта орнатуларды, *тұрақты желі қателерін* және Cloudflare тексерістерін жойыңыз.
// @description:km      *ដោយសុវត្ថិភាព* លុបការកំណត់ឡើងវិញនៃការជជែក 10 នាទី, *កំហុសបណ្តាញជាក់លាក់* និងការពិនិត្យរបស់ Cloudflare ចេញពី ChatGPT។
// @description:kn      ChatGPT ನಿಂದ 10 ನಿಮಿಷಗಳ ಚಾಟ್ ಮರುಹೊಂದಿಕೆಗಳು, *ನಿರಂತರ ಜಾಲ ದೋಷಗಳು* ಮತ್ತು ಕ್ಲೌಡ್‍ಫ್ಲೇರ್ ಪರಿಶೀಲನೆಗಳನ್ನು *ಸುರಕ್ಷಿತವಾಗಿ* ತೆಗೆದುಹಾಕಿ.
// @description:ko      ChatGPT에서 10분 채팅 재설정, *지속적인 네트워크 오류*, 클라우드플레어 검사를 *안전하게* 제거하십시오.
// @description:ku      *بە ئاسایی* ڕیسێتی چاتی ١٠ خولەکی، *کێشەی شبکەیی ڕاستەوخۆ* و دیاریکردنی کلاڵدفلەر لە ChatGPT دابڕۆ.
// @description:ky      *КООПСУЗДУК МЕНЕН* ChatGPT дан 10 мүнөттүк чаттын кайра жөндөөсүн, *туруктуу тармак каталарын* жана Cloudflare текшерүүлөрүн алып салыңыз.
// @description:la      *TUTO* dele 10 minutarum colloquii reconsitutiones, *crebros errores retis* et inspectiones Cloudflare ab ChatGPT.
// @description:lb      *SÉCHER* Huel 10 Minutte Chat-Limitt-Reschtellungen, *bestänneg Netzwierker-Feeler* an d'Cloudflare-Iwwerpréifunge fort vu ChatGPT.
// @description:lo      *ດ້ວຍຄວາມປອດໄພ* ລຶບການຕັ້ງຄ່າໃຫມ່ການແຊັດ 10 ນາທീ, *ຂໍ້ຜິດພາດເຄືອຂ່າຍປະຈໍາ* ແລະ ການກວດສອບຂອງ Cloudflare ອອກຈາກ ChatGPT.
// @description:lt      *SAUGIAI* pašalinkite 10 minučių pokalbių atstatymus, *nuolatinius tinklo trikdžius* ir Cloudflare patikras iš ChatGPT.
// @description:lv      *DROŠI* noņemiet 10 minūšu čata atiestatījumus, *pastāvīgās tīkla kļūdas* un Cloudflare pārbaudes no ChatGPT.
// @description:mg      *MIANDRY ARA-KIRA* esory ny fandrombahana ny fisalasana 10 minitra, *ny diso amin'ny tambajotra mandritra* ary ny fanamarinana amin'ny Cloudflare avy amin'ny ChatGPT.
// @description:mi      *KA TŪTURU* whakakorehia ngā whakatikatika kōrero 10 meneti, *hapa whatunga rāroto e tohu tonu ana + ngā aroturuki Cloudflare i ChatGPT.
// @description:mk      *БЕЗБЕДНО* отстранете ги 10-минутните повторни вклучувања на разговорот, *константни мрежни грешки* и проверките на Cloudflare од ChatGPT.
// @description:ml      ChatGPT നിന്ന് 10 മിനിറ്റ് ചാറ്റ് പുനഃസജ്ജമാക്കലുകൾ, *തുടർച്ചയായ നെറ്റ്‌വർക്ക് പിശകുകൾ*, ക്ലൗഡ്ഫ്ലെയർ പരിശോധനകൾ *സുരക്ഷിതമായി* നീക്കം ചെയ്യുക.
// @description:mn      ChatGPT-с *АЮУЛГҮЙ БОЛОВЧ* 10 минутын чат дахин тохирохыг, *үргэлжилсэн сүлжээний алдаа* болон Cloudflare-ийн шалгалтуудыг хасна уу.
// @description:mr      ChatGPT मधून *सुरक्षितपणे* १० मिनिटांची गप्पागोष्टी पुन्हा सेट करणे, *सातत्याने नेटवर्क त्रुटी* आणि क्लाउडफ्लेअर तपासणी काढून टाका.
// @description:ms      *DENGAN SELAMAT* singkirkan had sembang semula 10 minit, *kesalahan rangkaian yang kerap*, dan semakan Cloudflare daripada ChatGPT.
// @description:mt      *B'SIGURTÀ* neħħi l-limiti ta' risettjar tal-kliem ta' 10 minuta, *żbalji fil-network persistenti*, u kontrolli ta' Cloudflare minn ġewwa ChatGPT.
// @description:my      ChatGPT မှ *လုံးဝ လုံခြုံစွာ* ၁၀ မိနစ် စကားပြောရန် ပြန်လည် သတ်မှတ်ချက်များ၊ *မြောက်မြောက် ကွန်ရက် ပြၚ အမှား* များနှင့် Cloudflare စစ်ဆေးမှုများကို ဖယ်ရှားပါ။
// @description:ne      ChatGPT बाट *सुरक्षितरूपमा* १० मिनेटको च्याट पुनःसेट, *निरन्तर नेटवर्क त्रुटि* र क्लाउडफ्लेयर जाँच हटाउनुहोस्।
// @description:nl      *VEILIG* verwijder 10-minuten chat resets, *constante netwerkfouten* en Cloudflare-controles van ChatGPT.
// @description:no      *TRYGT* fjern 10-minutters chat-tilbakestillinger, *konstante nettverksfeil* og Cloudflare-sjekker fra ChatGPT.
// @description:ny      *NDIWOYIMILIRENI* tsikani kupindulitsanso kogawana kwamizuzu khumi + *zolakwika zambirimbiri pa intaneti* ndi zolingalira za Cloudflare kuchokera ku ChatGPT.
// @description:pa      ChatGPT ਤੋਂ *ਸੁਰੱਖਿਅਤ ਢੰਗ ਨਾਲ* 10 ਮਿੰਟ ਦੀਆਂ ਚੈਟ ਰੀ-ਸੈਟਾਂ, *ਲਗਾਤਾਰ ਨੈੱਟਵਰਕ ਗਲਤੀਆਂ* ਅਤੇ ਕਲਾਉਡਫਲੇਅਰ ਜਾਂਚਾਂ ਹਟਾਓ।
// @description:pap     *SEGURO* eliminá rekashonan di chat di 10 minüt, *faltanan di red kontínuo* i kontròlnan di Cloudflare for di ChatGPT.
// @description:pl      *BEZPIECZNIE* usuń 10-minutowe resetowanie czatu, *stałe błędy sieciowe* i kontrole Cloudflare z ChatGPT.
// @description:ps      له ChatGPT څخه *په امنه* توګه د ۱۰ دقیقو چت بیا ټاکل کول، *دوامداره شبکي غلطي* او Cloudflare بررسۍ لرې کړئ.
// @description:pt      *COM SEGURANÇA* elimine resets de chat de 10 minutos, *erros de rede constantes* e verificações do Cloudflare do ChatGPT.
// @description:pt-BR   *COM SEGURANÇA* elimine as redefinições de chat de 10 minutos, *erros frequentes de rede* e checagens do do Cloudflare do ChatGPT.
// @description:rn      *MU BUNYAMINE* gukuraho ingaruka zo gusegurira imyumvire icumi, amakosa akomeye yo mu murongo w'ubucuruzi no kugenzura amabuye ya Cloudflare ukufuma mu ChatGPT.
// @description:ro      *ÎN SIGURANȚĂ* eliminați reinițializările de chat de 10 minute, erorile constante de rețea și verificările Cloudflare din ChatGPT.
// @description:ru      *БЕЗОПАСНО* устраните 10-минутные сбросы чата, постоянные сетевые ошибки и проверки Cloudflare из ChatGPT.
// @description:rw      *MU BUNYAMINE* ikuraho iseswa ry’iminota 10, amakosa akomeje kw’itumanaho mu rwego rw’ibikorwaremezo n’igenzura rya Cloudflare mu ChatGPT.
// @description:sg      *NI ÌTỌJU* ṣe ìyọ̀sọ́wọ́jú ọrọ̀'lọ̀wọ́ mẹ́rinlelogun, awọn ṣiṣe ilana aláilóbájẹ́ + awọn adánilọ́jọ́ Cloudflare láti inú ChatGPT.
// @description:si      *ආරක්ෂිතව* 10 මිනිත්තු චැට් යළි සැකසීම්, ස්ථිර ජාල දෝෂ සහ Cloudflare පරීක්ෂණ ChatGPT වෙතින් ඉවත් කරන්න.
// @description:sk      *BEZPEČNE* odstráňte 10-minútové opätovné nastavenia četu, neustále sieťové chyby a kontroly Cloudflare z ChatGPT.
// @description:sl      *VARNO* odstranite 10-minutna ponastavljanja klepetov, nenehne napake v omrežju in preverjanja cloudfare iz ChatGPT.
// @description:sm      *MA FA'AMANUIAGA* ia eseese fa'amalosi e tusi tulaga tautua ta'aloga e 10 minute + tala esemanuuga + nisi'i Cloudflare mai ChatGPT.
// @description:sn      *KANA KUTAMBA WAKAWANDA* dzimba kupindura zvakare maonero echirongwa che10min + zvivi zvisingakoni nekupera + ruzivo rweCloudflare uye kubvisa zviri muChatGPT.
// @description:so      *SI AMMAAN* ka saar 10 daqiiqo dib u habayn xidhiidh + xatooyin xaaladaha ah + baaritaan Cloudflare ka mid ah ChatGPT.
// @description:sr      *BEZBEDNO* eliminišite 10-minutna resetovanja ćaska, konstantne mrežne greške i Cloudflare provere iz ChatGPT-a.
// @description:sv      *SÄKERT* eliminera 10-minuters återställningar av chattar, konstanta nätverksfel och Cloudflare-kontroller från ChatGPT.
// @description:sw      *KWA USALAMA* ondoa marejesho ya mazungumzo ya dakika 10, hitilafu endelevu za mtandao na ukaguzi wa Cloudflare kutoka ChatGPT.
// @description:ta      *பாதுகாப்பாக* 10 நிமிட உரையாடல் மறுதொடக்கங்கள், தொடர்ச்சியான வலையமைப்பு பிழைகள், மேகக்கம்பெனி சோதனைகளை ChatGPT இருந்து அகற்றுங்கள்.
// @description:te      *సురక్షితంగా* 10 నిమిషాల చాట్ రీసెట్లు, నిరంతర నెట్వర్క్ లోపాలు, క్లౌడ్ఫ్లేర్ తనిఖీలను ChatGPT నుండి తీసివేయండి.
// @description:tg      *БО ҲИФЗИ АМНИЯТ* 10-дақиқагии бозсозии чат, хатогиҳои доимии шабака ва санҷиши Cloudflare-ро аз ChatGPT ҳазф намоед.
// @description:th      *อย่างปลอดภัย* กําจัดการรีเซ็ตแชท 10 นาที ข้อผิดพลาดของเครือข่ายตลอดเวลา และการตรวจสอบของ Cloudflare ออกจาก ChatGPT
// @description:ti      *ብናይ ደሞዝ* 10 ደቂቕ ድምጺ ናይ መጀመርታ ምቕራብን, ናይ ሕፅይቲ ምእታይን, ናይ Cloudflare ፍልጠትን ካብ ChatGPT ክወግዙ::
// @description:tk      *HOWPSUZLYK BILEN* 10 minutly çat ýeniden başlatmalaryny, durnukly internet ýalňyşlaryny we Cloudflare barlagyny ChatGPT-den aýyrыň.
// @description:tn      *KA POLAOKEHI* e ntšha thekiso ya ho qala hape ya metsotso e 10 + diphoso tsa neteweke tse kileng + dipatlisiso tsa Cloudflare ho tswa ho ChatGPT.
// @description:to      *'I HE FA'A'EA'EA'ANGA* 'e aveese 'a e ngaahi fili 'o e fetu'utaki chatí ki he meniti 'e 10 + hili pea 'o e ngaahi me'angaue'aki 'a e néétuiaki + ngaahi sivi 'o e Cloudflare mei he ChatGPT.
// @description:tr      *GÜVENLİ BİR ŞEKİLDE* 10 dakikalık sohbet sıfırlamalarını, sürekli ağ hatalarını ve Cloudflare kontrollerini ChatGPT'ten kaldırın.
// @description:uk      *БЕЗПЕЧНО* усуньте 10-хвилинні скинення чату, постійні мережеві помилки та перевірки Cloudflare з ChatGPT.
// @description:ur      *محفوظ* ChatGPT سے 10 منٹ کی چیٹ ری سیٹس، مستقل نیٹ ورک نقص اور کلاؤڈ فلیئر چیکس ہٹائیں۔
// @description:uz      *XAVFSIZ* 10 daqiqa suhbat qayta tiklanishlarini, doimiy tarmoq xatoliklarini va Cloudflare tekshiruvlarini ChatGPT'dan olib tashlang.
// @description:vi      *AN TOÀN* loại bỏ đặt lại trò chuyện 10 phút, lỗi mạng liên tục và kiểm tra Cloudflare khỏi ChatGPT.
// @description:xh      *NGEKONAKALIYO* susa ukunqamula okutsha koxo yemizuzu eli-10 + amathuba olu hlulekileyo womeli + ukuhlolwa kukaCloudflare ukusuka ku ChatGPT.
// @description:yi      *זיכער* נעמט אַראָפ 10 מינוט רעד איבערארבעטן, שטענדיק נעץ פֿעלערן און קלוידפֿלאַרע באַשעקן פֿון ChatGPT.
// @description:zh      *安全* 消除 10 分钟聊天重置 + 持续的网络错误 + ChatGPT 的 Cloudflare 检查。
// @description:zh-CN   *安全* 消除 10 分钟聊天重置 + 持续的网络错误 + ChatGPT 的 Cloudflare 检查。
// @description:zh-HK   *安全* 消除 10 分鐘聊天重設 + 持續的網路錯誤 + ChatGPT 的 Cloudflare 檢查。
// @description:zh-SG   *安全* 消除 10 分钟聊天重置 + 持续的网络错误 + ChatGPT 的 Cloudflare 检查。
// @description:zh-TW   *安全* 消除 10 分鐘聊天重設 + 持續的網路錯誤 + ChatGPT 的 Cloudflare 檢查。
// @description:zu      *NGOKUPHEPHA* susa ukusetha kabusha ingxoxo yemizuzu eyi-10 + amaphutha enethiwekhi ahlala njalo + Ukuhlolwa kwe-Cloudflare ku-ChatGPT.
// @author              Adam Lui
// @namespace           https://github.com/adamlui
// @version             2024.11.29.1
// @license             MIT
// @match               *://chatgpt.com/*
// @match               *://chat.openai.com/*
// @compatible          chrome
// @compatible          firefox
// @compatible          edge
// @compatible          opera
// @compatible          brave
// @compatible          vivaldi
// @compatible          waterfox
// @compatible          librewolf
// @compatible          ghost
// @compatible          qq
// @icon                https://media.chatgptautorefresh.com/images/icons/openai/black/icon48.png?c56f963
// @icon64              https://media.chatgptautorefresh.com/images/icons/openai/black/icon64.png?c56f963
// @require             https://cdn.jsdelivr.net/npm/@kudoai/chatgpt.js@3.3.5/dist/chatgpt.min.js#sha256-rfC4kk8q0byrafp7X0Qf9vaa3JNvkHRwNnUt6uL2hUE=
// @connect             cdn.jsdelivr.net
// @connect             update.greasyfork.org
// @resource bsbgCSS    https://assets.aiwebextensions.com/styles/css/black-rising-stars.min.css?v=50f457d#sha256-RIkvVcaRwwWHMluYKcYeIr1txKkGItLXvdhFo673ST8=
// @resource wsbgCSS    https://assets.aiwebextensions.com/styles/css/white-rising-stars.min.css?v=50f457d#sha256-/cdMEDsWGfHzDc5rkoD2UGCHtiZme+z9fjkSgV2Z7No=
// @grant               GM_setValue
// @grant               GM_getValue
// @grant               GM_registerMenuCommand
// @grant               GM_unregisterMenuCommand
// @grant               GM_getResourceText
// @grant               GM_xmlhttpRequest
// @grant               GM.xmlHttpRequest
// @run-at              document-start
// @noframes
// @homepageURL         https://www.chatgptautorefresh.com
// @supportURL          https://support.chatgptautorefresh.com
// @contributionURL     https://github.com/sponsors/adamlui
// ==/UserScript==

// Documentation: https://docs.chatgptautorefresh.com
// NOTE: This script relies on the powerful chatgpt.js library @ https://chatgpt.js.org
//  © 2023–2024 KudoAI & contributors under the MIT license.

(async () => {

    // Init ENV context
    const env = {
        browser: {
            language: chatgpt.getUserLanguage(), isMobile: chatgpt.browser.isMobile(), isFF: chatgpt.browser.isFirefox()
        },
        scriptManager: {
            name: (() => { try { return GM_info.scriptHandler } catch (err) { return 'unknown' }})(),
            version: (() => { try { return GM_info.version } catch (err) { return 'unknown' }})()
        }
    }
    const xhr = env.scriptManager.name == 'OrangeMonkey' ? GM_xmlhttpRequest : GM.xmlHttpRequest

    // Init APP data
    const app = {
        name: 'ChatGPT Auto Refresh', symbol: '↻', configKeyPrefix: 'chatGPTautoRefresh',
        author: { name: 'Adam Lui', url: 'https://github.com/adamlui' },
        urls: {
            chatgptJS: 'https://chatgpt.js.org',
            donate: {
                cashApp: 'https://cash.app/$adamlui',
                gitHub: 'https://github.com/sponsors/adamlui',
                payPal: 'https://paypal.me/adamlui'
            },
            gitHub: 'https://github.com/adamlui/chatgpt-auto-refresh',
            greasyFork: 'https://greasyfork.org/scripts/462422-chatgpt-auto-refresh',
            mediaHost: 'https://media.chatgptautorefresh.com',
            relatedExtensions: 'https://github.com/adamlui/ai-web-extensions',
            review: {
                greasyFork: 'https://greasyfork.org/scripts/462422-chatgpt-auto-refresh/feedback#post-discussion'
            },
            support: 'https://support.chatgptautorefresh.com'
        },
        latestAssetCommitHash: 'c85f457' // for cached messages.json + navicon
    }
    app.urls.assetHost = app.urls.gitHub.replace('github.com', 'cdn.jsdelivr.net/gh') + `@${app.latestAssetCommitHash}`
    app.urls.update = app.urls.greasyFork.replace('https://', 'https://update.')
        .replace(/(\d+)-?([a-z-]*)$/i, (_, id, name) => `${id}/${ name || 'script' }.meta.js`)
    app.msgs = {
        appName: app.name,
        appAuthor: app.author.name,
        appDesc: '*SAFELY* keeps ChatGPT sessions fresh, eliminating constant network errors + Cloudflare checks (all from the background!)',
        menuLabel_autoRefresh: 'Auto-Refresh',
        menuLabel_toggleVis: 'Toggle Visibility',
        menuLabel_modeNotifs: 'Mode Notifications',
        menuLabel_refreshInt: 'Refresh Interval',
        menuLabel_about: 'About',
        menuLabel_donate: 'Please send a donation',
        about_version: 'Version',
        about_poweredBy: 'Powered by',
        about_sourceCode: 'Source code',
        prompt_updateInt: 'Update refresh interval (in secs)',
        helptip_toggleVis: 'Show Auto-Refresh toggle in sidebar',
        helptip_modeNotifs: 'Show notifications when toggling modes/settings',
        helptip_refreshInt: 'Average delay between refreshes (in seconds)',
        alert_intUpdated: 'Interval updated',
        alert_willRefresh: 'ChatGPT session will auto-refresh every',
        alert_choosePlatform: 'Choose a platform',
        alert_updateAvail: 'Update available',
        alert_newerVer: 'An update to',
        alert_isAvail: 'is available',
        alert_upToDate: 'Up-to-date',
        alert_showYourSupport: 'Show your support',
        alert_isOSS: 'is open-source software built & maintained for free through 100% volunteer efforts',
        alert_despiteAffliction: 'Despite being severely afflicted by',
        alert_longCOVID: 'long COVID',
        alert_since2020: 'since 2020',
        alert_byDonatingResults: 'by donating, you help me to continue improving, fixing bugs, adding new features, and making the software even better',
        alert_yourContrib: 'Your contribution',
        alert_noMatterSize: 'no matter the size',
        alert_directlySupports: 'directly supports my unpaid efforts to ensure this project remains free and open for all to use',
        alert_tyForSupport: 'Thank you for your support',
        alert_author: 'author',
        alert_isUpToDate: 'is up-to-date',
        btnLabel_moreAIextensions: 'More AI Extensions',
        btnLabel_rateUs: 'Rate Us',
        btnLabel_getSupport: 'Get Support',
        btnLabel_updateCheck: 'Check for Updates',
        btnLabel_update: 'Update',
        btnLabel_dismiss: 'Dismiss',
        link_viewChanges: 'View changes',
        unit_secs: 'secs',
        state_enabled: 'enabled',
        state_disabled: 'disabled',
        state_on: 'on',
        state_off: 'off'
    }

    // LOCALIZE app.msgs for non-English users
    if (!env.browser.language.startsWith('en')) {
        const localizedMsgs = await new Promise(resolve => {
            const msgHostDir = app.urls.assetHost + '/greasemonkey/_locales/',
                  msgLocaleDir = ( env.browser.language ? env.browser.language.replace('-', '_') : 'en' ) + '/'
            let msgHref = msgHostDir + msgLocaleDir + 'messages.json', msgXHRtries = 0
            function fetchMsgs() { xhr({ method: 'GET', url: msgHref, onload: handleMsgs })}
            function handleMsgs(resp) {
                try { // to return localized messages.json
                    const msgs = JSON.parse(resp.responseText), flatMsgs = {}
                    for (const key in msgs)  // remove need to ref nested keys
                        if (typeof msgs[key] == 'object' && 'message' in msgs[key])
                            flatMsgs[key] = msgs[key].message
                    resolve(flatMsgs)
                } catch (err) { // if bad response
                    msgXHRtries++ ; if (msgXHRtries == 3) return resolve({}) // try original/region-stripped/EN only
                    msgHref = env.browser.language.includes('-') && msgXHRtries == 1 ? // if regional lang on 1st try...
                        msgHref.replace(/([^_]+_[^_]+)_[^/]*(\/.*)/, '$1$2') // ...strip region before retrying
                            : ( msgHostDir + 'en/messages.json' ) // else use default English messages
                    fetchMsgs()
                }
            }
            fetchMsgs()
        })
        Object.assign(app.msgs, localizedMsgs)
    }

    // Init SETTINGS
    const config = {}
    const settings = {

        controls: { // displays top-to-bottom in toolbar menu
            arDisabled: { type: 'toggle',
                label: app.msgs.menuLabel_autoRefresh },
            toggleHidden: { type: 'toggle',
                label: app.msgs.menuLabel_toggleVis, helptip: app.msgs.helptip_toggleVis },
            notifDisabled: { type: 'toggle',
                label: app.msgs.menuLabel_modeNotifs, helptip: app.msgs.helptip_modeNotifs },
            refreshInterval: { type: 'prompt', symbol: '⌚',
                label: app.msgs.menuLabel_refreshInt, helptip: app.msgs.helptip_refreshInt }
        },

        load(...keys) {
            if (Array.isArray(keys[0])) keys = keys[0] // use 1st array arg, else all comma-separated ones
            keys.forEach(key => config[key] = GM_getValue(app.configKeyPrefix + '_' + key, false))
        },

        save(key, val) { GM_setValue(app.configKeyPrefix + '_' + key, val) ; config[key] = val }
    }
    settings.load('arDisabled', 'notifDisabled', 'refreshInterval', 'toggleHidden')
    if (!config.refreshInterval) settings.save('refreshInterval', 30) // init refresh interval to 30 secs if unset

    // Define MENU functions

    const menu = {
        ids: [], state: {
            symbols: ['❌', '✔️'], separator: env.scriptManager.name == 'Tampermonkey' ? ' — ' : ': ',
            words: [app.msgs.state_off.toUpperCase(), app.msgs.state_on.toUpperCase()]
        },

        register() {
            const tooltipsSupported = env.scriptManager.name == 'Tampermonkey'
                                   && parseInt(env.scriptManager.version.split('.')[0]) >= 5

            // Init prompt setting status labels
            settings.controls.refreshInterval.status = `${config.refreshInterval}s`

            // Add toggles
            Object.keys(settings.controls).forEach(key => {
                const settingIsEnabled = config[key] ^ /disabled|hidden/i.test(key)
                const menuLabel = `${ settings.controls[key].symbol || menu.state.symbols[+settingIsEnabled] } `
                                + settings.controls[key].label
                                + ( settings.controls[key].type == 'toggle' ? menu.state.separator
                                                                            + menu.state.words[+settingIsEnabled]
                                                                            : `— ${settings.controls[key].status}` )
                menu.ids.push(GM_registerMenuCommand(menuLabel, () => {
                    if (settings.controls[key].type == 'toggle') {
                        settings.save(key, !config[key])
                        notify(`${settings.controls[key].label}: ${
                            menu.state.words[+(config[key] ^ /disabled|hidden/i.test(key))]}`)
                    } else { // Refresh Interval prompt
                        while (true) {
                            const refreshInterval = prompt(
                                `${app.msgs.prompt_updateInt}:`, config.refreshInterval)
                            if (refreshInterval == null) break // user cancelled so do nothing
                            else if (!isNaN(parseInt(refreshInterval, 10)) && parseInt(refreshInterval, 10) > 0) {
                                settings.save('refreshInterval', parseInt(refreshInterval, 10))
                                if (chatgpt.autoRefresh.isActive) { // reset running auto-refresh
                                    chatgpt.autoRefresh.deactivate()
                                    chatgpt.autoRefresh.activate(refreshInterval)
                                }
                                menu.refresh()
                                const minInterval = Math.max(2, config.refreshInterval - 10)
                                const maxInterval = config.refreshInterval + 10
                                siteAlert(`${app.msgs.alert_intUpdated}!`,
                                    `${app.msgs.alert_willRefresh} ${minInterval}–${maxInterval} ${app.msgs.unit_secs}`)
                                break
                        }}
                    }
                    syncConfigToUI({ updatedKey: key })
                }, tooltipsSupported ? { title: settings.controls[key].helptip || ' ' } : undefined))
            })

            // Add About entry
            const aboutLabel = `💡 ${app.msgs.menuLabel_about} ${app.msgs.appName}`
            menu.ids.push(GM_registerMenuCommand(aboutLabel, modals.about.show,
                tooltipsSupported ? { title: ' ' } : undefined))

            // Add Donate entry
            const donateLabel = `💖 ${app.msgs.menuLabel_donate}`
            menu.ids.push(GM_registerMenuCommand(donateLabel, modals.about.show,
                tooltipsSupported ? { title: ' ' } : undefined))
        },

        refresh() {
            if (env.scriptManager.name == 'OrangeMonkey') return
            for (const id of menu.ids) { GM_unregisterMenuCommand(id) } menu.register()
        }
    }

    function updateCheck() {

        // Fetch latest meta
        const currentVer = GM_info.script.version
        xhr({
            method: 'GET', url: app.urls.update + '?t=' + Date.now(),
            headers: { 'Cache-Control': 'no-cache' },
            onload: resp => { const updateAlertWidth = 377

                // Compare versions
                const latestVer = /@version +(.*)/.exec(resp.responseText)[1]
                for (let i = 0 ; i < 4 ; i++) { // loop thru subver's
                    const currentSubVer = parseInt(currentVer.split('.')[i], 10) || 0,
                          latestSubVer = parseInt(latestVer.split('.')[i], 10) || 0
                    if (currentSubVer > latestSubVer) break // out of comparison since not outdated
                    else if (latestSubVer > currentSubVer) { // if outdated

                        // Alert to update
                        const updateModal = siteAlert(`🚀 ${app.msgs.alert_updateAvail}!`, // title
                            `${app.msgs.alert_newerVer} ${app.msgs.appName} `
                                + `(v${latestVer}) ${app.msgs.alert_isAvail}!  `
                                + '<a target="_blank" rel="noopener" style="font-size: 0.7rem" '
                                    + 'href="' + app.urls.gitHub + '/commits/main/greasemonkey/'
                                    + app.urls.update.replace(/[^/]*\/([^/]*?)meta\.js/, '$1user.js') + '"'
                                    + `> ${app.msgs.link_viewChanges}</a>`,
                            function update() { // button
                                modals.safeWinOpen(app.urls.update.replace('meta.js', 'user.js') + '?t=' + Date.now())
                            }, '', updateAlertWidth
                        )

                        // Localize button labels if needed
                        if (!env.browser.language.startsWith('en')) {
                            const updateBtns = updateModal.querySelectorAll('button')
                            updateBtns[1].textContent = app.msgs.btnLabel_update
                            updateBtns[0].textContent = app.msgs.btnLabel_dismiss
                        }

                        return
                }}

                // Alert to no update, return to About modal
                siteAlert(`${app.msgs.alert_upToDate}!`, // title
                    `${app.msgs.appName} (v${currentVer}) ${app.msgs.alert_isUpToDate}!`, // msg
                    '', '', updateAlertWidth
                )
                modals.about.show()
    }})}

    // Define FEEDBACK functions

    function notify(msg, pos = '', notifDuration = '', shadow = '') {
        if (config.notifDisabled && !msg.includes(app.msgs.menuLabel_modeNotifs)) return

        // Strip state word to append colored one later
        const foundState = menu.state.words.find(word => msg.includes(word))
        if (foundState) msg = msg.replace(foundState, '')

        // Show notification
        chatgpt.notify(`${app.symbol} ${msg}`, pos, notifDuration, shadow || chatgpt.isDarkMode() ? '' : 'shadow')
        const notif = document.querySelector('.chatgpt-notif:last-child')

        // Append styled state word
        if (foundState) {
            const styledStateSpan = document.createElement('span')
            styledStateSpan.style.cssText = `color: ${
                foundState == menu.state.words[0] ? '#ef4848 ; text-shadow: rgba(255, 169, 225, 0.44) 2px 1px 5px'
                                                  : '#5cef48 ; text-shadow: rgba(255, 250, 169, 0.38) 2px 1px 5px' }`
            styledStateSpan.append(foundState) ; notif.append(styledStateSpan)
        }
    }

    function siteAlert(title = '', msg = '', btns = '', checkbox = '', width = '') {
        const alertID = chatgpt.alert(title, msg, btns, checkbox, width ),
              alert = document.getElementById(alertID).firstChild
        modals.setup(alert) // add class + starry BG + drag handlers
        return alert
    }

    // Define MODAL functions

    const modals = {

        setup(modal) {
            modal.classList.add('chatgpt-auto-refresh-modal')
            modal.onmousedown = modals.dragHandlers.mousedown
            fillStarryBG(modal) // add stars
        },

        dragHandlers: {
            mousedown(event) { // find modal, attach listeners, init XY offsets
                if (event.button != 0) return // prevent non-left-click drag
                if (getComputedStyle(event.target).cursor == 'pointer') return // prevent drag on interactive elems
                modals.dragHandlers.draggableElem = event.currentTarget
                modals.dragHandlers.draggableElem.style.cursor = 'grabbing'
                event.preventDefault(); // prevent sub-elems like icons being draggable
                ['mousemove', 'mouseup'].forEach(event => document.addEventListener(event, modals.dragHandlers[event]))
                const draggableElemRect = modals.dragHandlers.draggableElem.getBoundingClientRect()
                modals.dragHandlers.offsetX = event.clientX - draggableElemRect.left +21
                modals.dragHandlers.offsetY = event.clientY - draggableElemRect.top +12
            },

            mousemove(event) { // drag modal
                if (modals.dragHandlers.draggableElem) {
                    const newX = event.clientX - modals.dragHandlers.offsetX,
                          newY = event.clientY - modals.dragHandlers.offsetY
                    Object.assign(modals.dragHandlers.draggableElem.style, { left: `${newX}px`, top: `${newY}px` })
                }
            },

            mouseup() { // remove listeners, reset modals.dragHandlers.draggableElem
                modals.dragHandlers.draggableElem.style.cursor = 'inherit';
                ['mousemove', 'mouseup'].forEach(event =>
                    document.removeEventListener(event, modals.dragHandlers[event]))
                modals.dragHandlers.draggableElem = null
            }
        },

        about: {
            show() {

                // Init data/styles
                const chatgptJSver = (/chatgpt-([\d.]+)\.min/.exec(GM_info.script.header) || [null, ''])[1],
                      headingStyle = 'font-size: 1.15rem',
                      pStyle = 'position: relative ; left: 3px',
                      pBrStyle = 'position: relative ; left: 4px ',
                      aStyle = 'color: ' + ( chatgpt.isDarkMode() ? '#c67afb' : '#8325c4' ) // purple

                // Show modal
                const aboutModal = siteAlert(
                    `${app.symbol} ${app.msgs.appName}`, // title
                    `<span style="${headingStyle}"><b>🏷️ <i>${app.msgs.about_version}</i></b>: </span>`
                        + `<span style="${pStyle}">${GM_info.script.version}</span>\n`
                    + `<span style="${headingStyle}"><b>⚡ <i>${app.msgs.about_poweredBy}</i></b>: </span>`
                        + `<span style="${pStyle}">`
                            + `<a style="${aStyle}" href="${app.urls.chatgptJS}" target="_blank" rel="noopener">`
                                + 'chatgpt.js</a>' + ( chatgptJSver ? ( ' v' + chatgptJSver ) : '' ) + '</span>\n'
                    + `<span style="${headingStyle}"><b>📜 <i>${app.msgs.about_sourceCode}</i></b>:</span>\n`
                        + `<span style="${pBrStyle}"><a href="${app.urls.gitHub}" target="_blank" rel="nopener">`
                            + app.urls.gitHub + '</a></span>',
                    [ // buttons
                        function checkForUpdates() { updateCheck() },
                        function getSupport() { modals.safeWinOpen(app.urls.support) },
                        function rateUs() { modals.safeWinOpen(app.urls.review.greasyFork) },
                        function moreAIextensions() { modals.safeWinOpen(app.urls.relatedExtensions) }
                    ], '', 546 // set width
                )

                // Re-style text
                aboutModal.querySelector('h2').style.cssText = 'text-align: center ; font-size: 37px ; padding: 9px'
                aboutModal.querySelector('p').style.cssText = 'text-align: center'

                // Re-format buttons to include emoji + localized label + hide Dismiss button
                for (const button of aboutModal.querySelectorAll('button')) {
                    if (/updates/i.test(button.textContent)) button.textContent = (
                        '🚀 ' + ( app.msgs.btnLabel_updateCheck ))
                    else if (/support/i.test(button.textContent)) button.textContent = (
                        '🧠 ' + ( app.msgs.btnLabel_getSupport ))
                    else if (/rate/i.test(button.textContent)) button.textContent = (
                        '⭐ ' + ( app.msgs.btnLabel_rateUs ))
                    else if (/extensions/i.test(button.textContent)) button.textContent = (
                        '🤖 ' + ( app.msgs.btnLabel_moreAIextensions ))
                    else button.style.display = 'none' // hide Dismiss button
                }
            }
        },

        donate: {
            longCOVIDwikiLink: 'https://en.wikipedia.org/wiki/Long_COVID',

            show() {

                // Show alert
                const donateModal = siteAlert(
                    `💖 ${app.msgs.alert_showYourSupport}`, // title
                        `<p>${app.msgs.appName} ${app.msgs.alert_isOSS}.</p>`
                      + `<p>${app.msgs.alert_despiteAffliction} `
                          + `<a target="_blank" rel="noopener" href="${modals.donate.longCOVIDwikiLink}">`
                              + `${app.msgs.alert_longCOVID}</a> `
                          + `${app.msgs.alert_since2020}, ${app.msgs.alert_byDonatingResults}.</p>`
                      + `<p>${app.msgs.alert_yourContrib}, <b>${app.msgs.alert_noMatterSize}</b>, `
                          + `${app.msgs.alert_directlySupports}.</p>`
                      + `<p>${app.msgs.alert_tyForSupport}!</p>`
                      + '<img src="https://cdn.jsdelivr.net/gh/adamlui/adamlui/images/siggie/'
                          + `${ chatgpt.isDarkMode() ? 'white' : 'black' }.png" `
                          + 'style="height: 54px ; margin: 5px 0 -2px 5px"></img>'
                      + `<p>—<b><a target="_blank" rel="noopener" href="${app.author.url}">`
                          + `${app.msgs.appAuthor}</a></b>, ${app.msgs.alert_author}</p>`,
                    [ // buttons
                        function paypal() { modals.safeWinOpen(app.urls.donate.payPal) },
                        function githubSponsors() { modals.safeWinOpen(app.urls.donate.gitHub) },
                        function cashApp() { modals.safeWinOpen(app.urls.donate.cashApp) },
                        function rateUs() { modals.safeWinOpen(app.urls.review.greasyFork) }
                    ], '', 478 // set width
                )

                // Format text
                donateModal.querySelectorAll('p').forEach(p => // v-pad text, shrink line height
                    p.style.cssText = 'padding: 8px 0 ; line-height: 20px')

                // Format buttons
                const btns = donateModal.querySelectorAll('button')
                btns.forEach((btn, idx) => {
                    if (idx == 0) btn.style.display = 'none' // hide Dismiss button
                    else {
                        btn.style.cssText = 'padding: 8px 6px !important ; margin-top: -14px ;'
                                          + ' width: 107px ; line-height: 14px'
                        if (idx == btns.length -1) // de-emphasize right-most button
                            btn.classList.remove('primary-modal-btn')
                        else if (/rate/i.test(btn.textContent)) // localize 'Rate Us' label
                            btn.textContent = app.msgs.btnLabel_rateUs
                    }
                })
            }
        },

        safeWinOpen(url) { open(url, '_blank', 'noopener') } // to prevent backdoor vulnerabilities
    }

    // Define UI functions

    function syncConfigToUI(options) {
        if (options?.updatedKey == 'arDisabled') toggleAutoRefresh()
        if (/arDisabled|toggleHidden/.test(options?.updatedKey)) sidebarToggle.update()
        menu.refresh() // prefixes/suffixes
    }

    function createStyle(content) {
        const style = document.createElement('style')
        if (content) style.innerText = content
        return style
    }

    function fillStarryBG(targetNode) {
        const starsDivsContainer = document.createElement('div')
        starsDivsContainer.style.cssText = 'position: absolute ; top: 0 ; left: 0 ;' // hug targetNode's top-left corner
          + 'height: 100% ; width: 100% ; border-radius: 15px ; overflow: clip ;' // bound innards exactly by targetNode
          + 'z-index: -1'; // allow interactive elems to be clicked
        ['sm', 'med', 'lg'].forEach(starSize => {
            const starsDiv = document.createElement('div')
            starsDiv.id = `${ chatgpt.isDarkMode() ? 'white' : 'black' }-stars-${starSize}`
            starsDivsContainer.append(starsDiv)
        })
        targetNode.prepend(starsDivsContainer)
    }

    const sidebarToggle = {

        create() {
            sidebarToggle.div = document.createElement('div')

            // Create/ID/size/position navicon
            const navicon = document.createElement('img') ; navicon.id = 'auto-refresh-toggle-navicon'
            navicon.style.cssText = 'width: 1.25rem ; height: 1.25rem ; margin-left: 2px ; margin-right: 4px'

            // Create/disable/hide checkbox
            const toggleInput = document.createElement('input')
            Object.assign(toggleInput, { type: 'checkbox', disabled: true })
            toggleInput.style.display = 'none'

            // Create/stylize switch
            const switchSpan = document.createElement('span')
            Object.assign(switchSpan.style, {
                position: 'relative', left: `${ env.browser.isMobile ? 169 : !env.ui.firstLink ? 160 : 154 }px`,
                backgroundColor: toggleInput.checked ? '#ccc' : '#AD68FF', // init opposite  final color
                bottom: `${ !env.ui.firstLink ? -0.15 : 0 }em`,
                width: '30px', height: '15px', '-webkit-transition': '.4s', transition: '0.4s',  borderRadius: '28px'
            })

            // Create/stylize knob, append to switch
            const knobSpan = document.createElement('span') ; knobSpan.id = 'auto-refresh-toggle-knob-span'
            Object.assign(knobSpan.style, {
                position: 'absolute', left: '3px', bottom: '1.25px',
                width: '12px', height: '12px', content: '""', borderRadius: '28px',
                transform: toggleInput.checked ? // init opposite final pos
                    'translateX(0)' : 'translateX(13px) translateY(0)',
                backgroundColor: 'white',  '-webkit-transition': '0.4s', transition: '0.4s'
            }) ; switchSpan.append(knobSpan)

            // Create/stylize/fill label
            const toggleLabel = document.createElement('label')
            if (!env.ui.firstLink) // add font size/weight since no env.ui.firstLink to borrow from
                toggleLabel.style.cssText = 'font-size: 0.875rem, font-weight: 600'
            Object.assign(toggleLabel.style, {
                marginLeft: `-${ !env.ui.firstLink ? 23 : 41 }px`, // left-shift to navicon
                cursor: 'pointer', // add finger cursor on hover
                width: `${ env.browser.isMobile ? 201 : 148 }px`, // to truncate overflown text
                overflow: 'hidden', textOverflow: 'ellipsis' // to truncate overflown text
            })

            // Append elements
            sidebarToggle.div.append(navicon, toggleInput, switchSpan, toggleLabel)

            // Stylize/classify
            sidebarToggle.div.style.cssText += 'height: 37px ; margin: 2px 0 ; user-select: none ; cursor: pointer'
            if (env.ui.firstLink) { // borrow/assign classes from sidebar elems
                const firstIcon = env.ui.firstLink.querySelector('div:first-child'),
                      firstLabel = env.ui.firstLink.querySelector('div:nth-child(2)')
                sidebarToggle.div.classList.add(...env.ui.firstLink.classList, ...(firstLabel?.classList || []))
                sidebarToggle.div.querySelector('img')?.classList.add(...(firstIcon?.classList || []))
            }

            sidebarToggle.update() // to opposite init state for animation on 1st load

            // Add click listener
            sidebarToggle.div.onclick = () => {
                settings.save('arDisabled', toggleInput.checked) ; syncConfigToUI({ updatedKey: 'arDisabled' })
                notify(`${app.msgs.menuLabel_autoRefresh}: ${menu.state.words[+!config.arDisabled]}`)
            }
        },

        insert() {
            if (sidebarToggle.status?.startsWith('insert') || document.getElementById('auto-refresh-toggle-navicon')) return
            sidebarToggle.status = 'inserting' ; if (!sidebarToggle.div) sidebarToggle.create()

            // Insert toggle
            const sidebar = document.querySelectorAll('nav')[env.browser.isMobile ? 1 : 0]
            if (!sidebar) return
            sidebar.insertBefore(sidebarToggle.div, sidebar.children[1])

            // Tweak styles
            const knobSpan = document.getElementById('auto-refresh-toggle-knob-span'),
                  navicon = document.getElementById('auto-refresh-toggle-navicon')
            sidebarToggle.div.style.flexGrow = 'unset' // overcome OpenAI .grow
            sidebarToggle.div.style.paddingLeft = '8px'
            if (knobSpan) knobSpan.style.boxShadow = (
                'rgba(0, 0, 0, .3) 0 1px 2px 0' + ( chatgpt.isDarkMode() ? ', rgba(0, 0, 0, .15) 0 3px 6px 2px' : '' ))
            if (navicon) navicon.src = `${ // update navicon color in case scheme changed
                app.urls.mediaHost}/images/icons/auto-refresh/`
              + `${ chatgpt.isDarkMode() ? 'white' : 'black' }/icon32.png?${app.latestAssetCommitHash}`

            sidebarToggle.status = 'inserted'
        },

        update() {
            const toggleLabel = sidebarToggle.div.querySelector('label'),
                  toggleInput = sidebarToggle.div.querySelector('input'),
                  switchSpan = sidebarToggle.div.querySelector('span'),
                  knobSpan = switchSpan.firstChild
            sidebarToggle.div.style.display = config.toggleHidden ? 'none' : 'flex'
            toggleInput.checked = !config.arDisabled
            toggleLabel.innerText = `${app.msgs.menuLabel_autoRefresh} ${
                app.msgs['state_' + ( toggleInput.checked ? 'enabled' : 'disabled' )]}`
            setTimeout(() => {
                switchSpan.style.backgroundColor = toggleInput.checked ? '#ad68ff' : '#ccc'
                switchSpan.style.boxShadow = toggleInput.checked ? '2px 1px 9px #d8a9ff' : 'none'
                knobSpan.style.transform = toggleInput.checked ? 'translateX(13px) translateY(0)' : 'translateX(0)'
            }, 1) // min delay to trigger transition fx
        }
    }

    // Define AUTO-REFRESH function

    function toggleAutoRefresh() {
        if (!config.arDisabled && !chatgpt.autoRefresh.isActive)
            chatgpt.autoRefresh.activate(config.refreshInterval)
        else if (config.arDisabled && chatgpt.autoRefresh.isActive)
            chatgpt.autoRefresh.deactivate()
    }

    // Run MAIN routine

    menu.register() // create browser toolbar menu

    // Init UI props
    await Promise.race([chatgpt.isLoaded(), new Promise(resolve => setTimeout(resolve, 5000))]) // initial UI loaded
    await chatgpt.sidebar.isLoaded()
    env.ui = { firstLink: chatgpt.getNewChatLink() }

    // Add/update TWEAKS style
    const tweaksStyleUpdated = 1732600036095 // timestamp of last edit for this file's tweaksStyle
    let tweaksStyle = document.getElementById('tweaks-style') // try to select existing style
    if (!tweaksStyle || parseInt(tweaksStyle.getAttribute('last-updated')) < tweaksStyleUpdated) {
        if (!tweaksStyle) { // outright missing, create/id/attr/append it first
            tweaksStyle = document.createElement('style') ; tweaksStyle.id = 'tweaks-style'
            tweaksStyle.setAttribute('last-updated', tweaksStyleUpdated.toString())
            document.head.append(tweaksStyle)
        }
        tweaksStyle.innerText = (
            '[class$="-modal"] { z-index: 13456 ; position: absolute }' // to be click-draggable
          + ( chatgpt.isDarkMode() ? '.chatgpt-modal > div { border: 1px solid white }' : '' )
          + '.chatgpt-modal button {'
              + 'font-size: 0.77rem ; text-transform: uppercase ;' // shrink/uppercase labels
              + 'border-radius: 0 !important ;' // square borders
              + 'transition: transform 0.1s ease-in-out, box-shadow 0.1s ease-in-out ;' // smoothen hover fx
              + 'cursor: pointer !important ;' // add finger cursor
              + 'padding: 5px !important ; min-width: 102px }' // resize
          + '.chatgpt-modal button:hover {' // add zoom, re-scheme
              + 'transform: scale(1.055) ; color: black !important ;'
              + `background-color: #${ chatgpt.isDarkMode() ? '00cfff' : '9cdaff' } !important }`
          + ( !env.browser.isMobile ? '.modal-buttons { margin-left: -13px !important }' : '' )
          + '* { scrollbar-width: thin }' // make FF scrollbar skinny to not crop toggle
        )
    }; // eslint-disable-line

    // Add STARS styles
    ['wsbg', 'bsbg'].forEach(cssType => // white stars, black stars
        document.head.append(createStyle(GM_getResourceText(`${cssType}CSS`))))

    sidebarToggle.insert()

    // Prevent sporadic convo RESETS
    const ogAEL = EventTarget.prototype.addEventListener
    EventTarget.prototype.addEventListener = function(type, listener, optionsOrUseCapture) {
        let calledByOpenAI = false
        if (type == 'focus' && this == unsafeWindow || type == 'visibilitychange') {
            const callStack = new Error().stack + '\n',
                  aelCaller = /-extension:\/\/.*\n(.+)/.exec(callStack)?.[1]
            calledByOpenAI = !aelCaller?.includes('-extension://')
            if (calledByOpenAI && type == 'visibilitychange') {
                ogAEL.call(this, type, function(event) {
                    if (document.visibilityState != 'visible') listener.call(this, event)
                }, optionsOrUseCapture)
        }}
        if (!calledByOpenAI) ogAEL.apply(this, arguments)
    }

    // Activate AUTO-REFRESH on first visit if enabled
    if (!config.arDisabled) {
        chatgpt.autoRefresh.activate(config.refreshInterval)
        notify(`${app.msgs.menuLabel_autoRefresh}: ${app.msgs.state_on}`)
    }

    // Monitor NODE CHANGES to maintain sidebar toggle visibility
    new MutationObserver(() => {
        if (!config.toggleHidden && !document.getElementById('auto-refresh-toggle-navicon')
            && sidebarToggle.status != 'inserting') {
                sidebarToggle.status = 'missing' ; sidebarToggle.insert() }
    }).observe(document.body, { attributes: true, subtree: true })

    // Disable distracting SIDEBAR CLICK-ZOOM effect
    if (!document.documentElement.hasAttribute('sidebar-click-zoom-observed')) {
        new MutationObserver(mutations => mutations.forEach(({ target }) => {
            if (target.closest('[class*="sidebar"]') // include sidebar divs
                && !target.id.endsWith('-knob-span') // exclude our sidebarToggle
                && target.style.transform != 'none' // click-zoom occurred
            ) target.style.transform = 'none'
        })).observe(document.body, { attributes: true, subtree: true, attributeFilter: [ 'style' ]})
        document.documentElement.setAttribute('sidebar-click-zoom-observed', true)
    }

})()