// ==UserScript== // @name YouTube™ Classic 📺 — (Remove rounded design + Return YouTube dislikes) // @name:af YouTube Klassiek // @name:am ዩቱብ ክላሲክ // @name:ar يوتيوب كلاسيك // @name:az YouTube Klassik // @name:be YouTube Класік // @name:bem YouTube Classic // @name:bg YouTube Класик // @name:bn ইউটিউব ক্লাসিক // @name:bo ཡུ་ཊུབ་སྲོལ་རྒྱུན། // @name:bs YouTube Klasični // @name:ca YouTube Clàssic // @name:ceb YouTube Klasiko // @name:ckb یوتیوب کلاسیک // @name:cs YouTube Klasický // @name:cy YouTube Clasurol // @name:da YouTube Klassisk // @name:de YouTube Classic // @name:dv ޔޫޓިއުބް ކްލަސިކް // @name:dz ཡུ་ཊུབ་སྲོལ་རྒྱུན། // @name:el YouTube Κλασικό // @name:eo YouTube Klasika // @name:es YouTube Clásico // @name:et YouTube Klassikaline // @name:eu YouTube Klasikoa // @name:fa یوتیوب کلاسیک // @name:fi YouTube Classic // @name:fo YouTube Classic // @name:fr YouTube Classique // @name:fr-CA YouTube Classique // @name:gd YouTube Clasaigeach // @name:gl YouTube Clásico // @name:gu યુટ્યુબ ક્લાસિક // @name:haw YouTube Kūmau // @name:he YouTube קלאסי // @name:hi यूट्यूब क्लासिक // @name:hr YouTube Klasični // @name:ht YouTube Klasik // @name:hu YouTube Klasszikus // @name:hy YouTube Դասական // @name:id YouTube Klasik // @name:is YouTube Sígilt // @name:it YouTube Classico // @name:ja YouTube クラシック // @name:jv YouTube Klasik // @name:ka YouTube კლასიკური // @name:kab YouTube Aklasik // @name:kk YouTube Классикалық // @name:km YouTube បុរាណ // @name:kn ಯೂಟ್ಯೂಬ್ ಕ್ಲಾಸಿಕ್ // @name:ko YouTube 클래식 // @name:ku YouTube Klasîk // @name:ky YouTube Классикалык // @name:la YouTube Classic // @name:lb YouTube Klassesch // @name:lo YouTube ຄລາສສິກ // @name:lt YouTube Klasikinis // @name:lv YouTube Klasiskais // @name:mg YouTube Klasika // @name:mi YouTube Matarohanga // @name:mk YouTube Класичен // @name:ml YouTube ക്ലാസിക് // @name:mn YouTube Сонгодог // @name:mr YouTube क्लासिक // @name:ms YouTube Klasik // @name:mt YouTube Klassiku // @name:my YouTube ဂန္ထဝင် // @name:ne YouTube क्लासिक // @name:nl YouTube Klassiek // @name:no YouTube Klassisk // @name:ny YouTube Yakale // @name:pa YouTube ਕਲਾਸਿਕ // @name:pl YouTube Klasyczny // @name:ps YouTube کلاسیک // @name:pt YouTube Clássico // @name:pt-BR YouTube Clássico // @name:ro YouTube Clasic // @name:ru YouTube Классический // @name:rw YouTube ya Kera // @name:sg YouTube Classique // @name:si YouTube සම්භාව්ය // @name:sk YouTube Klasický // @name:sl YouTube Klasični // @name:sm YouTube Fa'ata'atia // @name:sn YouTube Yekare // @name:so YouTube Qadiimiga // @name:sq YouTube Klasik // @name:sr YouTube Класични // @name:st YouTube ya Khale // @name:sv YouTube Klassisk // @name:sw YouTube ya Awali // @name:ta YouTube கிளாசிக் // @name:te YouTube క్లాసిక్ // @name:tg YouTube Классикӣ // @name:th YouTube คลาสสิก // @name:ti ዩቱብ ክላሲክ // @name:tk YouTube Klassiki // @name:tl YouTube Klasiko // @name:tn YouTube ya Bogologolo // @name:to YouTube Motu'a // @name:tr YouTube Klasik // @name:tt YouTube Классик // @name:ug YouTube كلاسسىك // @name:uk YouTube Класичний // @name:ur YouTube کلاسک // @name:uz YouTube Klassik // @name:vi YouTube Cổ Điển // @name:wo YouTube Xóot // @name:xh YouTube Yakudala // @name:yi YouTube קלאַסיש // @name:yo YouTube Ayebaye // @name:zh YouTube 经典 // @name:zh-CN YouTube 经典 // @name:zh-HK YouTube 經典 // @name:zh-SG YouTube 经典 // @name:zh-TW YouTube 經典 // @name:zu YouTube Yakudala // @version 2026.5.21.3 // @author Adam Lui, magma_craft // @namespace https://github.com/adamlui // @description Reverts YouTube to its classic design (before all the rounded corners & hidden dislikes) + redirects YouTube Shorts + blocks thumbnail ads // @description:af Keer YouTube terug na sy klassieke ontwerp (voor al die geronde hoeke en verborge dislikes) + herlei YouTube Shorts + blokkeer miniatuur advertensies // @description:am YouTubeን ወደ ክላሲክ ዲዛይኑ ይመልሳል (የተጠጋጉ ማዕዘኖች እና የተደበቁ አለመውደዶች በፊት) + YouTube Shortsን ያዛውራል + ድንክዬ ማስታወቂያዎችን ያግዳል // @description:ar يعيد YouTube إلى تصميمه الكلاسيكي (قبل كل الزوايا المستديرة وعدم الإعجابات المخفية) + إعادة توجيه YouTube Shorts + حظر إعلانات الصور المصغرة // @description:az YouTube-u klassik dizaynına qaytarır (bütün yuvarlaq künclər və gizli bəyənməmələrdən əvvəl) + YouTube Shorts-u yönləndirir + miniatür reklamlarını bloklayır // @description:be Вяртае YouTube да класічнага дызайну (да ўсіх закругленых кутоў і схаваных дызлайкаў) + перанакіроўвае YouTube Shorts + блакуе мініяцюрныя рэкламы // @description:bem Yubwekesha YouTube ku mushobo wayo wakale (pansela ya ma angle yonse ayendaula ne ma dislikes afisama) + ilolo kwa YouTube Shorts + blockinga ama thumbnail ads // @description:bg Връща YouTube към класическия му дизайн (преди всички заоблени ъгли и скрити нехаресвания) + пренасочва YouTube Shorts + блокира реклами с миниатюри // @description:bn ইউটিউবকে তার ক্লাসিক ডিজাইনে ফিরিয়ে আনে (সব গোলাকার কোণ এবং লুকানো ডিসলাইকের আগে) + ইউটিউব শর্টস রিডাইরেক্ট করে + থাম্বনেইল বিজ্ঞাপন ব্লক করে // @description:bo YouTubeའདི་དེའི་སྲོལ་རྒྱུན་དབྱིབས་དབྱངས་ལུང་བརྗེད་ཀྱི་སྐོར་ལ་སླར་གསོ་བྱེད་ཀྱིན་འདུག (ཟུར་ཟླུམ་མམ་བཞིན་དང་གསང་བའི་མི་འདོད་པ་རྣམས་ཀྱི་སྔོན་ལ) + YouTube Shortsབསྐྱར་ཁྲིད་བྱེད་ཀྱིན་འདུག + མཚོན་ཐུང་ཚོང་རྟགས་འགོག་བྱེད་ཀྱིན་འདུག // @description:bs Vraća YouTube na njegov klasični dizajn (prije svih zaobljenih uglova i skrivenih dislajkova) + preusmjerava YouTube Shorts + blokira minijaturne reklame // @description:ca Retorna YouTube al seu disseny clàssic (abans de totes les cantonades arrodonides i els dislikes amagats) + redirigeix YouTube Shorts + bloqueja anuncis de miniatures // @description:ceb Ibalik ang YouTube sa klasiko nga disenyo (sa wala pa ang tanang lingin nga mga suok ug gitago nga mga dislikes) + gi-redirect ang YouTube Shorts + gibabagan ang mga thumbnail ads // @description:ckb یوتیوب بۆ دیزاینی کلاسیکی خۆی دەگەڕێنێتەوە (پێش هەموو گۆشە خڕەکان و دڵنەکردنە شاراوەکان) + یوتیوب شۆرتس ڕەوانە دەکات + ڕیکلامی وێنە بچووکەکان بلۆک دەکات // @description:cs Vrací YouTube do klasického designu (před všemi zaoblenými rohy a skrytými dislikes) + přesměrovává YouTube Shorts + blokuje miniaturní reklamy // @description:cy Yn dychwelyd YouTube i'w ddyluniad clasurol (cyn yr holl gorneli crwn a dislikes cudd) + ailgyfeirio YouTube Shorts + blocio hysbysebion mân-luniau // @description:da Gendanner YouTube til dets klassiske design (før alle de afrundede hjørner og skjulte dislikes) + omdirigerer YouTube Shorts + blokerer miniatureannoncer // @description:de Stellt das klassische Design von YouTube wieder her (vor all den abgerundeten Ecken und versteckten Dislikes) + leitet YouTube Shorts um + blockiert Thumbnail-Werbung // @description:dv ޔޫޓިއުބް އޭގެ ކްލަސިކް ޑިޒައިން އަށް ރީޑިސައިން ކުރުން (ހުރިހާ ވަށްކޯނާއި ފޮރުވި ޑިސްލައިކްސް ގެ ކުރިން) + ޔޫޓިއުބް ޝޯޓްސް ރީޑައިރެކްޓް + ތަމްބްނެއިލް އިޝްތިހާރު ބްލޮކް // @description:dz ཡུ་ཊུབ་མོའི་སྲོལ་རྒྱུན་གྱི་དབྱིབས་རྩ་ལུ་སླར་ལོག་གཏང་དགོ (ཟུར་ཟླུམ་རང་བཞིན་མ་བྱུང་གོང་དང་གསང་བའི་མི་འདོད་པ་རྣམས་ཀྱི་སྔོན་ལ) + ཡུ་ཊུབ་ཐུང་ཐུང་དེ་ཚུ་ཁ་ཕྱོགས་བསྒྱུར་བ་ + མཚོན་ཐུང་ཚོང་རྟགས་དེ་ཚུ་འགོག་པ། // @description:el Επαναφέρει το YouTube στον κλασικό του σχεδιασμό (πριν από όλες τις στρογγυλεμένες γωνίες και τα κρυφά dislikes) + ανακατευθύνει τα YouTube Shorts + μπλοκάρει τις διαφημίσεις μικρογραφιών // @description:eo Reakiras YouTube al sia klasika dezajno (antaŭ ĉiuj rondigitaj anguloj kaj kaŝitaj mallaŭkoj) + alidirektas YouTube Shorts + blokas miniaturajn reklamojn // @description:es Revierte YouTube a su diseño clásico (antes de todas las esquinas redondeadas y dislikes ocultos) + redirige YouTube Shorts + bloquea anuncios en miniaturas // @description:et Taastab YouTube'i klassikalise disaini (enne kõiki ümaraid nurki ja peidetud dislikesid) + suunab YouTube Shorts ümber + blokeerib pisipildireklaamid // @description:eu YouTube bere diseinu klasikora itzultzen du (izkin biribildu guztiak eta ezkutuko dislikes-en aurretik) + YouTube Shorts berbideratzen du + miniaturazko iragarkiak blokeatzen ditu // @description:fa یوتیوب را به طراحی کلاسیک خود برمی‌گرداند (قبل از تمام گوشه‌های گرد و دیسلایک‌های پنهان) + یوتیوب شورتز را هدایت می‌کند + تبلیغات تصویر کوچک را مسدود می‌کند // @description:fi Palauttaa YouTuben klassiseen muotoiluun (ennen kaikkia pyöristettyjä kulmia ja piilotettuja dislikes) + ohjaa YouTube Shortsit uudelleen + estää pikkukuvamainokset // @description:fo Vendir YouTube aftur til sína klassiska snið (áðrenn øll rundu hornini og fjaldu dislikesini) + umstjórnar YouTube Shorts + forðar smámyndalýsingum // @description:fr Ramène YouTube à son design classique (avant tous les coins arrondis et les dislikes cachés) + redirige YouTube Shorts + bloque les publicités miniatures // @description:fr-CA Ramène YouTube à son design classique (avant tous les coins arrondis et les dislikes cachés) + redirige YouTube Shorts + bloque les publicités miniatures // @description:gd Tillidh YouTube chun a dhealbhachd clasaigeach (ro na h-uile ceàrnan cruinn agus dislikes falaichte) + ath-stiùiridh YouTube Shorts + bacadh shanasan dealbhagan // @description:gl Reverte YouTube ao seu deseño clásico (antes de todas as esquinas redondeadas e dislikes ocultos) + redirixe YouTube Shorts + bloquea anuncios en miniaturas // @description:gu યુટ્યુબને તેની ક્લાસિક ડિઝાઇનમાં પરત લાવે છે (બધા ગોળાકાર ખૂણા અને છુપાયેલા ડિસલાઇક્સ પહેલા) + યુટ્યુબ શોર્ટ્સ રીડાયરેક્ટ કરે છે + થંબનેઇલ જાહેરાતો બ્લોક કરે છે // @description:haw Hoʻihoʻi i YouTube i kona hoʻolālā kuʻuna (ma mua o nā kihi pōʻai a me nā dislikes huna) + hoʻihoʻi hou i YouTube Shorts + pāpā i nā hoʻolaha thumbnail // @description:he מחזיר את YouTube לעיצוב הקלאסי שלו (לפני כל הפינות המעוגלות והדיסלייקים המוסתרים) + מפנה מחדש YouTube Shorts + חוסם מודעות תמונות ממוזערות // @description:hi YouTube को उसके क्लासिक डिज़ाइन में वापस लाता है (सभी गोल कोनों और छिपे हुए डिसलाइक से पहले) + YouTube शॉर्ट्स को रीडायरेक्ट करता है + थंबनेल विज्ञापनों को ब्लॉक करता है // @description:hr Vraća YouTube na njegov klasični dizajn (prije svih zaobljenih uglova i skrivenih dislajkova) + preusmjerava YouTube Shorts + blokira minijaturne oglase // @description:ht Retounen YouTube nan konsepsyon klasik li (anvan tout kwen awondi ak dislikes kache yo) + redireksyon YouTube Shorts + bloke piblisite ti imaj yo // @description:hu Visszaállítja a YouTube-ot a klasszikus dizájnjára (az összes lekerekített sarok és a rejtett dislikes előtt) + átirányítja a YouTube Shorts-ot + blokkolja a miniatűr hirdetéseket // @description:hy YouTube-ը վերադարձնում է իր դասական ձևավորմանը (մինչ բոլոր կլորացված անկյունները և թաքցված դիզլայքերը) + վերաուղղորդում է YouTube Shorts-ը + արգելափակում է մանրապատկերի գովազդները // @description:id Mengembalikan YouTube ke desain klasiknya (sebelum semua sudut melengkung dan dislikes tersembunyi) + mengalihkan YouTube Shorts + memblokir iklan thumbnail // @description:is Endurheimtir YouTube í sína klassísku hönnun (fyrir öll rúnuðu hornin og földu dislikes) + endurbeina YouTube Shorts + lokar á smámyndaauglýsingar // @description:it Ripristina YouTube al suo design classico (prima di tutti gli angoli arrotondati e i dislikes nascosti) + reindirizza YouTube Shorts + blocca gli annunci miniatura // @description:ja YouTubeをクラシックデザインに戻します(丸みを帯びた角と非表示の低評価の前の状態)+ YouTubeショートをリダイレクト + サムネイル広告をブロック // @description:jv Mbalikake YouTube menyang desain klasik (sadurunge kabeh sudhut bunder lan dislikes sing didhelikake) + ngalihake YouTube Shorts + mblokir iklan gambar cilik // @description:ka YouTube-ს უბრუნებს კლასიკურ დიზაინს (ყველა მომრგვალებულ კუთხემდე და დამალულ dislikes-მდე) + გადამისამართებს YouTube Shorts-ს + ბლოკავს მინიატურულ რეკლამებს // @description:kab Yernu YouTube ɣer usebter-nnes aklasik (uqbel akk teɣmert iqejjiren akked dislikes ifferen) + yezzi YouTube Shorts + yessewḥal ads n thumbnail // @description:kk YouTube-ты классикалық дизайнына қайтарады (барлық дөңгеленген бұрыштар мен жасырын дизлайктарға дейін) + YouTube Shorts-ты қайта бағыттайды + нобай жарнамаларын бұғаттайды // @description:km ធ្វើអោយ YouTube ត្រឡប់ទៅរចនាបទបុរាណវិញ (មុនពេលជ្រុងមូលទាំងអស់ និង dislikes លាក់) + បញ្ជូនបន្ត YouTube Shorts + រារាំងពាណិជ្ជកម្មរូបភាពតូច // @description:kn YouTube ಅನ್ನು ಅದರ ಕ್ಲಾಸಿಕ್ ವಿನ್ಯಾಸಕ್ಕೆ ಹಿಂತಿರುಗಿಸುತ್ತದೆ (ಎಲ್ಲಾ ದುಂಡಾದ ಮೂಲೆಗಳು ಮತ್ತು ಅಡಗಿರುವ ಡಿಸ್‌ಲೈಕ್‌ಗಳ ಮೊದಲು) + YouTube ಶಾರ್ಟ್ಸ್‌ಗಳನ್ನು ಮರುನಿರ್ದೇಶಿಸುತ್ತದೆ + ಥಂಬ್‌ನೇಲ್ ಜಾಹೀರಾತುಗಳನ್ನು ನಿರ್ಬಂಧಿಸುತ್ತದೆ // @description:ko YouTube를 클래식 디자인으로 되돌립니다 (둥근 모서리와 숨겨진 싫어요 이전) + YouTube 쇼츠를 리디렉션 + 썸네일 광고 차단 // @description:ku YouTube-ê vedigerîne sêwirana xwe ya klasîk (berî hemî quncikên girover û dislikesên veşartî) + YouTube Shorts-ê rêve dike + reklamên thumbnail asteng dike // @description:ky YouTube'ду классикалык дизайнына кайтарат (бардык тегеректелген бурчтар жана жашырылган дизлайктарга чейин) + YouTube Shorts'ду багыттайт + эскиз жарнамаларын бөгөттөйт // @description:la YouTube ad classicum consilium suum revertit (ante omnes angulos rotundos et dislikes occultos) + YouTube Shorts redirigit + minutas tabulas impedit // @description:lb Setzt YouTube op säi klasseschen Design zréck (virun all de ronnen Ecker a verstoppten Dislikes) + leet YouTube Shorts ëm + blockéiert Miniatur Annoncen // @description:lo ເຮັດໃຫ້ YouTube ກັບຄືນສູ່ການອອກແບບຄລາສສິກ (ກ່ອນທີ່ຈະມີມຸມມົນທັງໝົດ ແລະການບໍ່ມັກທີ່ເຊື່ອງໄວ້) + ປ່ຽນເສັ້ນທາງ YouTube Shorts + ບລັອກໂຄສະນາຮູບພາບນ້ອຍ // @description:lt Grąžina YouTube į klasikinį dizainą (prieš visus užapvalintus kampus ir paslėptus dislikes) + nukreipia YouTube Shorts + blokuoja miniatiūrines reklamas // @description:lv Atgriež YouTube klasiskajā dizainā (pirms visiem noapaļotajiem stūriem un slēptajiem dislikes) + pārvirza YouTube Shorts + bloķē sīktēlu reklāmas // @description:mg Mamerina an'i YouTube amin'ny endriny klasika (alohan'ny zoro boribory rehetra sy ny dislikes miafina) + mamerina ny YouTube Shorts + manakana ny dokambarotra saritapaka // @description:mi Whakahokia a YouTube ki tana hoahoa matarohanga (i mua i ngā kokonga porowhita katoa me ngā dislikes huna) + whakaararua YouTube Shorts + aukati i ngā whakatairanga karakōnui // @description:mk Го враќа YouTube на неговиот класичен дизајн (пред сите заоблени агли и скриени dislikes) + пренасочува YouTube Shorts + блокира реклами со минијатури // @description:ml YouTube-നെ അതിന്റെ ക്ലാസിക് ഡിസൈനിലേക്ക് തിരികെ കൊണ്ടുവരുന്നു (എല്ലാ ഉരുണ്ട കോണുകളും മറഞ്ഞിരിക്കുന്ന ഡിസ്‌ലൈക്കുകളും മുമ്പ്) + YouTube ഷോർട്ട്സ് റീഡയറക്ട് ചെയ്യുന്നു + തംബ്നെയിൽ പരസ്യങ്ങൾ ബ്ലോക്ക് ചെയ്യുന്നു // @description:mn YouTube-г сонгодог загварт нь буцаана (бүх дугуйрсан булан болон нуугдсан дургүй байдлын өмнө) + YouTube Shorts-г дахин чиглүүлнэ + өнгөц зураг сурталчилгааг блоклоно // @description:mr YouTube ला त्याच्या क्लासिक डिझाइनवर परत आणते (सर्व गोलाकार कोपरे आणि लपविलेल्या डिसलाइकच्या आधी) + YouTube शॉर्ट्स रीडायरेक्ट करते + थंबनेल जाहिराती ब्लॉक करते // @description:ms Mengembalikan YouTube kepada reka bentuk klasiknya (sebelum semua sudut bulat dan dislikes tersembunyi) + mengalihkan YouTube Shorts + menyekat iklan lakaran kecil // @description:mt Ireġġa' lura YouTube għad-disinn klassiku tiegħu (qabel l-irkejjen kollha ttundjati u d-dislikes moħbija) + tirridirieġi YouTube Shorts + timblokka r-reklami tal-minjaturi // @description:my YouTube ကို ၎င်း၏ ဂန္ထဝင် ဒီဇိုင်းသို့ ပြန်ပြောင်းသည် (အဝိုင်းထောင့်များနှင့် ဝှက်ထားသော dislikes များ မတိုင်မီ) + YouTube Shorts ကို ပြန်ညွှန်းသည် + နမူနာပုံငယ် ကြော်ငြာများကို ပိတ်ဆို့သည် // @description:ne YouTube लाई यसको क्लासिक डिजाइनमा फर्काउँछ (सबै गोलाकार कुनाहरू र लुकाइएको डिसलाइकहरू अघि) + YouTube शर्ट्स रिडाइरेक्ट गर्दछ + थम्बनेल विज्ञापनहरू ब्लक गर्दछ // @description:nl Zet YouTube terug naar zijn klassieke ontwerp (vóór alle afgeronde hoeken en verborgen dislikes) + leidt YouTube Shorts om + blokkeert miniatuuradvertenties // @description:no Gjenoppretter YouTube til sitt klassiske design (før alle de avrundede hjørnene og skjulte dislikes) + omdirigerer YouTube Shorts + blokkerer miniatyrannonser // @description:ny Imabwezera YouTube ku mapangidwe ake akale (pamaso pa ngodya zonse zozungulira ndi dislikes zobisika) + imalowetsa YouTube Shorts + imatseka zotsatsa za thumbnail // @description:pa YouTube ਨੂੰ ਇਸਦੇ ਕਲਾਸਿਕ ਡਿਜ਼ਾਈਨ 'ਤੇ ਵਾਪਸ ਲਿਆਉਂਦਾ ਹੈ (ਸਾਰੇ ਗੋਲ ਕੋਨਿਆਂ ਅਤੇ ਲੁਕਵੇਂ ਡਿਸਲਾਈਕਸ ਤੋਂ ਪਹਿਲਾਂ) + YouTube ਸ਼ਾਰਟਸ ਨੂੰ ਰੀਡਾਇਰੈਕਟ ਕਰਦਾ ਹੈ + ਥੰਬਨੇਲ ਇਸ਼ਤਿਹਾਰਾਂ ਨੂੰ ਬਲਾਕ ਕਰਦਾ ਹੈ // @description:pl Przywraca YouTube do klasycznego wyglądu (sprzed wszystkich zaokrąglonych rogów i ukrytych dislikes) + przekierowuje YouTube Shorts + blokuje reklamy miniatur // @description:ps YouTube خپل کلاسیک ډیزاین ته بیرته ګرځوي (د ټولو ګردو کونجونو او پټو dislikes څخه مخکې) + YouTube Shorts ته لارښوونه کوي + د تمبنېل اعلانونه بلاک کوي // @description:pt Reverte o YouTube para o seu design clássico (antes de todos os cantos arredondados e dislikes ocultos) + redireciona YouTube Shorts + bloqueia anúncios em miniaturas // @description:pt-BR Reverte o YouTube para o seu design clássico (antes de todos os cantos arredondados e dislikes ocultos) + redireciona YouTube Shorts + bloqueia anúncios em miniaturas // @description:ro Revine YouTube la designul său clasic (înainte de toate colțurile rotunjite și dislikes ascunse) + redirecționează YouTube Shorts + blochează reclamele miniaturale // @description:ru Возвращает YouTube к классическому дизайну (до всех закругленных углов и скрытых дизлайков) + перенаправляет YouTube Shorts + блокирует миниатюрные рекламы // @description:rw Isubiza YouTube mu ishusho ryayo rya kera (mbere y'inguni zose z'umuzingi na dislikes zihishe) + yerekeza YouTube Shorts + ihagarika amatangazo ya thumbnail // @description:sg Ramène YouTube à son design classique (avant tous les coins arrondis et les dislikes cachés) + redirige YouTube Shorts + bloque les publicités miniatures // @description:si YouTube එහි සම්භාව්‍ය නිර්මාණයට ආපසු හරවයි (සියලු වටකුරු කොන් සහ සැඟවුණු dislikes වලට පෙර) + YouTube Shorts නැවත හරවා යවයි + සිඟිති රූප දැන්වීම් අවහිර කරයි // @description:sk Vracia YouTube do klasického dizajnu (pred všetkými zaoblenými rohmi a skrytými dislikes) + presmerováva YouTube Shorts + blokuje miniatúrne reklamy // @description:sl Povrne YouTube v klasično obliko (pred vsemi zaobljenimi vogali in skritimi dislikes) + preusmeri YouTube Shorts + blokira miniaturne oglase // @description:sm Toe fa'afo'i YouTube i lona fa'atusa masani (a'o le'i o'o i tulimanu lapotopoto uma ma dislikes natia) + toe fa'asino YouTube Shorts + poloka fa'asalalauga ata laiti // @description:sn Inodzosera YouTube kune dhizaini yayo yekare (pamberi pemakona ese akatenderera uye dislikes dzakavanzwa) + inodzosera YouTube Shorts + inodzivisa kushambadza kwemifananidzo midiki // @description:so Ku soo celinta YouTube qaabkeedii qadiiciga ahaa (ka hor dhammaan geesaha wareegsan iyo dislikes qarsoon) + u jiheeya YouTube Shorts + xannibaysa xayeysiisyada thumbnail // @description:sq E kthen YouTube në dizajnin e tij klasik (para të gjitha qosheve të rrumbullakosura dhe dislikes të fshehura) + ridrejton YouTube Shorts + bllokon reklamat e miniaturave // @description:sr Враћа YouTube на његов класични дизајн (пре свих заобљених углова и скривених дислајкова) + преусмерава YouTube Shorts + блокира рекламе са минијатурама // @description:st E khutlisetsa YouTube moetlong oa eona oa khale (pele ho li-angles tsohle tse chitja le dislikes tse patiloeng) + e lebisa YouTube Shorts + e thibela lipapatso tsa thumbnail // @description:sv Återställer YouTube till sin klassiska design (före alla rundade hörn och dolda dislikes) + omdirigerar YouTube Shorts + blockerar miniatyrannonser // @description:sw Inarejesha YouTube kwenye muundo wake wa awali (kabla ya pembe zote za mviringo na dislikes zilizofichwa) + inaelekeza YouTube Shorts + inazuia matangazo ya thumbnail // @description:ta YouTube-ஐ அதன் கிளாசிக் வடிவமைப்பிற்கு மாற்றியமைக்கிறது (அனைத்து வட்டமான மூலைகளும் மறைக்கப்பட்ட விருப்பமின்மைகளும் முன்பு) + YouTube Shorts-ஐ திருப்பிவிடுகிறது + சிறுபட விளம்பரங்களைத் தடுக்கிறது // @description:te YouTube ను దాని క్లాసిక్ డిజైన్‌కు తిరిగి మారుస్తుంది (అన్ని గుండ్రని మూలలు మరియు దాచిన డిస్‌లైక్‌ల ముందు) + YouTube షార్ట్‌లను రీడైరెక్ట్ చేస్తుంది + థంబ్‌నెయిల్ ప్రకటనలను బ్లాక్ చేస్తుంది // @description:tg YouTube-ро ба тарроҳии классикии худ бармегардонад (пеш аз ҳама гӯшаҳои мудаввар ва dislikes пинҳон) + YouTube Shorts-ро равона мекунад + рекламаҳои эскизиро манъ мекунад // @description:th คืน YouTube กลับสู่ดีไซน์คลาสสิก (ก่อนจะมีมุมโค้งมนและซ่อนดิสไลก์) + เปลี่ยนเส้นทาง YouTube Shorts + บล็อกโฆษณารูปขนาดย่อ // @description:ti ንYouTube ናብቲ ክላሲካዊ ዲዛይኑ ይመልሶ (ቅድሚ ኩለን እተዀረኻ ኩርናዕቲን ተሓቢኡ ዘሎ dislikesን) + ንYouTube Shorts ይመርሕ + ንምካንያዊ ረክላማታት ይዓግት // @description:tk YouTube-y öz klassiki dizaýnyna gaýtaryp berýär (ähli tegelek burçlardan we gizlenen dislikes-lerden öň) + YouTube Shorts-y gönükdirýär + miniatýura mahabatlaryny bloklaýar // @description:tl Ibinabalik ang YouTube sa klasikong disenyo nito (bago ang lahat ng bilugang sulok at nakatagong dislikes) + nire-redirect ang YouTube Shorts + hinaharang ang mga thumbnail ad // @description:tn E busetsa YouTube mo tlhamong ya yone ya bogologolo (pele ga dikhutlo tsotlhe tse di kgolokwe le dislikes tse di fitlhilweng) + e kganela YouTube Shorts + e thibela dipapatso tsa ditshwantsho tse dinnye // @description:to Fakafoki'i YouTube ki hono fa'u 'o e founga motu'a (ki mu'a 'a e ngaahi tuliki potupotu tatau mo e dislikes fufuu) + toe 'oatu YouTube Shorts + poloka'i e ngaahi fakamatala'i ki'i fakatata // @description:tr YouTube'u klasik tasarımına döndürür (tüm yuvarlatılmış köşeler ve gizlenmiş dislikelardan önce) + YouTube Shorts'u yönlendirir + küçük resim reklamlarını engeller // @description:tt YouTube'ны классик дизайнына кайтара (барлык түгәрәкләнгән почмаклар һәм яшерелгән dislikesлар алдыннан) + YouTube Shorts'ны юнәлтә + миниатюра рекламаларын блоклый // @description:ug YouTube نى كلاسسىك لايىھىسىگە قايتۇرىدۇ (بارلىق يۇمىلاق بۇلۇڭلار ۋە يوشۇرۇن dislikes دىن بۇرۇن) + YouTube Shorts نى قايتا نىشانلايدۇ + كىچىك رەسىملىك ئېلانلارنى بلوكلايدۇ // @description:uk Повертає YouTube до класичного дизайну (до всіх закруглених кутів і прихованих дизлайків) + перенаправляє YouTube Shorts + блокує мініатюрні реклами // @description:ur یوٹیوب کو اس کے کلاسک ڈیزائن پر واپس لاتا ہے (تمام گول کونوں اور چھپے ہوئے ڈس لائکس سے پہلے) + یوٹیوب شارٹس کو ری ڈائریکٹ کرتا ہے + تھمب نیل اشتہارات کو بلاک کرتا ہے // @description:uz YouTube'ni klassik dizayniga qaytaradi (barcha yumaloq burchaklar va yashirin dislikeslardan oldin) + YouTube Shorts'ni qayta yo'naltiradi + kichik rasmli reklamalarni bloklaydi // @description:vi Đưa YouTube trở lại thiết kế cổ điển (trước khi có tất cả các góc bo tròn và lượt không thích bị ẩn) + chuyển hướng YouTube Shorts + chặn quảng cáo hình thu nhỏ // @description:wo Jël YouTube ci nosukaayam bu xóot (laata ñu tase ko ak dislikes yu nëbbu) + yóbbu YouTube Shorts + fajj far // @description:xh Ibuyisela i-YouTube kuyilo lwayo lwakudala (phambi kwazo zonke iikona ezingqukuva kunye nee-dislikes ezifihliweyo) + yalathisa kwakhona i-YouTube Shorts + ivale iintengiso ze-thumbnail // @description:yi ברענגט YouTube צוריק צו זיין קלאַסישן דיזיין (פֿאַר אַלע די ראַונדיד עקן און באַהאַלטענע דיסלייקס) + רידערעקץ YouTube שאָרץ + בלאַקירט מיניאַטורע אַדס // @description:yo Mu YouTube pada si apẹrẹ ayeraye rẹ (ṣaaju gbogbo awọn igun yika ati awọn aifẹ ti o farapamọ) + awọn YouTube Shorts pada + dènà awọn ipolowo eekanna atampako // @description:zh 将 YouTube 恢复为经典设计(在圆角和隐藏的不喜欢之前)+ 重定向 YouTube Shorts + 屏蔽缩略图广告 // @description:zh-CN 将 YouTube 恢复为经典设计(在圆角和隐藏的不喜欢之前)+ 重定向 YouTube Shorts + 屏蔽缩略图广告 // @description:zh-HK 將 YouTube 還原為經典設計(在圓角與隱藏的不喜歡之前)+ 重新導向 YouTube Shorts + 封鎖縮圖廣告 // @description:zh-SG 将 YouTube 恢复为经典设计(在圆角和隐藏的不喜欢之前)+ 重定向 YouTube Shorts + 屏蔽缩略图广告 // @description:zh-TW 將 YouTube 還原為經典設計(在圓角與隱藏的不喜歡之前)+ 重新導向 YouTube Shorts + 封鎖縮圖廣告 // @description:zu Ibuyisela i-YouTube kumklamo wayo wakudala (ngaphambi kwawo wonke amakhona ayindilinga nama-dislikes afihliwe) + iqondisa kabusha i-YouTube Shorts + ivimba izikhangisi ze-thumbnail // @license MIT // @icon https://cdn.jsdelivr.net/gh/adamlui/youtube-classic@3bd207d/assets/images/icons/app/icon48.png // @icon64 https://cdn.jsdelivr.net/gh/adamlui/youtube-classic@3bd207d/assets/images/icons/app/icon64.png // @compatible chrome // @compatible firefox // @compatible opera // @compatible safari // @compatible edge // @match *://*.youtube.com/* // @connect cdn.jsdelivr.net // @connect gm.ytclassic.com // @connect scriptcat.org // @require https://cdn.jsdelivr.net/npm/json5@2.2.3/dist/index.min.js#sha256-S7ltnVPzgKyAGBlBG4wQhorJqYTehj5WQCrADCKJufE= // @require https://cdn.jsdelivr.net/gh/adamlui/userscripts@ff2baba/assets/js/lib/css.js/dist/css.min.js#sha256-zf9s8C0cZ/i+gnaTIUxa0+RpDYpsJVlyuV5L2q4KUdA= // @require https://cdn.jsdelivr.net/gh/adamlui/userscripts@ff2baba/assets/js/lib/dom.js/dist/dom.min.js#sha256-nTc2by3ZAz6AR7B8fOqjloJNETvjAepe15t2qlghMDo= // @require https://cdn.jsdelivr.net/gh/Anarios/return-youtube-dislike@v4.0.4/Extensions/UserScript/Return%20Youtube%20Dislike.user.js#sha256-BPRgJOQfxTUmr09fqGi1dlZ14jtZfdKHhKltqmf5B+Y= // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_getValue // @grant GM_setValue // @grant GM_xmlhttpRequest // @grant GM.xmlHttpRequest // @run-at document-end // @homepageURL https://www.ytclassic.com // @supportURL https://github.com/adamlui/youtube-classic/issues // @contributionURL https://ko-fi.com/adamlui // ==/UserScript== (async () => { 'use strict' // Init DATA window.env = { browser: { language: navigator.languages[0] || navigator.language || navigator.browserLanguage || navigator.systemLanguage || navigator.userLanguage || '', isFF: navigator.userAgent.includes('Firefox'), isMobile: /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) }, scriptManager: { name: (() => { try { return GM_info.scriptHandler } catch (err) { return 'unknown' }})(), version: (() => { try { return GM_info.version } catch (err) { return 'unknown' }})() } } env.scriptManager.supportsTooltips = env.scriptManager.name == 'Tampermonkey' && parseInt(env.scriptManager.version.split('.')[0]) >= 5 window.xhr = typeof GM != 'undefined' && GM.xmlHttpRequest || GM_xmlhttpRequest window.app = { name: 'YouTube Classic', symbol: '📺', slug: 'youtube-classic', configKeyPrefix: 'ytClassic', version: GM_info.script.version, author: { name: 'Adam Lui', url: 'https://github.com/adamlui' }, commitHashes: { data: '2c46666', // for messages.json + selectors.json5 images: '1b6e5d3' // for header logo } } app.urls = { github: 'https://github.com/adamlui/youtube-classic', jsd: 'https://cdn.jsdelivr.net/gh/adamlui/youtube-classic', review: { scriptcat: 'https://scriptcat.org/script-show-page/6345/comment' }, support: 'https://support.ytclassic.com', update: { gm: 'https://scriptcat.org/scripts/code/6345/youtube-classic.meta.js' }, userscripts: 'https://github.com/adamlui/userscripts' } app.urls.data = `${app.urls.jsd}@${app.commitHashes.data}/assets/data` app.urls.images = `${app.urls.jsd}@${app.commitHashes.images}/assets/images` app.msgs = await new Promise(resolve => { const msgBaseURL = `${app.urls.data}/_locales`, locale = `${ env.browser.language ? env.browser.language.replace('-', '_') : 'en' }` let msgURL = `${msgBaseURL}/${locale}/messages.json`, msgFetchesTried = 0 function fetchMsgs() { xhr({ method: 'GET', url: msgURL, 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) { msgFetchesTried++ ; if (msgFetchesTried == 3) return resolve({}) // try og/region-stripped/EN only msgURL = env.browser.language.includes('-') && msgFetchesTried == 1 ? // if regional lang on 1st try... msgURL.replace(/(_locales\/[^_]+)_[^_]+(\/)/, '$1$2') // ...strip region before retrying : `${msgBaseURL}/en/messages.json` // else use default English messages fetchMsgs() } } fetchMsgs() }) app.selectors = await new Promise(resolve => xhr({ // used in *block modes method: 'GET', onload: ({ responseText }) => resolve(JSON5.parse(responseText)), url: `${app.urls.data}/selectors.json5` })) // Init SETTINGS app.config ??= {} window.i18n = { getMsg(key) { return typeof GM_info == 'undefined' ? browserAPI.i18n.getMessage(key) // from ./_locales/*/messages.json : app.msgs[key] // from userscript } } window.settings = { controls: { // displays top-to-bottom in toolbar menu restoreDislikes: { type: 'toggle', defaultVal: true }, unroundCorners: { type: 'toggle', defaultVal: true }, disableShorts: { type: 'toggle', defaultVal: true }, shortsBlock: { type: 'toggle', defaultVal: true }, playablesBlock: { type: 'toggle', defaultVal: true }, adBlock: { type: 'toggle', defaultVal: false }, aiBlock: { type: 'toggle', defaultVal: true }, reduceAnimations: { type: 'toggle', defaultVal: true }, idlePrevention: { type: 'toggle', defaultVal: true }, notifDisabled: { type: 'toggle', defaultVal: false } }, load(...keys) { keys.flat().forEach(key => app.config[key] = processKey(key, GM_getValue(`${app.configKeyPrefix}_${key}`, undefined))) function processKey(key, val) { const ctrl = settings.controls?.[key] if (val != undefined && ( // validate stored val (ctrl?.type == 'toggle' && typeof val != 'boolean') || (ctrl?.type == 'slider' && isNaN(parseFloat(val))) )) val = undefined return val ?? (ctrl?.defaultVal ?? (ctrl?.type == 'slider' ? 100 : false)) } }, save(key, val) { GM_setValue(`${app.configKeyPrefix}_${key}`, val) ; app.config[key] = val }, typeIsEnabled(key) { // for menu labels + notifs to return ON/OFF const reInvertSuffixes = /disabled|hidden/i return reInvertSuffixes.test(key) // flag in control key name && !reInvertSuffixes.test(this.controls[key]?.label || '') // but not in label msg key name ? !app.config[key] : app.config[key] // so invert since flag reps opposite type state, else don't } } for (const [key, ctrl] of Object.entries(settings.controls)) { ctrl.label = i18n.getMsg(`mode_${key}`) ctrl.helptip = i18n.getMsg(`helptip_${key}`) } settings.load(Object.keys(settings.controls)) const EXPFLAGS = { enable_channel_page_header_profile_section: false, enable_header_channel_handler_ui: false, kevlar_unavailable_video_error_ui_client: false, kevlar_refresh_on_theme_change: false, kevlar_modern_sd_v2: false, kevlar_watch_cinematics: false, kevlar_watch_comments_panel_button: false, kevlar_watch_grid: false, kevlar_watch_grid_hide_chips: false, kevlar_watch_metadata_refresh: false, kevlar_watch_metadata_refresh_no_old_secondary_data: false, kevlar_watch_modern_metapanel: false, kevlar_watch_modern_panels: false, kevlar_watch_panel_height_matches_player: false, smartimation_background: false, web_amsterdam_playlists: false, web_animated_actions: false, web_animated_like: false, web_button_rework: false, web_button_rework_with_live: false, web_darker_dark_theme: false, web_enable_youtab: false, web_guide_ui_refresh: false, web_modern_ads: false, web_modern_buttons: false, web_modern_chips: false, web_modern_collections_v2: false, web_modern_dialogs: false, web_modern_playlists: false, web_modern_subscribe: false, web_modern_tabs: false, web_rounded_containers: false, web_rounded_thumbnails: false, web_searchbar_style: 'default', web_segmented_like_dislike_button: false, web_sheets_ui_refresh: false, web_snackbar_ui_refresh: false, web_watch_rounded_player_large: false } // Define FUNCTIONS localStorage.alertQueue = '[]' window.feedback = { cjsAlert(title, msg, btns, checkbox, width) { // [ title/msg = strings, btns = [named functions], checkbox = named function, width (px) = int ] = optional // * Spaces are inserted into button labels by parsing function names in camel/kebab/snake case // Init env context const scheme = ui.getScheme(), isMobile = env.browser.isMobile // Define event handlers const handlers = { dismiss: { click(event) { if (event.target == event.currentTarget || event.target.closest('[class*=-close-btn]')) dismissAlert() }, key(event) { if (!/^(?: |Space|Enter|Return|Esc)/.test(event.key) || ![32, 13, 27].includes(event.keyCode)) return for (const alertId of alertQueue) { // look to handle only if triggering alert is active const alert = document.getElementById(alertId) if (!alert || alert.style.display == 'none') return if (event.key.startsWith('Esc') || event.keyCode == 27) dismissAlert() // and do nothing else { // Space/Enter pressed const mainBtn = alert.querySelector('.modal-buttons').lastChild // look for main button if (mainBtn) { mainBtn.click() ; event.preventDefault() } // click if found } } } }, drag: { mousedown(event) { // find modal, update styles, attach listeners, init XY offsets if ( // prevent drag when... event.button != 0 // non-left-click || !/auto|default/.test(getComputedStyle(event.target).cursor) // cursor changed ) return feedback.draggingModal = event.currentTarget event.preventDefault() // prevent sub-elems like icons being draggable Object.assign(feedback.draggingModal.style, { transition: 'transform 0.1s ease', transform: 'scale(1.05)' }) document.body.style.cursor = 'grabbing' // update cursor ;[...feedback.draggingModal.children] // prevent hover FX if drag lags behind cursor .forEach(child => child.style.pointerEvents = 'none') ;['mousemove', 'mouseup'].forEach(eventType => // add listeners document.addEventListener(eventType, handlers.drag[eventType])) const draggingModalRect = feedback.draggingModal.getBoundingClientRect() handlers.drag.offsetX = event.clientX - draggingModalRect.left +21 handlers.drag.offsetY = event.clientY - draggingModalRect.top +12 }, mousemove(event) { // drag modal if (!feedback.draggingModal) return const newX = event.clientX - handlers.drag.offsetX, newY = event.clientY - handlers.drag.offsetY Object.assign(feedback.draggingModal.style, { left: `${newX}px`, top: `${newY}px` }) }, mouseup() { // restore styles/pointer events, remove listeners, reset feedback.draggingModal Object.assign(feedback.draggingModal.style, { // restore styles cursor: 'inherit', transition: 'inherit', transform: 'scale(1)' }) document.body.style.cursor = '' // restore cursor ;[...feedback.draggingModal.children] // restore pointer events .forEach(child => child.style.pointerEvents = '') ;['mousemove', 'mouseup'].forEach(eventType => // remove listeners document.removeEventListener(eventType, handlers.drag[eventType])) feedback.draggingModal = null } } } // Create modal parent/children elems const modalContainer = document.createElement('div') modalContainer.id = Math.floor(randomFloat() * 1000000) + Date.now() modalContainer.classList.add('chatgpt-modal') // add class to main div const modal = document.createElement('div'), modalTitle = document.createElement('h2'), modalMsg = document.createElement('p') // Create/append/update modal style (if missing or outdated) const thisUpdated = 1739338889852 // timestamp of last edit for this file's `modalStyle` let modalStyle = document.querySelector('#chatgpt-modal-style') // try to select existing style if (!modalStyle || parseInt(modalStyle.getAttribute('last-updated'), 10) < thisUpdated) { // if missing or outdated if (!modalStyle) { // outright missing, create/id/attr/append it first modalStyle = document.createElement('style') ; modalStyle.id = 'chatgpt-modal-style' modalStyle.setAttribute('last-updated', thisUpdated.toString()) document.head.append(modalStyle) } modalStyle.textContent = ( // update prev/new style contents `.chatgpt-modal { /* vars */ --transition: opacity 0.65s cubic-bezier(.165,.84,.44,1), /* for fade-in */ transform 0.55s cubic-bezier(.165,.84,.44,1) ; /* for move-in */ --bg-transition: background-color 0.25s ease ; /* for bg dim */ --btn-transition: transform 0.1s ease-in-out, box-shadow 0.1s ease-in-out ; /* for smooth zoom */ --btn-shadow: 2px 1px ${ scheme == 'dark' ? '54px #00cfff' : '30px #9cdaff' }}` + '.no-mobile-tap-outline { outline: none ; -webkit-tap-highlight-color: transparent }' // Background styles + `.chatgpt-modal { pointer-events: auto ; /* override any disabling from site modals (like guest login spam) */ position: fixed ; top: 0 ; left: 0 ; width: 100% ; height: 100% ; /* expand to full view-port */ display: flex ; justify-content: center ; align-items: center ; z-index: 9999 ; /* align */ transition: var(--bg-transition) ; /* for bg dim */ -webkit-transition: var(--bg-transition) ; -moz-transition: var(--bg-transition) ; -o-transition: var(--bg-transition) ; -ms-transition: var(--bg-transition) }` // Alert styles + `.chatgpt-modal > div { border-radius: 0 ; position: absolute ; /* to be click-draggable */ opacity: 0 ; /* to fade-in */ font-family: -apple-system, system-ui, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen-Sans, Ubuntu, Cantarell, Helvetica Neue, sans-serif ; padding: 20px ; margin: 12px 23px ; font-size: 20px ; color: ${ scheme == 'dark' ? 'white' : 'black' }; background-color: ${ scheme == 'dark' ? 'black' : 'white' }; border: 1px solid ${ scheme == 'dark' ? 'white' : '#b5b5b5' }; transform: translateX(-3px) translateY(7px) ; /* offset to move-in from */ max-width: 75vw ; word-wrap: break-word ; border-radius: 15px ; --shadow: 0 30px 60px rgba(0,0,0,0.12) ; box-shadow: var(--shadow) ; -webkit-box-shadow: var(--shadow) ; -moz-box-shadow: var(--shadow) ; user-select: none ; -webkit-user-select: none ; -moz-user-select: none ; -o-user-select: none ; -ms-user-select: none ; transition: var(--transition) ; /* for fade-in + move-in */ -webkit-transition: var(--transition) ; -moz-transition: var(--transition) ; -o-transition: var(--transition) ; -ms-transition: var(--transition) } .chatgpt-modal h2 { font-weight: bold ; font-size: 24px ; margin-bottom: 9px } .chatgpt-modal a { color: ${ scheme == 'dark' ? '#00cfff' : '#1e9ebb' }} .chatgpt-modal a:hover { text-decoration: underline } .chatgpt-modal.animated > div { z-index: 13456 ; opacity: 0.98 ; transform: translateX(0) translateY(0) } @keyframes alert-zoom-fade-out { 0% { opacity: 1 } 50% { opacity: 0.25 ; transform: scale(1.05) } 100% { opacity: 0 ; transform: scale(1.35) }}` // Button styles + `.modal-buttons { display: flex ; justify-content: flex-end ; margin: 20px -5px -3px 0 ; ${ isMobile ? 'flex-direction: column-reverse' : '' }} .chatgpt-modal button { font-size: 14px ; text-transform: uppercase ; cursor: crosshair ; margin-left: ${ isMobile ? 0 : 10 }px ; padding: ${ isMobile ? 15 : 8 }px 18px ; ${ isMobile ? 'margin-top: 5px ; margin-bottom: 3px ;' : '' } border-radius: 0 ; border: 1px solid ${ scheme == 'dark' ? 'white' : 'black' }; transition: var(--btn-transition) ; -webkit-transition: var(--btn-transition) ; -moz-transition: var(--btn-transition) ; -o-transition: var(--btn-transition) ; -ms-transition: var(--btn-transition) } .chatgpt-modal button:hover { transform: scale(1.055) ; color: black ; background-color: #${ scheme == 'dark' ? '00cfff' : '9cdaff' }; box-shadow: var(--btn-shadow) ; -webkit-box-shadow: var(--btn-shadow) ; -moz-box-shadow: var(--btn-shadow) } .primary-modal-btn { border: 1px solid ${ scheme == 'dark' ? 'white' : 'black' }; background: ${ scheme == 'dark' ? 'white' : 'black' }; color: ${ scheme == 'dark' ? 'black' : 'white' }} .modal-close-btn { cursor: pointer ; width: 29px ; height: 29px ; border-radius: 17px ; float: right ; position: relative ; right: -6px ; top: -5px } .modal-close-btn svg { margin: 10px } /* center SVG for hover underlay */ .modal-close-btn:hover { background-color: #f2f2f2${ scheme == 'dark' ? '00' : '' }}` // Checkbox styles + `.chatgpt-modal .checkbox-group { margin: 5px 0 -8px 5px } .chatgpt-modal input[type=checkbox] { cursor: pointer ; transform: scale(0.7) ; margin-right: 5px ; border: 1px solid ${ scheme == 'dark' ? 'white' : 'black' }} .chatgpt-modal input[type=checkbox]:checked { background-color: black ; position: inherit ; border: 1px solid ${ scheme == 'dark' ? 'white' : 'black' }} .chatgpt-modal input[type=checkbox]:focus { outline: none ; box-shadow: none ; -webkit-box-shadow: none ; -moz-box-shadow: none } .chatgpt-modal .checkbox-group label { cursor: pointer ; font-size: 14px ; color: ${ scheme == 'dark' ? '#e1e1e1' : '#1e1e1e' }}` ) } // Insert text into elems modalTitle.textContent = title || '' ; modalMsg.innerText = msg || '' feedback.cjsRenderHTML(modalMsg) // Create/append buttons (if provided) to buttons div const modalButtons = document.createElement('div') modalButtons.classList.add('modal-buttons', 'no-mobile-tap-outline') if (btns) { // are supplied if (!Array.isArray(btns)) btns = [btns] // convert single button to array if necessary btns.forEach((buttonFn) => { // create title-cased labels + attach listeners const button = document.createElement('button') button.textContent = buttonFn.name .replace(/[_-]\w/g, match => match.slice(1).toUpperCase()) // convert snake/kebab to camel case .replace(/([A-Z])/g, ' $1') // insert spaces .replace(/^\w/, firstChar => firstChar.toUpperCase()) // capitalize first letter button.onclick = () => { dismissAlert() ; buttonFn() } modalButtons.insertBefore(button, modalButtons.firstChild) }) } // Create/append OK/dismiss button to buttons div const dismissBtn = document.createElement('button') dismissBtn.textContent = btns ? 'Dismiss' : 'OK' modalButtons.insertBefore(dismissBtn, modalButtons.firstChild) // Highlight primary button modalButtons.lastChild.classList.add('primary-modal-btn') // Create/append checkbox (if provided) to checkbox group div const checkboxDiv = document.createElement('div') if (checkbox) { // is supplied checkboxDiv.classList.add('checkbox-group') const checkboxFn = checkbox, // assign the named function to checkboxFn checkboxInput = document.createElement('input') checkboxInput.type = 'checkbox' ; checkboxInput.onchange = checkboxFn // Create/show label const checkboxLabel = document.createElement('label') checkboxLabel.onclick = () => { checkboxInput.checked = !checkboxInput.checked ; checkboxFn() } checkboxLabel.textContent = checkboxFn.name[0].toUpperCase() // capitalize first char + checkboxFn.name.slice(1) // format remaining chars .replace(/([A-Z])/g, (match, letter) => ' ' + letter.toLowerCase()) // insert spaces, convert to lowercase .replace(/\b(\w+)nt\b/gi, '$1n\'t') // insert apostrophe in 'nt' suffixes .trim() // trim leading/trailing spaces checkboxDiv.append(checkboxInput) ; checkboxDiv.append(checkboxLabel) } // Create close button const closeBtn = document.createElement('div') closeBtn.title = 'Close' ; closeBtn.classList.add('modal-close-btn', 'no-mobile-tap-outline') const closeSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg') closeSVG.setAttribute('height', '10px') closeSVG.setAttribute('viewBox', '0 0 14 14') closeSVG.setAttribute('fill', 'none') const closeSVGpath = document.createElementNS('http://www.w3.org/2000/svg', 'path') closeSVGpath.setAttribute('fill-rule', 'evenodd') closeSVGpath.setAttribute('clip-rule', 'evenodd') closeSVGpath.setAttribute('fill', ui.getScheme() == 'dark' ? 'white' : 'black') closeSVGpath.setAttribute('d', 'M13.7071 1.70711C14.0976 1.31658 14.0976 0.683417 13.7071 0.292893C13.3166 -0.0976312 12.6834 -0.0976312 12.2929 0.292893L7 5.58579L1.70711 0.292893C1.31658 -0.0976312 0.683417 -0.0976312 0.292893 0.292893C-0.0976312 0.683417 -0.0976312 1.31658 0.292893 1.70711L5.58579 7L0.292893 12.2929C-0.0976312 12.6834 -0.0976312 13.3166 0.292893 13.7071C0.683417 14.0976 1.31658 14.0976 1.70711 13.7071L7 8.41421L12.2929 13.7071C12.6834 14.0976 13.3166 14.0976 13.7071 13.7071C14.0976 13.3166 14.0976 12.6834 13.7071 12.2929L8.41421 7L13.7071 1.70711Z') closeSVG.append(closeSVGpath) ; closeBtn.append(closeSVG) // Assemble/append div modal.append(closeBtn, modalTitle, modalMsg, checkboxDiv, modalButtons) modal.style.width = `${ width || 458 }px` modalContainer.append(modal) ; document.body.append(modalContainer) // Enqueue alert let alertQueue = JSON.parse(localStorage.alertQueue ??= JSON.stringify([])) alertQueue.push(modalContainer.id) localStorage.alertQueue = JSON.stringify(alertQueue) // Show alert if none active modalContainer.style.display = 'none' if (alertQueue.length == 1) { modalContainer.style.display = '' setTimeout(() => { // dim bg modal.parentNode.style.backgroundColor = `rgba(67,70,72,${ scheme == 'dark' ? 0.62 : 0.33 })` modal.parentNode.classList.add('animated') }, 100) // delay for transition fx } // Add listeners [modalContainer, closeBtn, closeSVG, dismissBtn].forEach(elem => elem.onclick = handlers.dismiss.click) document.addEventListener('keydown', handlers.dismiss.key) modal.onmousedown = handlers.drag.mousedown // enable click-dragging // Define alert dismisser const dismissAlert = () => { modalContainer.style.backgroundColor = 'transparent' modal.style.animation = 'alert-zoom-fade-out 0.165s ease-out' modal.onanimationend = () => { // Remove alert modalContainer.remove() // ...from DOM alertQueue = JSON.parse(localStorage.alertQueue) alertQueue.shift() // + memory localStorage.alertQueue = JSON.stringify(alertQueue) // + storage document.removeEventListener('keydown', handlers.dismiss.key) // prevent memory leaks // Check for pending alerts in queue if (alertQueue.length) { const nextAlert = document.getElementById(alertQueue[0]) setTimeout(() => { nextAlert.style.display = '' setTimeout(() => nextAlert.classList.add('animated'), 100) }, 500) } } } function randomFloat() { // * Generates a random, cryptographically secure value between 0 (inclusive) & 1 (exclusive) const crypto = window.crypto || window.msCrypto return crypto?.getRandomValues(new Uint32Array(1))[0] / 0xFFFFFFFF || Math.random() } return modalContainer.id // if assignment used }, cjsNotify(...args) { const scheme = ui.getScheme() let msg, position, notifDuration, shadow, toast if (typeof args[0] == 'object' && !Array.isArray(args[0])) ({ msg, position, notifDuration, shadow, toast } = args[0]) else [msg, position, notifDuration, shadow] = args notifDuration = notifDuration ? +notifDuration : 1.75 // sec duration to maintain notification visibility const fadeDuration = 0.35, // sec duration of fade-out vpYoffset = 23, vpXoffset = 27 // px offset from viewport border // Create/append notification div const notificationDiv = document.createElement('div') // make div notificationDiv.id = Math.floor(Math.random() * 1000000) + Date.now() notificationDiv.classList.add('chatgpt-notif') notificationDiv.textContent = msg // insert msg document.body.append(notificationDiv) // insert into DOM // Create/append close button const closeBtn = document.createElement('div') closeBtn.title = 'Dismiss' ; closeBtn.classList.add('notif-close-btn', 'no-mobile-tap-outline') const closeSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg') closeSVG.setAttribute('height', '8px') closeSVG.setAttribute('viewBox', '0 0 14 14') closeSVG.setAttribute('fill', 'none') closeSVG.style.height = closeSVG.style.width = '8px' // override SVG styles on non-OpenAI sites const closeSVGpath = document.createElementNS('http://www.w3.org/2000/svg', 'path') closeSVGpath.setAttribute('fill-rule', 'evenodd') closeSVGpath.setAttribute('clip-rule', 'evenodd') closeSVGpath.setAttribute('fill', 'white') closeSVGpath.setAttribute('d', 'M13.7071 1.70711C14.0976 1.31658 14.0976 0.683417 13.7071 0.292893C13.3166 -0.0976312 12.6834 -0.0976312 12.2929 0.292893L7 5.58579L1.70711 0.292893C1.31658 -0.0976312 0.683417 -0.0976312 0.292893 0.292893C-0.0976312 0.683417 -0.0976312 1.31658 0.292893 1.70711L5.58579 7L0.292893 12.2929C-0.0976312 12.6834 -0.0976312 13.3166 0.292893 13.7071C0.683417 14.0976 1.31658 14.0976 1.70711 13.7071L7 8.41421L12.2929 13.7071C12.6834 14.0976 13.3166 14.0976 13.7071 13.7071C14.0976 13.3166 14.0976 12.6834 13.7071 12.2929L8.41421 7L13.7071 1.70711Z') closeSVG.append(closeSVGpath) ; closeBtn.append(closeSVG) ; notificationDiv.append(closeBtn) // Determine div position/quadrant notificationDiv.isTop = !position || !/low|bottom/i.test(position) notificationDiv.isRight = !position || !/left/i.test(position) notificationDiv.quadrant = (notificationDiv.isTop ? 'top' : 'bottom') + (notificationDiv.isRight ? 'Right' : 'Left') // Create/append/update notification style (if missing or outdated) const thisUpdated = 1746996635555 // timestamp of last edit for this file's `notifStyle` let notifStyle = document.querySelector('#chatgpt-notif-style') // try to select existing style if (!notifStyle || parseInt(notifStyle.getAttribute('last-updated'), 10) < thisUpdated) { // if missing or outdated if (!notifStyle) { // outright missing, create/id/attr/append it first notifStyle = document.createElement('style') ; notifStyle.id = 'chatgpt-notif-style' notifStyle.setAttribute('last-updated', thisUpdated.toString()) document.head.append(notifStyle) } notifStyle.textContent = ( // update prev/new style contents '.chatgpt-notif {' + 'font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC",' + '"Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", sans-serif ;' + '.no-mobile-tap-outline { outline: none ; -webkit-tap-highlight-color: transparent }' + 'background-color: black ; padding: 10px 13px 10px 18px ;' // bubble style + 'border-radius: 11px ; border: 1px solid #f5f5f7 ;' + 'opacity: 0 ; position: fixed ; z-index: 9999 ; font-size: 1.8rem ; color: white ;' // visibility + 'user-select: none ; -webkit-user-select: none ; -moz-user-select: none ; -o-user-select: none ;' + '-ms-user-select: none ;' + `transform: translateX(${ // init off-screen for transition fx !notificationDiv.isRight ? '-' : '' }35px) ;` + ( shadow ? `--shadow: -8px 13px 25px 0 ${ /\b(?:shadow|on)\b/i.test(shadow) ? 'gray' : shadow }; box-shadow: var(--shadow) ; -webkit-box-shadow: var(--shadow) ; -moz-box-shadow: var(--shadow)` : '' ) + '}' + `.notif-close-btn { cursor: pointer ; float: right ; position: relative ; right: -4px ; margin-left: -3px ;` + 'display: grid }' // top-align for non-OpenAI sites + '@keyframes notif-zoom-fade-out { 0% { opacity: 1 ; transform: scale(1) }' // transition out keyframes + '15% { opacity: 0.35 ; transform: rotateX(-27deg) scale(1.05) }' + '45% { opacity: 0.05 ; transform: rotateX(-81deg) }' + '100% { opacity: 0 ; transform: rotateX(-180deg) scale(1.15) }}' ) if (toast) notifStyle.textContent += ` div.chatgpt-notif { position: absolute ; left: 50% ; right: 21% !important ; text-align: center ; ${ scheme == 'dark' ? 'border: 2px solid white ;' : '' } margin-${ !notificationDiv.isTop ? 'bottom: 105px' : 'top: 42px' }; transform: translate(-50%, -50%) scale(0.6) !important } div.chatgpt-notif > div.notif-close-btn { top: 18px ; right: 7px ; transform: scale(2) }` } // Enqueue notification let notifyProps = JSON.parse(localStorage.notifyProps ??= JSON.stringify({ queue: { topRight: [], bottomRight: [], bottomLeft: [], topLeft: [] }})) notifyProps.queue[notificationDiv.quadrant].push(notificationDiv.id) localStorage.notifyProps = JSON.stringify(notifyProps) // Position notification (defaults to top-right) notificationDiv.style.top = notificationDiv.isTop ? vpYoffset.toString() + 'px' : '' notificationDiv.style.bottom = !notificationDiv.isTop ? vpYoffset.toString() + 'px' : '' notificationDiv.style.right = notificationDiv.isRight ? vpXoffset.toString() + 'px' : '' notificationDiv.style.left = !notificationDiv.isRight ? vpXoffset.toString() + 'px' : '' // Re-position old notifications const thisQuadrantQueue = notifyProps.queue[notificationDiv.quadrant] if (thisQuadrantQueue.length > 1) { try { // to move old notifications for (const divID of thisQuadrantQueue.slice(0, -1)) { // exclude new div const oldDiv = document.getElementById(divID) ; if (!oldDiv) break const offsetProp = oldDiv.style.top ? 'top' : 'bottom' // pick property to change const vOffset = +parseInt(oldDiv.style[offsetProp]) +5 + oldDiv.getBoundingClientRect().height oldDiv.style[offsetProp] = `${vOffset}px` // change prop } } catch (err) { console.warn('Failed to re-position notification:', err) } } // Show notification setTimeout(() => { notificationDiv.style.opacity = scheme == 'dark' ? 0.8 : 0.67 // show msg notificationDiv.style.transform = 'translateX(0)' // bring from off-screen notificationDiv.style.transition = 'transform 0.15s ease, opacity 0.15s ease' }, 10) // Init delay before hiding const hideDelay = fadeDuration > notifDuration ? 0 // don't delay if fade exceeds notification duration : notifDuration - fadeDuration // otherwise delay for difference // Add notification dismissal to timeout schedule + button clicks const dismissNotif = () => { notificationDiv.style.animation = `notif-zoom-fade-out ${fadeDuration}s ease-out` clearTimeout(dismissFuncTID) } const dismissFuncTID = setTimeout(dismissNotif, hideDelay * 1000) // maintain visibility for `hideDelay` secs, then dismiss closeSVG.onclick = dismissNotif // add to close button clicks // Destroy notification notificationDiv.onanimationend = () => { notificationDiv.remove() // remove from DOM notifyProps = JSON.parse(localStorage.notifyProps) notifyProps.queue[notificationDiv.quadrant].shift() // + memory localStorage.notifyProps = JSON.stringify(notifyProps) // + storage } return notificationDiv }, cjsRenderHTML(node) { const reTags = /<([a-z\d]+)\b([^>]*)>([\s\S]*?)<\/\1>/g, reAttrs = /(\S+)=['"]?((?:.(?!['"]?\s+\S+=|[>']))+.)['"]?/g, // eslint-disable-line nodeContent = node.childNodes // Preserve consecutive spaces + line breaks if (!feedback.cjsRenderHTML.preWrapSet) { node.style.whiteSpace = 'pre-wrap' ; feedback.cjsRenderHTML.preWrapSet = true setTimeout(() => feedback.cjsRenderHTML.preWrapSet = false, 100) } // Process child nodes for (const childNode of nodeContent) { // Process text node if (childNode.nodeType == Node.TEXT_NODE) { const text = childNode.nodeValue, elems = [...text.matchAll(reTags)] // Process 1st element to render if (elems.length) { const elem = elems[0], [tagContent, tagName, tagAttrs, tagText] = elem.slice(0, 4), tagNode = document.createElement(tagName) ; tagNode.textContent = tagText // Extract/set attributes const attrs = [...tagAttrs.matchAll(reAttrs)] attrs.forEach(attr => { const name = attr[1], val = attr[2].replace(/['"]/g, '') tagNode.setAttribute(name, val) }) const renderedNode = feedback.cjsRenderHTML(tagNode) // render child elems of newly created node // Insert newly rendered node const beforeTextNode = document.createTextNode(text.substring(0, elem.index)), afterTextNode = document.createTextNode(text.substring(elem.index + tagContent.length)) // Replace text node with processed nodes node.replaceChild(beforeTextNode, childNode) node.insertBefore(renderedNode, beforeTextNode.nextSibling) node.insertBefore(afterTextNode, renderedNode.nextSibling) } // Process element nodes recursively } else if (childNode.nodeType == Node.ELEMENT_NODE) feedback.cjsRenderHTML(childNode) } return node // if assignment used }, notify(msg, pos = '', notifDuration = '', shadow = '') { // requires dom.js if (app.config.notifDisabled && !msg.includes(settings.controls.notifDisabled.label)) return // Strip state word to append colored one later const foundState = toolbarMenu.state.words.find(word => msg.includes(word)) if (foundState) msg = msg.replace(foundState, '') // Show notification this.cjsNotify(`${app.symbol} ${msg}`, pos, notifDuration, shadow || ui.getScheme() == 'dark' ? '' : 'shadow') const notif = document.querySelector('.chatgpt-notif:last-child') // Tweak styles notif.style.fontSize = '385%' if (foundState) { // append styled state word const styledStateSpan = dom.create.elem('span', { style: `color: ${ foundState == toolbarMenu.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) } } } window.modals = { // requires .js + stack: [], // of types of undismissed modals get class() { return `${app.slug}-modal` }, get runtime() { return typeof GM_info != 'undefined' ? 'greasemonkey' : navigator.userAgent.includes('Firefox') ? 'firefox' : 'chromium' }, about() { // requires const { browser: { isCompact }} = env, scheme = ui.getScheme() // Init buttons const modalBtns = [ function getSupport(){}, function rateUs(){}, function moreUserscripts(){} ] if (this.runtime == 'greasemonkey') // add Check for Updates modalBtns.unshift(function checkForUpdates(){ updateCheck() }) // Show modal const labelStyles = 'text-transform: uppercase ; font-size: 17px ; font-weight: bold ;' + `color: ${ scheme == 'dark' ? 'white' : '#494141' }` const aboutModal = modals.alert( `${app.symbol} ${i18n.getMsg('appName')}`, // title `🧠 ${i18n.getMsg('about_author')}: ` + `${i18n.getMsg('appAuthor')} ` + `${i18n.getMsg('about_and')} ${i18n.getMsg('about_contributors')}\n` + `🏷️ ${i18n.getMsg('about_version')}: ` + `${app.version}\n` + `📜 ${i18n.getMsg('about_openSourceCode')}: ` + `` + app.urls.github + '\n' + `🚀 ${i18n.getMsg('about_latestChanges')}: ` + `` + `${app.urls.github}/commits/main/${this.runtime}`, modalBtns, '', 747 ) // Format text aboutModal.querySelector('h2').style.cssText = ` text-align: center ; font-size: 51px ; line-height: 46px ; padding: 15px 0` aboutModal.querySelector('p').style.cssText = ` text-align: center ; overflow-wrap: anywhere ; margin: ${ isCompact ? '6px 0 -16px' : '3px 0 29px' }` // Hack buttons aboutModal.querySelector('.modal-buttons').style.justifyContent = 'center' aboutModal.querySelectorAll('button').forEach(btn => { btn.style.cssText = 'min-width: 136px ; text-align: center ;' + `height: ${ this.runtime == 'greasemonkey' ? 58 : 55 }px` // Replace link buttons w/ clones that don't dismiss modal if (/support|rateus|userscripts/i.test(btn.textContent)) { btn.replaceWith(btn = btn.cloneNode(true)) btn.onclick = () => this.safeWinOpen( btn.textContent.includes(i18n.getMsg('btnLabel_getSupport')) ? app.urls.support : btn.textContent.includes(i18n.getMsg('btnLabel_rateUs')) ? app.urls.review.scriptcat : app.urls.userscripts ) } // Prepend emoji + localize labels if (/updates/i.test(btn.textContent)) btn.textContent = `🚀 ${i18n.getMsg('btnLabel_checkForUpdates')}` else if (/support/i.test(btn.textContent)) btn.textContent = `🧠 ${i18n.getMsg('btnLabel_getSupport')}` else if (/rateus/i.test(btn.textContent)) btn.textContent = `⭐ ${i18n.getMsg('btnLabel_rateUs')}` else if (/userscripts/i.test(btn.textContent)) btn.textContent = `🤖 ${i18n.getMsg('btnLabel_moreUserscripts')}` // Hide Dismiss button else btn.style.display = 'none' }) return aboutModal }, alert(title = '', msg = '', btns = '', checkbox = '', width = '') { // generic one from feedback.cjsAlert() const alertID = feedback.cjsAlert(title, msg, btns, checkbox, width), alert = document.getElementById(alertID).firstChild this.init(alert) // add classes + rising particles bg return alert }, init(modal) { // requires lib/.js this.stylize() modal.classList.add(this.class) ; modal.parentNode.classList.add(`${this.class}-bg`) css.addRisingParticles(modal) }, observeRemoval(modal, modalType, modalSubType) { // to maintain stack for proper nav const modalBG = modal.parentNode new MutationObserver(([mutation], obs) => { mutation.removedNodes.forEach(removedNode => { if (removedNode == modalBG) { if (this.stack[0].includes(modalSubType || modalType)) { // new modal not launched so nav back this.stack.shift() // remove this modal type from stack 1st const prevModalType = this.stack[0] if (prevModalType) { // open it this.stack.shift() // remove type from stack since re-added on open this.open(prevModalType) } } obs.disconnect() }}) }).observe(modalBG.parentNode, { childList: true, subtree: true }) }, open(modalType, modalSubType) { const modal = modalSubType ? this[modalType][modalSubType]() : this[modalType]() // show modal if (!modal) return // since no div returned this.stack.unshift(modalSubType ? `${modalType}_${modalSubType}` : modalType) // add to stack this.init(modal) // add classes + rising particles bg this.observeRemoval(modal, modalType, modalSubType) // to maintain stack for proper nav }, safeWinOpen(url) { open(url, '_blank', 'noopener') }, // to prevent backdoor vulnerabilities stylize() { // requires lib/dom.js + env const { browser: { isMobile }} = env, scheme = ui.getScheme() if (!this.styles?.isConnected) document.head.append(this.styles ||= dom.create.style()) this.styles.textContent = ` .${this.class} { /* modals */ user-select: none ; -webkit-user-select: none ; -moz-user-select: none ; -ms-user-select: none ; font-family: -apple-system, system-ui, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen-Sans, Ubuntu, Cantarell, Helvetica Neue, sans-serif ; padding: 20px 25px 24px 25px !important ; font-size: 20px ; color: ${ scheme == 'dark' ? 'white' : 'black' } !important ; background-image: linear-gradient(180deg, ${ scheme == 'dark' ? '#99a8a6 -200px, black 200px' : '#b6ebff -296px, white 171px' }) ; border-radius: 0 } .${this.class} [class*=modal-close-btn] { position: absolute !important ; float: right ; top: 14px !important ; right: 16px !important ; cursor: pointer ; width: 33px ; height: 33px ; border-radius: 20px } .${this.class} [class*=modal-close-btn] svg { height: 10px } .${this.class} [class*=modal-close-btn] path { ${ scheme == 'dark' ? 'stroke: white ; fill: white' : 'stroke: #9f9f9f ; fill: #9f9f9f' }} ${ scheme == 'dark' ? // invert dark mode hover paths `.${this.class} [class*=modal-close-btn]:hover path { stroke: black ; fill: black }` : '' } .${this.class} [class*=modal-close-btn]:hover { background-color: #f2f2f2 } /* hover underlay */ .${this.class} [class*=modal-close-btn] svg { margin: 11.5px } /* center SVG for hover underlay */ .${this.class} a { color: #${ scheme == 'dark' ? '00cfff' : '1e9ebb' } !important } .${this.class} a:hover { text-decoration: none ; opacity: 0.7 ; transition: 0.15s ease } .${this.class} h2 { font-weight: bold } .${this.class} button { --btn-transition: transform 0.1s ease-in-out, box-shadow 0.1s ease-in-out ; font-size: 14px ; text-transform: uppercase ; /* shrink/uppercase labels */ border-radius: 0 !important ; /* square borders */ transition: var(--btn-transition) ; /* smoothen hover fx */ -webkit-transition: var(--btn-transition) ; -moz-transition: var(--btn-transition) ; -o-transition: var(--btn-transition) ; -ms-transition: var(--btn-transition) ; cursor: pointer !important ; /* add finger cursor */ border: 1px solid ${ scheme == 'dark' ? 'white' : 'black' } !important ; padding: 8px !important ; min-width: 102px /* resize */ } .${this.class} button:not([class*=primary]) { background: none } .${this.class} button:hover { ${ scheme == 'light' ? // reduce intensity of light scheme hover glow '--btn-shadow: 2px 1px 43px #00cfff70 ;' : '' } color: inherit !important ; /* remove color hack */ background-color: rgb(${ scheme == 'light' ? '192 223 227 / 5%' : '43 156 171 / 43%' }) } ${ !isMobile ? `.${this.class} .modal-buttons { margin-left: -13px !important }` : '' } .about-em { color: ${ scheme == 'dark' ? 'white' : 'green' } !important }` }, update: { width: 377, available() { // Show modal const updateAvailModal = modals.alert(`🚀 ${app.msgs.alert_updateAvail}!`, // title `${app.msgs.alert_newerVer} ${app.msgs.appName} ` // msg + `(v${app.latestVer}) ${app.msgs.alert_isAvail}! ` + '${app.msgs.link_viewChanges}`, function update() { // button modals.safeWinOpen(`${app.urls.update.gm}?t=${Date.now()}`) }, '', modals.update.width ) // Localize button labels if needed if (!env.browser.language.startsWith('en')) { const updateBtns = updateAvailModal.querySelectorAll('button') updateBtns[1].textContent = app.msgs.btnLabel_update updateBtns[0].textContent = app.msgs.btnLabel_dismiss } return updateAvailModal }, unavailable() { return modals.alert(`${app.msgs.alert_upToDate}!`, // title `${app.msgs.appName} (v${app.version}) ${app.msgs.alert_isUpToDate}!`, // msg '', '', modals.update.width ) } } } window.toolbarMenu = { state: { symbols: ['❌', '✔️'], separator: env.scriptManager.name == 'Tampermonkey' ? ' — ' : ': ', words: [app.msgs.state_off.toUpperCase(), app.msgs.state_on.toUpperCase()] }, refresh() { if (typeof GM_unregisterMenuCommand == 'undefined') return this.entryIDs.forEach(id => GM_unregisterMenuCommand(id)) this.register() }, register() { // Add mode/settings toggles this.entryIDs = Object.keys(settings.controls).map(key => { const ctrl = settings.controls[key] const menuLabel = `${ ctrl.symbol || this.state.symbols[+settings.typeIsEnabled(key)] } ${ctrl.label} ${ ctrl.type == 'toggle' ? this.state.separator + this.state.words[+settings.typeIsEnabled(key)] : ctrl.type == 'slider' ? ': ' + app.config[key] + ctrl.labelSuffix || '' : ctrl.status ? ` — ${ctrl.status}` : '' }` return GM_registerMenuCommand(menuLabel, () => { settings.save(key, !app.config[key]) ; sync.configToUI({ updatedKey: key }) feedback.notify(`${ctrl.label}: ${this.state.words[+settings.typeIsEnabled(key)]}`) }, env.scriptManager.supportsTooltips ? { title: ctrl.helptip || ' ' } : undefined) }) // Add About entry this.entryIDs.push(GM_registerMenuCommand( `💡 ${app.msgs.menuLabel_about} ${app.msgs.appName}`, () => modals.open('about'), env.scriptManager.supportsTooltips ? { title: ' ' } : undefined )) } } window.styles = { update({ key, keys, append }) { // requires dom.js if (!key && !keys) return console.error('Option \'key\' or \'keys\' required by styles.update()') ;[].concat(keys || key).forEach(key => { const style = this[key] ; style.node ||= dom.create.style() style.node.textContent = style.css if ((append ?? style.autoAppend) && !style.node.isConnected) document.head.append(style.node) }) }, block: { autoAppend: true, get css() { return Object.entries(app.selectors.block) .map(([key, selectors]) => !app.config[`${key}Block`] ? '' : `${css.selectors.extract(selectors).join(',')} { display: none !important }` ).join('') } }, dislikes: { autoAppend: true, get css() { return app.config.restoreDislikes ? '' : ` dislike-button-view-model, like-button-view-model button::after { /* Like btn right sep */ display: none !important }` } }, tweaks: { autoAppend: true, get css() { return ` /* Revert old background color and buttons */ html[dark] { --yt-spec-general-background-a: #181818 !important ; --yt-spec-general-background-b: #0f0f0f !important ; --yt-spec-brand-background-primary: rgba(33,33,33,0.98) !important ; --yt-spec-10-percent-layer: rgba(255,255,255,0.1) !important } html:not([dark]) { --yt-spec-general-background-a: #f9f9f9 !important ; --yt-spec-general-background-b: #f1f1f1 !important ; --yt-spec-brand-background-primary: rgba(255,255,255,0.98) !important ; --yt-spec-10-percent-layer: rgba(0,0,0,0.1) !important } /* Un-segment engagement buttons below vid https://github.com/adamlui/youtube-classic/issues/10 */ :where(segmented-like-dislike-button-view-model, yt-button-view-model) button { background: none !important } ytd-masthead { background: var(--yt-spec-brand-background-solid) !important } ytd-app { background: var(--yt-spec-general-background-a) !important } ytd-browse[page-subtype="channels"] { background: var(--yt-spec-general-background-b) !important } ytd-c4-tabbed-header-renderer { --yt-lightsource-section1-color: var(--yt-spec-general-background-a) !important } ytd-mini-guide-renderer, ytd-mini-guide-entry-renderer { background-color: var(--yt-spec-brand-background-solid) !important } #cinematics.ytd-watch-flexy { display: none !important } #tabs-divider.ytd-c4-tabbed-header-renderer { border-bottom: 0px !important } #header.ytd-rich-grid-renderer { width: 100% !important } [page-subtype="home"] #chips-wrapper.ytd-feed-filter-chip-bar-renderer { background-color: var(--yt-spec-brand-background-primary) !important ; border-top: 1px solid var(--yt-spec-10-percent-layer) !important ; border-bottom: 1px solid var(--yt-spec-10-percent-layer) !important } ytd-feed-filter-chip-bar-renderer[is-dark-theme] #left-arrow.ytd-feed-filter-chip-bar-renderer::after { background: linear-gradient( to right, var(--yt-spec-brand-background-primary) 20%, rgba(33,33,33,0) 80%) !important } ytd-feed-filter-chip-bar-renderer[is-dark-theme] #right-arrow.ytd-feed-filter-chip-bar-renderer::before { background: linear-gradient( to left, var(--yt-spec-brand-background-primary) 20%, rgba(33,33,33,0) 80%) !important } ytd-feed-filter-chip-bar-renderer :where(#left-arrow-button, #right-arrow-button).ytd-feed-filter-chip-bar-renderer { background-color: var(--yt-spec-brand-background-primary) !important } yt-chip-cloud-renderer[is-dark-theme] #right-arrow.yt-chip-cloud-renderer::before { background: linear-gradient(to left, var(--ytd-chip-cloud-background, var(--yt-spec-general-background-a)) 10%, rgba(24,24,24,0) 90%) !important } yt-chip-cloud-renderer :where(#left-arrow-button, #right-arrow-button).yt-chip-cloud-renderer { background: var(--ytd-chip-cloud-background, var(--yt-spec-general-background-a)) !important } yt-chip-cloud-renderer[is-dark-theme] #left-arrow.yt-chip-cloud-renderer::after { background: linear-gradient(to right, var(--ytd-chip-cloud-background, var(--yt-spec-general-background-a)) 10%, rgba(24,24,24,0) 90%) !important } yt-chip-cloud-renderer #left-arrow.yt-chip-cloud-renderer::after { background: linear-gradient( to right, var(--ytd-chip-cloud-background, var(--yt-spec-general-background-a)) 10%, rgba(249,249,249,0) 90% ) !important } yt-chip-cloud-renderer #right-arrow.yt-chip-cloud-renderer::before { background: linear-gradient( to left, var(--ytd-chip-cloud-background, var(--yt-spec-general-background-a)) 10%, rgba(249,249,249,0) 90% ) !important } ytd-feed-filter-chip-bar-renderer[component-style="FEED_FILTER_CHIP_BAR_STYLE_TYPE_HASHTAG_LANDING_PAGE"] #chips-wrapper.ytd-feed-filter-chip-bar-renderer, ytd-feed-filter-chip-bar-renderer[component-style="FEED_FILTER_CHIP_BAR_STYLE_TYPE_CHANNEL_PAGE_GRID"] #chips-wrapper.ytd-feed-filter-chip-bar-renderer { background-color: var(--yt-spec-general-background-b) !important } ytd-feed-filter-chip-bar-renderer:where( [component-style="FEED_FILTER_CHIP_BAR_STYLE_TYPE_HASHTAG_LANDING_PAGE"], [component-style="FEED_FILTER_CHIP_BAR_STYLE_TYPE_CHANNEL_PAGE_GRID"] ) #chips-wrapper.ytd-feed-filter-chip-bar-renderer { background-color: var(--yt-spec-general-background-b) !important } yt-chip-cloud-chip-renderer { height: 32px !important ; border: 1px solid var(--yt-spec-10-percent-layer) !important ; border-radius: 16px !important ; box-sizing: border-box !important } /* Remove rounded corners on buttons and boxes */ #container.ytd-searchbox { background-color: var(--ytd-searchbox-background) !important ; border-radius: 2px 0 0 2px !important ; box-shadow: inset 0 1px 2px var(--ytd-searchbox-legacy-border-shadow-color) !important ; color: var(--ytd-searchbox-text-color) !important ; padding: 2px 6px !important } ytd-searchbox[desktop-searchbar-style="rounded_corner_dark_btn"] #searchbox-button.ytd-searchbox { display: none !important } ytd-searchbox[desktop-searchbar-style="rounded_corner_light_btn"] #searchbox-button.ytd-searchbox { display: none !important } #search[has-focus] #search-input { margin-left: 32px !important } #search-icon-legacy.ytd-searchbox { display: block !important ; border-radius: 0px 2px 2px 0px !important } .sbsb_a { border-radius: 2px !important } .sbsb_c { padding-left: 10px !important } div.sbqs_c::before { margin-right: 10px !important } ytd-searchbox[has-focus] #search-icon.ytd-searchbox { padding-left: 10px !important ; padding-right: 10px !important } #voice-search-button.ytd-masthead { background-color: var(--yt-spec-general-background-a) !important ; margin-left: 4px !important } #guide-content.ytd-app { background: var(--yt-spec-brand-background-solid) !important } a#endpoint.yt-simple-endpoint.style-scope.ytd-mini-guide-entry-renderer { margin: 0px !important } ytd-guide-entry-renderer[guide-refresh] { width: 100% !important ; border-radius: 0px !important } tp-yt-paper-item.ytd-guide-entry-renderer { --paper-item-focused-before-border-radius: 0px !important } ytd-guide-section-renderer.style-scope.ytd-guide-renderer { padding-left: 0px !important } ytd-mini-guide-renderer[guide-refresh] { padding: 0 !important } tp-yt-paper-item.style-scope.ytd-guide-entry-renderer { border-radius: 0px !important ; padding-left: 24px !important } #guide-section-title.ytd-guide-section-renderer { color: var(--yt-spec-text-secondary) !important ; padding: 8px 24px !important ; font-size: var(--ytd-tab-system-font-size) !important ; font-weight: var(--ytd-tab-system-font-weight) !important ; letter-spacing: var(--ytd-tab-system-letter-spacing) !important ; text-transform: var(--ytd-tab-system-text-transform) !important } .style-scope.ytd-rich-item-renderer { border-radius: 2px !important } #tooltip.tp-yt-paper-tooltip { border-radius: 2px !important } .style-scope.ytd-topic-link-renderer { border-radius: 2px !important } .bold.style-scope.yt-formatted-string { font-family: Roboto !important } .style-scope.yt-formatted-string { font-family: Roboto !important } #bar { border-radius: 2px !important } ytd-multi-page-menu-renderer { border-radius: 0px !important ; border: 1px solid var(--yt-spec-10-percent-layer) !important ; border-top: none !important ; box-shadow: none !important } yt-dropdown-menu { --paper-menu-button-content-border-radius: 2px !important } ytd-menu-popup-renderer { border-radius: 2px !important } .style-scope.ytd-feed-nudge-renderer { border-radius: 2px !important } .style-scope.ytd-inline-survey-renderer { border-radius: 2px !important} tp-yt-paper-button#button.style-scope.ytd-button-renderer.style-inactive-outline.size-default { border-radius: 2px !important } ytd-thumbnail-overlay-toggle-button-renderer.style-scope.ytd-thumbnail { border-radius: 2px !important } ytd-compact-link-renderer.ytd-settings-sidebar-renderer { margin: 0px !important ; border-radius: 0 !important } ytd-compact-link-renderer[compact-link-style=compact-link-style-type-settings-sidebar] tp-yt-paper-item.ytd-compact-link-renderer { padding-left: 24px !important ; padding-right: 24px !important } img#img.style-scope.yt-image-shadow { border-radius: 50px !important } #title.style-scope.ytd-feed-nudge-renderer { font-family: Roboto !important } yt-chip-cloud-chip-renderer.style-scope.ytd-feed-nudge-renderer { border-radius: 50px !important } div#label-container.style-scope.ytd-thumbnail-overlay-toggle-button-renderer { border: 2px !important ; text-transform: uppercase !important } ytd-thumbnail-overlay-time-status-renderer.style-scope.ytd-thumbnail { border-radius: 2px !important } ytd-backstage-post-dialog-renderer { border-radius: 2px !important } yt-bubble-hint-renderer { border-radius: 2px !important } #top-row.ytd-watch-metadata > div#actions.item.style-scope.ytd-watch-metadata > div#actions-inner.style-scope.ytd-watch-metadata > div#menu.style-scope.ytd-watch-metadata > ytd-menu-renderer.style-scope.ytd-watch-metadata > div#top-level-buttons-computed.top-level-buttons.style-scope.ytd-menu-renderer > ytd-button-renderer, #top-row.ytd-watch-metadata > div#actions.item.style-scope.ytd-watch-metadata > div#actions-inner.style-scope.ytd-watch-metadata > div#menu.style-scope.ytd-watch-metadata > ytd-menu-renderer.style-scope.ytd-watch-metadata > div#flexible-item-buttons.style-scope.ytd-menu-renderer > ytd-button-renderer, #top-row.ytd-watch-metadata > div#actions.item.style-scope.ytd-watch-metadata > div#actions-inner.style-scope.ytd-watch-metadata > div#menu.style-scope.ytd-watch-metadata > ytd-menu-renderer.style-scope.ytd-watch-metadata > div#top-level-buttons-computed.top-level-buttons.style-scope.ytd-menu-renderer > ytd-segmented-like-dislike-button-renderer.style-scope.ytd-menu-renderer > yt-smartimation.style-scope.ytd-segmented-like-dislike-button-renderer > div#segmented-buttons-wrapper.style-scope.ytd-segmented-like-dislike-button-renderer > div#segmented-like-button.style-scope.ytd-segmented-like-dislike-button-renderer > ytd-toggle-button-renderer { text-transform: capitalize !important } #top-row.ytd-watch-metadata > div#actions.item.style-scope.ytd-watch-metadata > div#actions-inner.style-scope.ytd-watch-metadata > div#menu.style-scope.ytd-watch-metadata > ytd-menu-renderer.style-scope.ytd-watch-metadata > div#top-level-buttons-computed.top-level-buttons.style-scope.ytd-menu-renderer > ytd-segmented-like-dislike-button-renderer.style-scope.ytd-menu-renderer > yt-smartimation.style-scope.ytd-segmented-like-dislike-button-renderer > div#segmented-buttons-wrapper.style-scope.ytd-segmented-like-dislike-button-renderer > div#segmented-dislike-button.style-scope.ytd-segmented-like-dislike-button-renderer > ytd-toggle-button-renderer.style-scope.ytd-segmented-like-dislike-button-renderer.style-text > a.yt-simple-endpoint.style-scope.ytd-toggle-button-renderer > yt-icon-button#button.yt-simple-endpoint.style-scope.ytd-toggle-button-renderer > button#button.style-scope.yt-icon-button { width: 24px !important ; height: 24px !important } #top-row.ytd-watch-metadata > div#actions.item.style-scope.ytd-watch-metadata > div#actions-inner.style-scope.ytd-watch-metadata > div#menu.style-scope.ytd-watch-metadata > ytd-menu-renderer.style-scope.ytd-watch-metadata > div#top-level-buttons-computed.top-level-buttons.style-scope.ytd-menu-renderer > ytd-segmented-like-dislike-button-renderer.style-scope.ytd-menu-renderer > yt-smartimation.style-scope.ytd-segmented-like-dislike-button-renderer > div#segmented-buttons-wrapper.style-scope.ytd-segmented-like-dislike-button-renderer > div#segmented-dislike-button.style-scope.ytd-segmented-like-dislike-button-renderer > ytd-toggle-button-renderer.style-scope.ytd-segmented-like-dislike-button-renderer.style-text > a.yt-simple-endpoint.style-scope.ytd-toggle-button-renderer > yt-icon-button#button.yt-simple-endpoint.style-scope.ytd-toggle-button-renderer { padding: 6px !important } ytd-watch-metadata[modern-metapanel] #description.ytd-watch-metadata, #description.ytd-watch-metadata { background-color: transparent !important ; border-radius: 0px !important } ytd-watch-metadata[modern-metapanel] #description-inner.ytd-watch-metadata, #description-inner.ytd-watch-metadata { margin: 0px !important } ytd-watch-metadata[modern-metapanel-order] #comment-teaser.ytd-watch-metadata, #comment-teaser.ytd-watch-metadata { border: 1px solid var(--yt-spec-10-percent-layer) !important ; border-radius: 4px !important } ytd-comments-entry-point-header-renderer[modern-metapanel], #comment-teaser.ytd-watch-metadata { background-color: transparent !important } div#title.text-shell.skeleton-bg-color { border-radius: 2px !important } div#count.text-shell.skeleton-bg-color { border-radius: 2px !important } div#owner-name.text-shell.skeleton-bg-color { border-radius: 2px !important } div#published-date.text-shell.skeleton-bg-color { border-radius: 2px !important } div.rich-video-title.text-shell.skeleton-bg-color { border-radius: 2px !important } div.rich-video-meta.text-shell.skeleton-bg-color { border-radius: 2px !important } ytd-video-view-count-renderer { font-size: 1.4rem !important } #meta #avatar { width: 48px ; height: 48px ; margin-right: 16px } #meta #avatar img { width: 100% } #channel-name.ytd-video-owner-renderer { font-size: 1.4rem !important } #info.ytd-video-primary-info-renderer { height: 40px !important } ytd-merch-shelf-renderer { background-color: transparent !important } div#clarify-box.attached-message.style-scope.ytd-watch-flexy { margin-top: 0px !important } ytd-clarification-renderer.style-scope:where(.ytd-item-section-renderer, .ytd-watch-flexy) { border: 1px solid !important ; border-color: #0000001a !important ; border-radius: 0px !important } yt-formatted-string.description.style-scope.ytd-clarification-renderer { font-size: 1.4rem !important } div.content-title.style-scope.ytd-clarification-renderer { padding-bottom: 4px !important } ytd-toggle-button-renderer.style-scope.ytd-live-chat-frame, yt-live-chat-header-renderer.style-scope.yt-live-chat-renderer { background: var(--yt-spec-brand-background-solid) !important } ytd-toggle-button-renderer.style-scope.ytd-live-chat-frame > a.yt-simple-endpoint.style-scope.ytd-toggle-button-renderer > tp-yt-paper-button.style-scope.ytd-toggle-button-renderer { padding-top: 4px !important ; padding-bottom: 4px !important } ytd-playlist-panel-renderer[modern-panels]:not([hide-header-text]) .title.ytd-playlist-panel-renderer { font-family: Roboto !important ; font-size: 1.4rem !important ; line-height: 2rem !important ; font-weight: 500 !important } ytd-tvfilm-offer-module-renderer[modern-panels] #header.ytd-tvfilm-offer-module-renderer { font-family: Roboto !important ; font-size: 1.6rem !important ; line-height: 2.2rem !important ; font-weight: 400 !important } ytd-donation-shelf-renderer[modern-panels] #header-text.ytd-donation-shelf-renderer { font-family: Roboto !important ; font-size: 1.6rem !important ; font-weight: 500 !important } .ytp-flyout-cta .ytp-flyout-cta-action-button.ytp-flyout-cta-action-button-rounded { font-family: Arial !important ; background: #167ac6 !important ; border: solid 1px transparent !important ; border-color: #167ac6 !important ; border-radius: 2px !important ; box-shadow: 0 1px 0 rgba(0,0,0,.05) !important ; font-size: 11px !important ; font-weight: 500 !important ; height: 28px !important ; margin: 0 8px 0 0 !important ; max-width: 140px !important ; padding: 0 10px !important } .ytp-ad-action-interstitial-action-button.ytp-ad-action-interstitial-action-button-rounded { background-color: #167ac6 !important ; border: none !important ; border-radius: 2px ; font-family: Roboto !important ; font-size: 23px !important ; height: 46px !important ; line-height: 46px !important ; min-width: 164px !important ; padding: 0 20px !important } .ytp-settings-menu { border-radius: 2px !important } .branding-context-container-inner.ytp-rounded-branding-context { border-radius: 2px !important } .ytp-tooltip.ytp-rounded-tooltip:not(.ytp-preview) .ytp-tooltip-text { border-radius: 2px !important } .ytp-autonav-endscreen-upnext-button.ytp-autonav-endscreen-upnext-button-rounded { border-radius: 2px !important } .ytp-videowall-still-image { border-radius: 0 !important } div.iv-card.iv-card-video.ytp-rounded-info { border-radius: 0 !important} div.iv-card.iv-card-playlist.ytp-rounded-info { border-radius: 0 !important } div.iv-card.iv-card-channel.ytp-rounded-info { border-radius: 0 !important } div.iv-card.ytp-rounded-info { border-radius: 0 !important } .ytp-tooltip.ytp-rounded-tooltip.ytp-text-detail.ytp-preview, .ytp-tooltip.ytp-rounded-tooltip.ytp-text-detail.ytp-preview .ytp-tooltip-bg { border-radius: 2px !important } @font-face { font-family: no-parens ; src: url("data:application/x-font-woff;base64,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");; unicode-range: U+0028, U+0029 } span.ytp-menu-label-secondary { font-family: "no-parens", "Roboto", sans-serif } .ytp-swatch-color-white { color: #f00 !important } .iv-branding .branding-context-container-inner { border-radius: 2px !important } .ytp-offline-slate-bar { border-radius: 2px !important } .ytp-offline-slate-button { border-radius: 2px !important } .ytp-tooltip.ytp-rounded-tooltip.ytp-preview:not(.ytp-text-detail), .ytp-tooltip.ytp-rounded-tooltip.ytp-preview:not(.ytp-text-detail) .ytp-tooltip-bg { border-radius: 2px !important } #movie_player > div.ytp-promotooltip-wrapper > div.ytp-promotooltip-container { border-radius: 2px !important } .ytp-fine-scrubbing-container { display: none !important } .ytp-progress-bar, .ytp-heat-map-container, .ytp-fine-scrubbing-container { transform: translateY(0) !important } .ytp-chrome-bottom { height: auto !important } .ytp-tooltip-edu { display: none !important } #buttons.ytd-c4-tabbed-header-renderer { flex-direction: row-reverse !important } button.yt-spec-button-shape-next.yt-spec-button-shape-next--tonal.yt-spec-button-shape-next--mono.yt-spec-button-shape-next--size-s { background-color: var(--yt-spec-badge-chip-background) !important ; color: var(--yt-spec-text-secondary) !important ; height: 25px !important ; letter-spacing: 0.5px !important ; border-radius: 2px !important ; text-transform: uppercase !important } ytd-channel-tagline-renderer { display: none !important } #avatar.ytd-c4-tabbed-header-renderer { width: 80px !important ; height: 80px !important ; margin: 0 24px 0 0 !important ; flex: none !important ; overflow: hidden !important } #avatar-editor.ytd-c4-tabbed-header-renderer { --ytd-channel-avatar-editor-size: 80px !important } #channel-name.ytd-c4-tabbed-header-renderer { margin-bottom: 0 !important } #channel-header-container.ytd-c4-tabbed-header-renderer { padding-top: 0 !important ; align-items: center !important } #inner-header-container.ytd-c4-tabbed-header-renderer { margin-top: 0 !important ; align-items: center !important } yt-formatted-string#channel-handle.style-scope.ytd-c4-tabbed-header-renderer { display: none !important } ytd-c4-tabbed-header-renderer[use-page-header-style] #channel-pronouns.ytd-c4-tabbed-header-renderer, yt-formatted-string#channel-pronouns.style-scope.ytd-c4-tabbed-header-renderer { display: none !important } #videos-count { display: none !important } .meta-item.ytd-c4-tabbed-header-renderer { display: block !important } div#channel-header-links.style-scope.ytd-c4-tabbed-header-renderer { display: none !important } ytd-c4-tabbed-header-renderer[use-page-header-style] #channel-name.ytd-c4-tabbed-header-renderer { font-size: 2.4em !important ; font-weight: 400 !important ; line-height: var(--yt-channel-title-line-height, 3rem) !important } span.delimiter.style-scope.ytd-c4-tabbed-header-renderer { display: none !important } div#meta.style-scope.ytd-c4-tabbed-header-renderer { width: auto !important } ytd-c4-tabbed-header-renderer[use-page-header-style] #inner-header-container.ytd-c4-tabbed-header-renderer { flex-direction: row !important } div.page-header-banner.style-scope.ytd-c4-tabbed-header-renderer { margin-left: 0px !important ; margin-right: 0px !important ; border-radius: 0px !important } ytd-browse[darker-dark-theme][page-subtype="playlist"], ytd-browse[darker-dark-theme][page-subtype="show"] { background-color: var(--yt-spec-general-background-b) !important} ytd-two-column-browse-results-renderer.ytd-browse[background-refresh] { background-color: var(--yt-spec-general-background-b) !important } .yt-sans-20.yt-dynamic-sizing-formatted-string, .yt-sans-22.yt-dynamic-sizing-formatted-string, .yt-sans-24.yt-dynamic-sizing-formatted-string, .yt-sans-28.yt-dynamic-sizing-formatted-string, yt-text-input-form-field-renderer[component-style="INLINE_FORM_STYLE_TITLE"][amsterdam] tp-yt-paper-input.yt-text-input-form-field-renderer .input-content.tp-yt-paper-input-container > input { font-family: "Roboto", "Arial", sans-serif !important ; font-size: 2.4rem !important ; line-height: 3.2rem !important ; font-weight: 400 !important } ytd-browse[page-subtype=playlist][amsterdam] { padding-top: 0 !important } ytd-browse[page-subtype=playlist][amsterdam] ytd-playlist-header-renderer.ytd-browse { margin-left: 0 !important ; height: calc(100vh - var(--ytd-toolbar-height)) !important } .immersive-header-container.ytd-playlist-header-renderer { margin-bottom: 0 !important ; border-radius: 0 !important } ytd-playlist-header-renderer, yt-formatted-string[has-link-only_]:not([force-default-style]) a.yt-simple-endpoint.yt-formatted-string:visited, .metadata-stats.ytd-playlist-byline-renderer, .yt-spec-button-shape-next--overlay.yt-spec-button-shape-next--text, ytd-text-inline-expander.ytd-playlist-header-renderer { color: var(--yt-spec-text-primary) !important ; --ytd-text-inline-expander-button-color: var(--yt-spec-text-primary) !important } ytd-dropdown-renderer[no-underline] tp-yt-paper-dropdown-menu-light .tp-yt-paper-dropdown-menu-light[style-target=input], tp-yt-iron-icon.tp-yt-paper-dropdown-menu-light { color: var(--yt-spec-text-primary) !important } .yt-spec-button-shape-next--overlay.yt-spec-button-shape-next--tonal, .yt-spec-button-shape-next--overlay.yt-spec-button-shape-next--filled { background: transparent !important ; color: var(--yt-spec-text-primary) !important ; border-radius: 2px !important ; text-transform: uppercase } .metadata-text-wrapper.ytd-playlist-header-renderer { --yt-endpoint-color: var(--yt-spec-text-primary) !important ; --yt-endpoint-hover-color: var(--yt-spec-text-primary) !important } div.immersive-header-background-wrapper.style-scope.ytd-playlist-header-renderer > div { background: var(--yt-spec-general-background-a) !important } #contents > ytd-playlist-video-list-renderer { background: var(--yt-spec-general-background-b) !important ; margin-right: 0px !important } ytd-browse[page-subtype=playlist][amsterdam] #alerts.ytd-browse { padding-left: 388px !important ; padding-right: 0px !important ; margin-bottom: 0 !important } ytd-alert-with-button-renderer[type=INFO], ytd-alert-with-button-renderer[type=SUCCESS] { background: var(--yt-spec-general-background-a) !important } .yt-spec-button-shape-next--overlay.yt-spec-button-shape-next--tonal { background: var(--yt-spec-base-background) } iron-input.tp-yt-paper-input > input.tp-yt-paper-input, textarea.tp-yt-iron-autogrow-textarea { color: var(--yt-spec-text-primary) !important } #labelAndInputContainer.tp-yt-paper-input-container :where(> label, > .paper-input-label) { color: var(--yt-spec-text-secondary) } .unfocused-line.tp-yt-paper-input-container, .focused-line.tp-yt-paper-input-container { border-bottom-color: var(--yt-spec-text-primary) !important } [page-subtype="history"] #channel-header.ytd-tabbed-page-header { background-color: var(--yt-spec-general-background-a) !important ; padding-top: 0 !important ; padding-bottom: 0 !important } .page-header-view-model-wiz__page-header-title--page-header-title-large { margin-top: 24px !important ; margin-bottom: 8px !important ; color: var(--yt-spec-text-primary) !important ; font-size: 1.6em !important ; line-height: 1.4em !important ; font-weight: 500 !important } #endpoint.yt-simple-endpoint.ytd-guide-entry-renderer.style-scope[title="Trending"] { display: none !important } #endpoint.yt-simple-endpoint.ytd-guide-entry-renderer.style-scope[title="Podcasts"] { display: none !important } ytd-guide-entry-renderer > a[href*="/channel/UCkYQyvc_i9hXEo4xic9Hh2g"] { display: none !important } .yt-tab-shape-wiz { padding: 0 32px !important ; margin-right: 0 !important } .yt-tab-shape-wiz__tab { font-size: 14px !important ; font-weight: 500 !important ; letter-spacing: var(--ytd-tab-system-letter-spacing) !important ; text-transform: uppercase !important } .yt-tab-group-shape-wiz__slider { display: none !important } .yt-tab-shape-wiz__tab-bar { display: none !important } yt-formatted-string.style-scope.yt-chip-cloud-chip-renderer, span.style-scope.ytd-rich-shelf-renderer { font-weight: 400 !important } span.style-scope.ytd-shelf-renderer, ytd-reel-shelf-renderer[modern-typography] #title.ytd-reel-shelf-renderer { font-size: 1.6rem !important ; font-weight: 500 !important } .count-text.ytd-comments-header-renderer { font-size: 1.6rem !important ; line-height: 2.2rem !important ; font-weight: 400 !important } ytd-item-section-renderer.style-scope.ytd-watch-next-secondary-results-renderer > div#contents.style-scope.ytd-item-section-renderer > ytd-reel-shelf-renderer.style-scope.ytd-item-section-renderer, ytd-reel-shelf-renderer.ytd-structured-description-content-renderer { display: none !important } ytd-video-description-infocards-section-renderer.style-scope.ytd-structured-description-content-renderer > #header.ytd-video-description-infocards-section-renderer, ytd-video-description-infocards-section-renderer.style-scope.ytd-structured-description-content-renderer > #action-buttons.ytd-video-description-infocards-section-renderer { display: none !important } ytd-video-description-infocards-section-renderer.style-scope.ytd-structured-description-content-renderer { border-top: 0px !important } button.ytp-button.ytp-jump-button.ytp-jump-button-enabled {display: none !important} ytd-player#ytd-player.style-scope.ytd-watch-flexy > div#container.style-scope.ytd-player > .html5-video-player > div.ytp-chrome-bottom > div.ytp-chrome-controls > div.ytp-left-controls > a.ytp-next-button.ytp-button\ { display: block !important } div#chip-bar.style-scope.ytd-search-header-renderer > yt-chip-cloud-renderer.style-scope.ytd-search-header-renderer > div#container.style-scope.yt-chip-cloud-renderer { display: none !important } #play.ytd-moving-thumbnail-renderer { color: #fff !important } /* Hide Edit your custom feed chip */ yt-chip-cloud-chip-renderer:has(path[d^="M5 0a5 5"]) { display: none } /* Fix Verified badge super big in FF vid pages (even w/o this script) */ ${ !env.browser.isFF ? '' : 'yt-metadata-badge-renderer span > div { height: 12px !important ; width: 12px !important }' } ` } }, unround: { autoAppend: true, get css() { return !app.config.unroundCorners ? '' : ` yt-thumbnail-view-model, /* homepage thumb */ yt-image-banner-view-model, /* channel banner */ div.ytPageHeaderViewModelBackground, /* playlist sidebar */ yt-content-preview-image-view-model, /* playlist sidebar thumb */ :where(div#sponsor-button, div#purchase-button, div.ytPageHeaderViewModelHeadline) button, :where(div#buttons.ytd-masthead, div#action-buttons, yt-flexible-actions-view-model) :is( button, a[class*=Button]), [class*=CollectionsStackCollectionStack], /* https://imgur.com/a/b221rzJ */ yt-video-metadata-carousel-view-model, ytd-player, ytd-playlist-panel-renderer[modern-panels]:not([within-miniplayer]) #container.ytd-guide-entry-renderer, ytd-mini-guide-entry-renderer, ytd-guide-entry-renderer:hover, .style-scope.ytd-item-section-renderer, div.style-scope.yt-tooltip-renderer, .style-scope.ytd-shared-post-renderer, div#repost-context.style-scope.ytd-shared-post-renderer, ytd-post-renderer.style-scope.ytd-shared-post-renderer, div#dismissed.style-scope.ytd-compact-video-renderer, .style-scope.ytd-brand-video-shelf-renderer, div#dismissible.style-scope.ytd-brand-video-singleton-renderer, #inline-survey-compact-video-renderer, ytd-thumbnail[size="medium"] a.ytd-thumbnail, ytd-thumbnail[size="medium"]::before, ytd-playlist-thumbnail[size="medium"] a.ytd-playlist-thumbnail, ytd-playlist-thumbnail[size="medium"]::before, ytd-playlist-thumbnail[size="large"] a.ytd-playlist-thumbnail, ytd-playlist-thumbnail[size="large"]::before, ytd-playlist-panel-renderer[modern-panels]:not([within-miniplayer]) #container.ytd-playlist-panel-renderer, div#dismissed.style-scope.ytd-rich-grid-media, ytd-thumbnail[size="large"] a.ytd-thumbnail, ytd-thumbnail[size="large"]::before, ytd-compact-link-renderer[compact-link-style=compact-link-style-type-settings-sidebar][active], tp-yt-paper-item.style-scope.ytd-compact-link-renderer::before, div.rich-thumbnail.skeleton-bg-color, ytd-rich-metadata-renderer[rounded], ytd-live-chat-frame[rounded-container], ytd-live-chat-frame[rounded-container] #show-hide-button.ytd-live-chat-frame ytd-toggle-button-renderer.ytd-live-chat-frame, iframe.style-scope.ytd-live-chat-frame, ytd-playlist-panel-renderer, ytd-donation-shelf-renderer.style-scope.ytd-watch-flexy, ytd-universal-watch-card-renderer[rounded] #header.ytd-universal-watch-card-renderer,ytd-universal-watch-card-renderer[rounded] #hero.ytd-universal-watch-card-renderer, .ytp-ad-overlay-container.ytp-rounded-overlay-ad .ytp-ad-overlay-image img, .ytp-ad-overlay-container.ytp-rounded-overlay-ad .ytp-ad-text-overlay, .ytp-ad-overlay-container.ytp-rounded-overlay-ad .ytp-ad-enhanced-overlay, .ytp-ce-video.ytp-ce-medium-round, .ytp-ce-playlist.ytp-ce-medium-round, .ytp-ce-medium-round .ytp-ce-expanding-overlay-background, .ytp-autonav-endscreen-upnext-thumbnail, .iv-card, .ytp-ce-video.ytp-ce-large-round, .ytp-ce-playlist.ytp-ce-large-round, .ytp-ce-large-round .ytp-ce-expanding-overlay-background, .ytp-flyout-cta .ytp-flyout-cta-icon.ytp-flyout-cta-icon-rounded, .ytp-player-minimized .html5-main-video, .ytp-player-minimized .ytp-miniplayer-scrim, .ytp-player-minimized.html5-video-player, ytd-miniplayer #player-container.ytd-miniplayer, ytd-miniplayer #video-container.ytd-miniplayer .video.ytd-miniplayer, ytd-miniplayer #card.ytd-miniplayer, ytd-miniplayer, ytd-channel-video-player-renderer[rounded] #player.ytd-channel-video-player-renderer, ytd-c4-tabbed-header-renderer[use-page-header-style] .page-header-banner.ytd-c4-tabbed-header-renderer, .image-wrapper.ytd-hero-playlist-thumbnail-renderer { border-radius: 0 !important } /* Subscribe button */ :is(ytd-subscribe-button-renderer, /* channel page */ yt-subscribe-button-view-model /* video page */ ) button { background-color: #cc0000 !important ; color: #fff !important ; border-radius: 2px !important ; text-transform: uppercase !important ; font-weight: 500 !important ; letter-spacing: 0.5px !important } #subscribe-button ytd-subscribe-button-renderer button.yt-spec-button-shape-next--tonal { background-color: #f2f2f2 !important ; color: #606060 !important ; border-radius: 2px !important ; text-transform: uppercase !important ; font-weight: 500 !important ; letter-spacing: 0.5px !important } #subscribe-button ytd-subscribe-button-renderer button.yt-spec-button-shape-next--tonal:hover { background-color: #e5e5e5 !important } yt-button-shape.style-scope.ytd-subscribe-button-renderer, yt-smartimation.ytd-subscribe-button-renderer, .smartimation__content, yt-smartimation.ytd-subscribe-button-renderer, .smartimation__content > __slot-el { display: flex !important } .ytp-sb-subscribe { border-radius: 2px !important ; background-color: #f00 !important ; color: #fff !important ; text-transform: uppercase !important } .ytp-sb-unsubscribe { border-radius: 2px !important ; background-color: #eee !important ; color: #606060 !important ; text-transform: uppercase !important } .ytp-sb-subscribe.ytp-sb-disabled { background-color: #f3908b !important } div#subscribe-button.skeleton-bg-color { border-radius: 4px !important } #subscribe-button ytd-subscribe-button-renderer button.yt-spec-button-shape-next--tonal { background-color: var(--yt-spec-badge-chip-background) !important ; color: var(--yt-spec-text-secondary) !important } /* Notif bell */ div.ytSmartImationsContent:has(#notification-preference-toggle-button) { /* sub/bell container */ display: flex } /* display bell right of sub btn */ div#notification-preference-button button { background: none !important } div#notification-preference-button div.ytSpecButtonShapeNextSecondaryIcon { display: none } /* hide down caret */ div#notification-preference-button span.ytIconWrapperHost div { /* color All/None */ fill: var(--yt-sys-color-baseline--mono-filled-hover) !important } div.ytSubscribeButtonViewModelContainer svg:has(path[d*="20.104999542236328"]) { filter: invert(100%) } /* whiten Personalized bell on channel */ ` } } } window.sync = { configToUI(options) { if (options?.updatedKey == 'restoreDislikes') styles.update({ key: 'dislikes' }) else if (options?.updatedKey == 'unroundCorners') styles.update({ key: 'unround' }) else if (options?.updatedKey == 'disableShorts') { if (app.config.disableShorts && !checkShortsToRedir.id) checkShortsToRedir() else if (!app.config.disableShorts && checkShortsToRedir.id) { cancelAnimationFrame(checkShortsToRedir.id) ; checkShortsToRedir.id = null } } else if (options?.updatedKey.endsWith('Block')) styles.update({ key: 'block' }) else if (options?.updatedKey == 'idlePrevention') { if (app.config.idlePrevention && !preventIdle.id) preventIdle() else if (!app.config.idlePrevention && preventIdle.id) { clearInterval(preventIdle.id) preventIdle.id = null delete document.hidden delete document.webkitHidden delete document.visibilityState delete document.webkitVisibilityState } } toolbarMenu.refresh() // prefixes/suffixes } } window.ui = { getScheme() { return document.querySelector('ytd-masthead[dark]') || window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' } } window.updateCheck = () => xhr({ method: 'GET', url: `${app.urls.update.gm}?t=${Date.now()}`, headers: { 'Cache-Control': 'no-cache' }, onload: ({ responseText }) => { // Compare versions, alert if update found app.latestVer = /@version +(.*)/.exec(responseText)?.[1] if (app.latestVer) for (let i = 0 ; i < 4 ; i++) { // loop thru subver's const currentSubVer = parseInt(app.version.split('.')[i], 10) || 0, latestSubVer = parseInt(app.latestVer.split('.')[i], 10) || 0 if (currentSubVer > latestSubVer) break // out of comparison since not outdated else if (latestSubVer > currentSubVer) // if outdated return modals.open('update', 'available') } // Alert to no update found, nav back to About modals.open('update', 'unavailable') ; modals.open('about') }}) class YTP { static observer = new MutationObserver(this.onNewScript) static _config = {} static isObject(item) { return (item && typeof item == 'object' && !Array.isArray(item)) } static mergeDeep(target, ...sources) { if (!sources.length) return target const source = sources.shift() if (this.isObject(target) && this.isObject(source)) for (const key in source) if (this.isObject(source[key])) { if (!target[key]) Object.assign(target, { [key]: {} }) this.mergeDeep(target[key], source[key]) } else Object.assign(target, { [key]: source[key] }) return this.mergeDeep(target, ...sources) } static onNewScript(mutations) { if (mutations.some(mut => mut.addedNodes.length)) YTP.bruteforce() } static start() { this.observer.observe(document, { childList: true, subtree: true }) } static stop() { this.observer.disconnect() } static bruteforce() { if (!unsafeWindow.yt?.config_) return this.mergeDeep(unsafeWindow.yt.config_, this._config) } static setExpMulti(exps) { if (!('EXPERIMENT_FLAGS' in this._config)) this._config.EXPERIMENT_FLAGS = {} this.mergeDeep(this._config.EXPERIMENT_FLAGS, exps) } } // Run MAIN routine toolbarMenu.register() if (app.config.disableShorts) checkShortsToRedir() function checkShortsToRedir() { if (location.pathname.startsWith('/shorts/')) return location.replace(`https://www.youtube.com/watch?v=${location.pathname.split('/')[2]}`) checkShortsToRedir.id = requestAnimationFrame(checkShortsToRedir) } styles.update({ keys: Object.keys(styles).filter(key => styles[key].autoAppend) }) // Update header logo app.logo = dom.create.elem('img', { style: 'margin-left: 5px', height: 65 }) new MutationObserver(updateYTlogo).observe(document.documentElement, { attributes: true, subtree: true, attributeFilter: ['dark'] }) updateYTlogo() function updateYTlogo() { const ytLogo = document.getElementById('logo-icon') ; if (!ytLogo) return const ytScheme = document.querySelector('ytd-masthead[dark]') || window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' app.logo.src = `${app.urls.images}/logos/youtube/${ytScheme}mode.png` ytLogo.textContent = '' ; ytLogo.append(app.logo) } // Tweak EXPFLAGS YTP.start() Object.keys(EXPFLAGS).filter(key => /_animated_/.test(key)) .forEach(animationKey => EXPFLAGS[animationKey] = !app.config.reduceAnimations) YTP.setExpMulti(EXPFLAGS) addEventListener('yt-page-data-updated', function handleDataUpdated() { YTP.stop() ; removeEventListener('yt-page-data-updated', handleDataUpdated) }) if (app.config.idlePrevention) preventIdle() function preventIdle() { Object.defineProperties(document, { // force page visibility hidden: { configurable: true, value: false }, webkitHidden: { configurable: true, value: false }, visibilityState: { configurable: true, value: 'visible' }, webkitVisibilityState: { configurable: true, value: 'visible' } }) preventIdle.id = setInterval(() => // send pulse document.dispatchEvent(new KeyboardEvent('keyup', { bubbles: true, cancelable: true, keyCode: 143, which: 143 })) , 60000) } })()