YouTube 會員徽章及自訂表情符號圖標下載器

下載最佳畫質的YouTube在留言和聊天室中,顯示頻道的會員徽章及自訂表情符號。

  1. // ==UserScript==
  2. // @name YouTube 會員徽章及自訂表情符號圖標下載器
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0
  5. // @description 下載最佳畫質的YouTube在留言和聊天室中,顯示頻道的會員徽章及自訂表情符號。
  6. // @author ChatGPT, kkom kbro
  7. // @license MIT
  8. // @match https://youtube.com/*
  9. // @match https://www.youtube.com/*
  10. // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js
  11. // @require https://cdnjs.cloudflare.com/ajax/libs/jszip-utils/0.0.2/jszip-utils.min.js
  12. // @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js
  13. // @grant none
  14. // ==/UserScript==
  15.  
  16. (function() {
  17. 'use strict';
  18.  
  19. window.addEventListener("load", main, false);
  20.  
  21. const replacementNames = [
  22. "新規メンバー",
  23. "1か月",
  24. "2か月",
  25. "6か月",
  26. "1年",
  27. "2年",
  28. "3年",
  29. "4年",
  30. "5年"
  31. ];
  32.  
  33. const labels = {
  34. "af-ZA": {
  35. prefix: "Voorvoegsel",
  36. suffix: "Achtervoegsel",
  37. capitalize: "Kapitaliseer die eerste letter as dit met 'n letter begin",
  38. download: "Ikone aflaai!"
  39. },
  40. "az-Latn-AZ": {
  41. prefix: "Ön əlavə",
  42. suffix: "Arxa əlavə",
  43. capitalize: "Əgər hərf ilə başlayırsa, ilk hərfi böyük edin",
  44. download: "İkonu yükləyin!"
  45. },
  46. "id-ID": {
  47. prefix: "Awalan",
  48. suffix: "Akhiran",
  49. capitalize: "Jika dimulai dengan huruf, kapitalisasi huruf pertama",
  50. download: "Unduh ikon!"
  51. },
  52. "ms-MY": {
  53. prefix: "Awalan",
  54. suffix: "Akhiran",
  55. capitalize: "Jika bermula dengan huruf, besar huruf pertama",
  56. download: "Muat turun ikon!"
  57. },
  58. "bs-Latn-BA": {
  59. prefix: "Prefiks",
  60. suffix: "Sufiks",
  61. capitalize: "Ako počinje sa slovom, kapitalizuj prvo slovo",
  62. download: "Preuzmi ikonu!"
  63. },
  64. "ca-ES": {
  65. prefix: "Prefix",
  66. suffix: "Sufix",
  67. capitalize: "Si comença per una lletra, posa en majúscula la primera lletra",
  68. download: "Descarrega la icona!"
  69. },
  70. "cs-CZ": {
  71. prefix: "Předpona",
  72. suffix: "Přípona",
  73. capitalize: "Pokud začíná písmenem, velké první písmeno",
  74. download: "Stáhnout ikonu!"
  75. },
  76. "da-DK": {
  77. prefix: "Præfiks",
  78. suffix: "Suffiks",
  79. capitalize: "Hvis det starter med et bogstav, skal det første bogstav skrives med stort",
  80. download: "Hent ikon!"
  81. },
  82. "de-DE": {
  83. prefix: "Präfix",
  84. suffix: "Suffix",
  85. capitalize: "Wenn es mit einem Buchstaben beginnt, den ersten Buchstaben großschreiben",
  86. download: "Symbol herunterladen!"
  87. },
  88. "et-EE": {
  89. prefix: "Eesliide",
  90. suffix: "Tagae liide",
  91. capitalize: "Kui see algab tähega, siis suurtäht esimese tähega",
  92. download: "Laadi ikoon alla!"
  93. },
  94. "en-IN": {
  95. prefix: "Prefix",
  96. suffix: "Suffix",
  97. capitalize: "If it starts with a letter, capitalize the first letter",
  98. download: "Download icon!"
  99. },
  100. "en-GB": {
  101. prefix: "Prefix",
  102. suffix: "Suffix",
  103. capitalize: "If it starts with a letter, capitalize the first letter",
  104. download: "Download icon!"
  105. },
  106. "en": {
  107. prefix: "Prefix",
  108. suffix: "Suffix",
  109. capitalize: "If it starts with a letter, capitalize the first letter",
  110. download: "Download icon!"
  111. },
  112. "es-ES": {
  113. prefix: "Prefijo",
  114. suffix: "Sufijo",
  115. capitalize: "Si empieza con una letra, pon en mayúscula la primera letra",
  116. download: "¡Descargar ícono!"
  117. },
  118. "es-419": {
  119. prefix: "Prefijo",
  120. suffix: "Sufijo",
  121. capitalize: "Si empieza con una letra, pon en mayúscula la primera letra",
  122. download: "¡Descargar ícono!"
  123. },
  124. "es-US": {
  125. prefix: "Prefijo",
  126. suffix: "Sufijo",
  127. capitalize: "Si empieza con una letra, pon en mayúscula la primera letra",
  128. download: "¡Descargar ícono!"
  129. },
  130. "eu-ES": {
  131. prefix: "Aurkeztu",
  132. suffix: "Atzizkia",
  133. capitalize: "Letra batekin hasten bada, idatzi lehen letra nagusian",
  134. download: "Ikonoa jaitsi!"
  135. },
  136. "fil-PH": {
  137. prefix: "Paunang salita",
  138. suffix: "Sugnay",
  139. capitalize: "Kung nagsisimula ito sa isang titik, i-capitalize ang unang titik",
  140. download: "I-download ang icon!"
  141. },
  142. "fr-FR": {
  143. prefix: "Préfixe",
  144. suffix: "Suffixe",
  145. capitalize: "S'il commence par une lettre, mettre la première lettre en majuscule",
  146. download: "Télécharger l'icône !"
  147. },
  148. "fr-CA": {
  149. prefix: "Préfixe",
  150. suffix: "Suffixe",
  151. capitalize: "S'il commence par une lettre, mettre la première lettre en majuscule",
  152. download: "Télécharger l'icône !"
  153. },
  154. "gl-ES": {
  155. prefix: "Prefixo",
  156. suffix: "Sufixo",
  157. capitalize: "Se comeza cunha letra, escribe a primeira letra en maiúscula",
  158. download: "Descargar o ícono!"
  159. },
  160. "hr-HR": {
  161. prefix: "Prefiks",
  162. suffix: "Sufiks",
  163. capitalize: "Ako počinje slovom, kapitaliziraj prvo slovo",
  164. download: "Preuzmi ikonu!"
  165. },
  166. "zu-ZA": {
  167. prefix: "Isithako",
  168. suffix: "Isiphetho",
  169. capitalize: "Uma iqala ngeleta, khuphula ileta yokuqala",
  170. download: "Landa isithonjana!"
  171. },
  172. "is-IS": {
  173. prefix: "Forskeyti",
  174. suffix: "Eftirskeyti",
  175. capitalize: "Ef það byrjar á staf, skaltu stórskrifa fyrsta stafinn",
  176. download: "Sækið táknið!"
  177. },
  178. "it-IT": {
  179. prefix: "Prefisso",
  180. suffix: "Suffisso",
  181. capitalize: "Se inizia con una lettera, maiuscola la prima lettera",
  182. download: "Scarica l'icona!"
  183. },
  184. "sw-TZ": {
  185. prefix: "Kichwa",
  186. suffix: "Kiambatanishi",
  187. capitalize: "Ikiwa inaanza na herufi, inua herufi ya kwanza",
  188. download: "Pakua ikoni!"
  189. },
  190. "lv-LV": {
  191. prefix: "Priekšmets",
  192. suffix: "Pielikums",
  193. capitalize: "Ja tas sākas ar burtu, lielais pirmais burts",
  194. download: "Lejupielādēt ikonu!"
  195. },
  196. "lt-LT": {
  197. prefix: "Priešdėlis",
  198. suffix: "Priedas",
  199. capitalize: "Jei prasideda su raide, didžiuoju pirmą raide",
  200. download: "Atsisiųsti ikoną!"
  201. },
  202. "hu-HU": {
  203. prefix: "Előtag",
  204. suffix: "Utótag",
  205. capitalize: "Ha betűvel kezdődik, a nagybetűt az első betűvel",
  206. download: "Ikont letölteni!"
  207. },
  208. "nl-NL": {
  209. prefix: "Voorvoegsel",
  210. suffix: "Achtervoegsel",
  211. capitalize: "Als het begint met een letter, maak de eerste letter hoofdletter",
  212. download: "Pictogram downloaden!"
  213. },
  214. "nb-NO": {
  215. prefix: "Prefiks",
  216. suffix: "Suffiks",
  217. capitalize: "Hvis det begynner med en bokstav, kapitaliser den første bokstaven",
  218. download: "Last ned ikonet!"
  219. },
  220. "uz-Latn-UZ": {
  221. prefix: "Oldingi qo'shimcha",
  222. suffix: "Yana qo'shimcha",
  223. capitalize: "Agar harf bilan boshlangan bo'lsa, birinchi harfni katta qilib qo'ying",
  224. download: "Ikonni yuklab oling!"
  225. },
  226. "pl-PL": {
  227. prefix: "Prefiks",
  228. suffix: "Sufiks",
  229. capitalize: "Jeśli zaczyna się od litery, użyj wielkiej litery na pierwszej literze",
  230. download: "Pobierz ikonę!"
  231. },
  232. "pt-PT": {
  233. prefix: "Prefixo",
  234. suffix: "Sufixo",
  235. capitalize: "Se começar com uma letra, capitaliza a primeira letra",
  236. download: "Baixar ícone!"
  237. },
  238. "pt-BR": {
  239. prefix: "Prefixo",
  240. suffix: "Sufixo",
  241. capitalize: "Se começar com uma letra, capitaliza a primeira letra",
  242. download: "Baixar ícone!"
  243. },
  244. "ro-RO": {
  245. prefix: "Prefix",
  246. suffix: "Sufix",
  247. capitalize: "Dacă începe cu o literă, pune prima literă cu majuscule",
  248. download: "Descarcă pictograma!"
  249. },
  250. "sq-AL": {
  251. prefix: "Prefiks",
  252. suffix: "Shtesë",
  253. capitalize: "Nëse fillon me një shkronjë, shkruaj me shkronjë të madhe shkronjën e parë",
  254. download: "Shkarko ikonën!"
  255. },
  256. "sk-SK": {
  257. prefix: "Predpona",
  258. suffix: "Prípona",
  259. capitalize: "Ak začína písmenom, veľké prvé písmeno",
  260. download: "Stiahnuť ikonu!"
  261. },
  262. "sl-SI": {
  263. prefix: "Predpona",
  264. suffix: "Pripona",
  265. capitalize: "Če se začne z črko, z velikimi začetnicami",
  266. download: "Prenesi ikono!"
  267. },
  268. "sr-Latn-RS": {
  269. prefix: "Prefiks",
  270. suffix: "Sufiks",
  271. capitalize: "Ako počinje slovom, kapitalizuj prvo slovo",
  272. download: "Preuzmi ikonu!"
  273. },
  274. "fi-FI": {
  275. prefix: "Etuliite",
  276. suffix: "Loppuliite",
  277. capitalize: "Jos se alkaa kirjaimella, isolla ensimmäisellä kirjaimella",
  278. download: "Lataa ikoni!"
  279. },
  280. "sv-SE": {
  281. prefix: "Prefix",
  282. suffix: "Suffix",
  283. capitalize: "Om det börjar med en bokstav, skriv första bokstaven med stort",
  284. download: "Ladda ner ikon!"
  285. },
  286. "vi-VN": {
  287. prefix: "Tiền tố",
  288. suffix: "Hậu tố",
  289. capitalize: "Nếu bắt đầu bằng chữ cái, viết hoa chữ cái đầu tiên",
  290. download: "Tải xuống biểu tượng!"
  291. },
  292. "tr-TR": {
  293. prefix: "Önek",
  294. suffix: "Sonek",
  295. capitalize: "Eğer bir harfle başlıyorsa, ilk harfi büyük yaz",
  296. download: "İkonu indir!"
  297. },
  298. "be-BY": {
  299. prefix: "Префікс",
  300. suffix: "Суфікс",
  301. capitalize: "Калі пачынаецца з літары, напішыце першую літару з вялікай",
  302. download: "Спампаваць значок!"
  303. },
  304. "bg-BG": {
  305. prefix: "Префикс",
  306. suffix: "Суфикс",
  307. capitalize: "Ако започва с буква, направете първата буква главна",
  308. download: "Изтеглете иконата!"
  309. },
  310. "ky-KG": {
  311. prefix: "Префикс",
  312. suffix: "Суфикс",
  313. capitalize: "Эгер ал бугаардан башталса, биринчи харфин чоң кыл",
  314. download: "Иконканы жүктөө!"
  315. },
  316. "kk-KZ": {
  317. prefix: "Префикс",
  318. suffix: "Суфикс",
  319. capitalize: "Егер әріптен басталса, бірінші әріпті бас әріппен жазыңыз",
  320. download: "Иконканы жүктеңіз!"
  321. },
  322. "mk-MK": {
  323. prefix: "Префикс",
  324. suffix: "Суфикс",
  325. capitalize: "Ако започнува со буква, напиши го првото слово со голема буква",
  326. download: "Преземи икона!"
  327. },
  328. "mn-MN": {
  329. prefix: "Урьдчилсан",
  330. suffix: "Дүгнэлт",
  331. capitalize: "Хэрвээ үсэгтэй эхэлж байвал, анхны үсгийг томоор бич",
  332. download: "Икон хуулах!"
  333. },
  334. "ru-RU": {
  335. prefix: "Префикс",
  336. suffix: "Суффикс",
  337. capitalize: "Если оно начинается с буквы, сделайте первую букву заглавной",
  338. download: "Скачать иконку!"
  339. },
  340. "sr-Cyrl-RS": {
  341. prefix: "Префикс",
  342. suffix: "Суфикс",
  343. capitalize: "Ако почиње словом, капитализуј прво слово",
  344. download: "Преузми иконку!"
  345. },
  346. "uk-UA": {
  347. prefix: "Префікс",
  348. suffix: "Суфікс",
  349. capitalize: "Якщо починається з літери, напишіть першу літеру з великої",
  350. download: "Завантажити іконку!"
  351. },
  352. "el-GR": {
  353. prefix: "Πρόθεμα",
  354. suffix: "Επίθημα",
  355. capitalize: "Αν αρχίζει με γράμμα, κεφαλαιοποιήστε το πρώτο γράμμα",
  356. download: "Κατεβάστε το εικονίδιο!"
  357. },
  358. "hy-AM": {
  359. prefix: "Առաջադիմություն",
  360. suffix: "Վերջաբան",
  361. capitalize: "Եթե սկսվում է տառով, մեծացրեք առաջին տառը",
  362. download: "Բեռնել սիմվոլը!"
  363. },
  364. "he-IL": {
  365. prefix: "קידומת",
  366. suffix: "סופית",
  367. capitalize: "אם זה מתחיל באות, הכנס אות גדולה ראשונה",
  368. download: "הורד סמל!"
  369. },
  370. "ur-PK": {
  371. prefix: "پیش لفظ",
  372. suffix: "لاحقہ",
  373. capitalize: "اگر یہ کسی حرف سے شروع ہوتا ہے تو پہلے حرف کو بڑے حروف میں لکھیں",
  374. download: "آئیکن ڈاؤن لوڈ کریں!"
  375. },
  376. "ar": {
  377. prefix: "بادئة",
  378. suffix: "لاحقة",
  379. capitalize: "إذا بدأت بحرف، اجعل الحرف الأول كبيرًا",
  380. download: "تنزيل الأيقونة!"
  381. },
  382. "fa-IR": {
  383. prefix: "پیشوند",
  384. suffix: "پسوند",
  385. capitalize: "اگر با حرف شروع می‌شود، حرف اول را بزرگ کنید",
  386. download: "دانلود آیکون!"
  387. },
  388. "ne-NP": {
  389. prefix: "प्रीफिक्स",
  390. suffix: "सफिक्स",
  391. capitalize: "यदि यो अक्षरले सुरु हुन्छ भने, पहिलो अक्षरलाई ठूलो बनाउनुहोस्",
  392. download: "आइकन डाउनलोड गर्नुहोस्!"
  393. },
  394. "mr-IN": {
  395. prefix: "पूर्वसूचक",
  396. suffix: "अंतसूचक",
  397. capitalize: "जर तुमच्या अक्षराने सुरूवात केली, तर पहिल्या अक्षराला मोठा करा",
  398. download: "आइकन डाउनलोड करा!"
  399. },
  400. "hi-IN": {
  401. prefix: "पूर्ववर्ती",
  402. suffix: "उपसर्ग",
  403. capitalize: "यदि यह एक अक्षर से शुरू होता है, तो पहले अक्षर को बड़े अक्षर में करें",
  404. download: "आइकन डाउनलोड करें!"
  405. },
  406. "as-IN": {
  407. prefix: "পূৰ্বৰ অংশ",
  408. suffix: "অংশ",
  409. capitalize: "যদি এটি এখন অক্ষৰে আৰম্ভ হয়, তেনেহ'লে প্ৰথম অক্ষৰখন বৃহৎ কৰক",
  410. download: "আইকন ডাউনলোড কৰক!"
  411. },
  412. "bn-BD": {
  413. prefix: "প্রিফিক্স",
  414. suffix: "সাফিক্স",
  415. capitalize: "যদি এটি একটি অক্ষর দিয়ে শুরু হয় তবে প্রথম অক্ষরকে বড় করুন",
  416. download: "আইকন ডাউনলোড করুন!"
  417. },
  418. "pa-Guru-IN": {
  419. prefix: "ਪੂਰਵਲੇਖ",
  420. suffix: "ਲਾਗੂ",
  421. capitalize: "ਜੇ ਇਹ ਅੱਖਰ ਨਾਲ ਸ਼ੁਰੂ ਹੁੰਦਾ ਹੈ, ਤਾਂ ਪਹਿਲੇ ਅੱਖਰ ਨੂੰ ਵੱਡਾ ਕਰੋ",
  422. download: "ਆਈਕਨ ਡਾਊਨਲੋਡ ਕਰੋ!"
  423. },
  424. "gu-IN": {
  425. prefix: "પૂર્વવાહી",
  426. suffix: "અર્થશાસ્ત્ર",
  427. capitalize: "જો તે અક્ષરથી શરૂ થાય તો પ્રથમ અક્ષરને મોટા બનાવો",
  428. download: "આઇકન ડાઉનલોડ કરો!"
  429. },
  430. "or-IN": {
  431. prefix: "ପ୍ରିଫିକ୍ସ",
  432. suffix: "ସୁଫିକ୍ସ",
  433. capitalize: "ଯଦି ଏହା ଏକ ଅକ୍ଷରରୁ ଆରମ୍ଭ ହୁଏ, ତେବେ ପ୍ରଥମ ଅକ୍ଷରକୁ ବଡ ରଖନ୍ତୁ",
  434. download: "ଆଇକନ୍‌ ଡାଉନଲୋଡ୍‌ କରନ୍ତୁ!"
  435. },
  436. "ta-IN": {
  437. prefix: "முன்சொல்",
  438. suffix: "இணைப்பு",
  439. capitalize: "அது எழுத்தில் தொடங்கின், முதல் எழுத்தை பெரிய எழுத்தில் மாற்றவும்",
  440. download: "அச்சொல்லை பதிவிறக்கம் செய்க!"
  441. },
  442. "te-IN": {
  443. prefix: "ప్రీఫిక్స్",
  444. suffix: "సఫిక్స్",
  445. capitalize: "అది అక్షరంతో ప్రారంభం అయితే, మొదటి అక్షరాన్ని పెద్దదిగా చేయండి",
  446. download: "ఐకాన్ డౌన్లోడ్ చేయండి!"
  447. },
  448. "kn-IN": {
  449. prefix: "ಮೂರು",
  450. suffix: "ಅನುಕ್ರಮ",
  451. capitalize: "ಅದು ಅಕ್ಷರದಿಂದ ಪ್ರಾರಂಭವಾದರೆ, ಮೊದಲ ಅಕ್ಷರವನ್ನು ದೊಡ್ಡದಾಗಿ ಮಾಡಿ",
  452. download: "ಐಕಾನ್ ಡೌನ್‌ಲೋಡ್ ಮಾಡಿ!"
  453. },
  454. "ml-IN": {
  455. prefix: "മുൻപറഞ്ഞത്",
  456. suffix: "ശേഷം",
  457. capitalize: "അത് അക്ഷരത്തിൽ തുടങ്ങുകയാണെങ്കിൽ, ആദ്യ അക്ഷരം വലിയയാക്കി",
  458. download: "അയോൺ ഡൗൺലോഡ് ചെയ്യുക!"
  459. },
  460. "si-LK": {
  461. prefix: "පෙරපදය",
  462. suffix: "අනුපදය",
  463. capitalize: "එය අක්ෂරයකින් ආරම්භ කළහොත්, පළමු අක්ෂරය විශාල කරන්න",
  464. download: "ලොාකීකරණය කරන්න!"
  465. },
  466. "th-TH": {
  467. prefix: "คำนำ",
  468. suffix: "คำต่อท้าย",
  469. capitalize: "ถ้าเริ่มด้วยตัวอักษรให้ตัวอักษรตัวแรกเป็นตัวพิมพ์ใหญ่",
  470. download: "ดาวน์โหลดไอคอน!"
  471. },
  472. "lo-LA": {
  473. prefix: "ເຄື່ອນຄົນ",
  474. suffix: "ປ່ອນອັນ",
  475. capitalize: "ໂດຍຖ້າເລີ່ມດ້ວຍອັກສອນ ຂອງເລີ່ມສຽງດິບໃນຂອບໃນ",
  476. download: "ດາວເລີ່ອຄອນ!"
  477. },
  478. "my-MM": {
  479. prefix: "အကြောင်းအရာ",
  480. suffix: "အဆုံးသတ်",
  481. capitalize: "အက္ခရာဖြင့်စလွှတ်သည့်အခါ၊ ပထမဆုံးအက္ခရာကို အကြီးစီးရေးပါ",
  482. download: "အိုင်ကွန်းဒေါင်းလုပ်လုပ်ပါ!"
  483. },
  484. "ka-GE": {
  485. prefix: "წინადადება",
  486. suffix: "საფუძველი",
  487. capitalize: "თუ ის იწყება ასოზე, გააკეთეთ პირველი ასო დიდი",
  488. download: "დაამატეთ აიკონი!"
  489. },
  490. "am-ET": {
  491. prefix: "ቅድመ ቃል",
  492. suffix: "መደብ",
  493. capitalize: "እንደ የዕለት አይደለም፣ የመጀመሪያ ፊደል ይትወዳድር",
  494. download: "መልዕክት ይላኩ!"
  495. },
  496. "km-KH": {
  497. prefix: "គម្រូ",
  498. suffix: "សរុប",
  499. capitalize: "បើវាលើកឡើងដោយអក្សរ សូមធ្វើអក្សរដំបូងអោយធំបំផុត",
  500. download: "ទាញយកស្លាក!"
  501. },
  502. "zh-Hans-CN": {
  503. prefix: "前缀",
  504. suffix: "后缀",
  505. capitalize: "如果以字母开头则大写第一个字母",
  506. download: "下载图标!"
  507. },
  508. "zh-Hant-TW": {
  509. prefix: "前綴",
  510. suffix: "後綴",
  511. capitalize: "如果以字母開頭則大寫第一個字母",
  512. download: "下載圖標!"
  513. },
  514. "zh-Hant-HK": {
  515. prefix: "前綴",
  516. suffix: "後綴",
  517. capitalize: "如果以字母開頭則大寫第一個字母",
  518. download: "下載圖標!"
  519. },
  520. "ja-JP": {
  521. prefix: "接頭辞",
  522. suffix: "接尾辞",
  523. capitalize: "文字で始まる場合は最初の文字を大文字にする",
  524. download: "アイコンをダウンロード!"
  525. },
  526. "ko-KR": {
  527. prefix: "접두사",
  528. suffix: "접미사",
  529. capitalize: "문자로 시작하면 첫 글자를 대문자로 작성하세요",
  530. download: "아이콘 다운로드!"
  531. }
  532. };
  533.  
  534. let jsInitChecktimer = null;
  535.  
  536. function main() {
  537. jsInitChecktimer = setInterval(addDownloadButtons, 1000);
  538. }
  539.  
  540. function getFullSizeImgUrl(url) {
  541. return url.split("=").slice(0, -1).join("=") + "=s0";
  542. }
  543.  
  544. function getIconNameFromAlt(alttext, index) {
  545. if (alttext === "Custom badge for members") {
  546. alttext = null;
  547. }
  548. return alttext || "Icon_" + (index + 1);
  549. }
  550.  
  551. async function getExtensionFromURL(url) {
  552. try {
  553. let response = await fetch(url, { method: 'HEAD' });
  554. if (response.ok) {
  555. let contentType = response.headers.get('Content-Type');
  556. if (contentType) {
  557. return contentTypeToExtension(contentType);
  558. }
  559. }
  560. return 'png';
  561. } catch (error) {
  562. console.error("Failed to fetch Content-Type for URL:", url, error);
  563. return 'png';
  564. }
  565. }
  566.  
  567. function contentTypeToExtension(contentType) {
  568. const mapping = {
  569. 'image/jpeg': 'jpg',
  570. 'image/png': 'png',
  571. 'image/gif': 'gif',
  572. 'image/webp': 'webp',
  573. };
  574. return mapping[contentType] || 'png';
  575. }
  576.  
  577. function capitalizeFirstLetter(string) {
  578. return string.charAt(0).toUpperCase() + string.slice(1);
  579. }
  580.  
  581. function applyPrefixSuffix(filename, prefix, suffix, capitalize) {
  582. if (capitalize && /[a-zA-Z]/.test(filename.charAt(0))) {
  583. filename = capitalizeFirstLetter(filename);
  584. }
  585. return (prefix || '') + filename + (suffix || '');
  586. }
  587.  
  588. function extractUrls(imgs, prefix, suffix, capitalize) {
  589. const urls = [];
  590. const metadata = []; // 用來保存alt文本、url和filename的metadata
  591. const filenameCount = {}; // 用來記錄每個名稱出現的次數
  592. const firstAppearanceMap = {}; // 用來記錄每個文件名第一次出現的index和對應的url信息
  593.  
  594. for (let i = 0; i < imgs.snapshotLength; i++) {
  595. const img = imgs.snapshotItem(i);
  596. let originalFilename = getIconNameFromAlt(img.alt, i); // 使用原始名稱
  597.  
  598. let finalFilename;
  599.  
  600. // 初始化計數器
  601. if (!filenameCount[originalFilename]) {
  602. filenameCount[originalFilename] = 0; // 初始化名稱計數為 0
  603. }
  604.  
  605. // 獲取當前計數
  606. const count = filenameCount[originalFilename];
  607.  
  608. if (count === 0) {
  609. // 第一次出現,保留原始名稱,但記錄它的位置以便後續修改
  610. finalFilename = applyPrefixSuffix(originalFilename, prefix, suffix, capitalize);
  611.  
  612. // 記錄第一次出現的位置和相關信息
  613. firstAppearanceMap[originalFilename] = {
  614. index: i, // 記錄第一次出現的 index
  615. url: getFullSizeImgUrl(img.src) // 記錄對應的圖片URL
  616. };
  617. } else {
  618. // 重複出現,則根據計數獲取 replacementNames
  619. const replacementIndex = Math.min(count, replacementNames.length - 1); // 確保索引不超過範圍
  620. finalFilename = applyPrefixSuffix(replacementNames[replacementIndex], prefix, suffix, capitalize); // 使用替換名稱
  621.  
  622. // 如果是第二次出現,修改第一次的文件名
  623. if (count === 1) {
  624. const firstAppearance = firstAppearanceMap[originalFilename];
  625. if (firstAppearance) {
  626. // 將第一次的文件名更新為替換名稱的第一個
  627. urls[firstAppearance.index].filename = applyPrefixSuffix(replacementNames[0], prefix, suffix, capitalize);
  628. metadata[firstAppearance.index].altText = applyPrefixSuffix(replacementNames[0], prefix, suffix, capitalize); // 同步更新metadata的altText
  629. }
  630. }
  631. }
  632.  
  633. // 增加計數
  634. filenameCount[originalFilename]++;
  635.  
  636. // 將網址和檔名推入數組
  637. urls.push({
  638. "url": getFullSizeImgUrl(img.src),
  639. "filename": finalFilename
  640. });
  641.  
  642. // 保存metadata信息,包括最終的文件名
  643. metadata.push({
  644. "altText": finalFilename,
  645. "url": getFullSizeImgUrl(img.src)
  646. });
  647. }
  648. return { urls, metadata }; // 返回圖片數據與metadata
  649. }
  650.  
  651. function addDownloadButtons() {
  652. const iconContainerXPath = "//ytd-sponsorships-perk-renderer[descendant::img]";
  653. const iconContainers = document.evaluate(iconContainerXPath, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  654. if (iconContainers.snapshotLength !== 0) {
  655. clearInterval(jsInitChecktimer);
  656. jsInitChecktimer = null;
  657. }
  658.  
  659. // 獲取 YouTube 的介面語言
  660. const lang = document.documentElement.lang || 'en'; // 默認為英文
  661. const currentLabels = labels[lang] || labels['en']; // 如果沒有對應的語言則使用英文
  662.  
  663. for (let i = 0; i < iconContainers.snapshotLength; i++) {
  664. const container = iconContainers.snapshotItem(i);
  665. const titleResult = document.evaluate(".//yt-formatted-string[@id=\"title\"]/text()", container, null, XPathResult.STRING_TYPE, null);
  666. const sectionTitle = titleResult.stringValue || "";
  667. const header = sectionTitle.split(" ").slice(0, 2).join(" ") || "unknown";
  668.  
  669. if (container.querySelector('.download-icons-button')) continue;
  670.  
  671. // 創建前綴、後綴的輸入框和大寫切換
  672. const prefixInput = document.createElement("input");
  673. prefixInput.placeholder = currentLabels.prefix; // 設置前綴的佔位符
  674. prefixInput.style.marginRight = "5px";
  675. prefixInput.style.display = "block";
  676.  
  677. const capitalizeLabel = document.createElement("label");
  678. capitalizeLabel.style.marginRight = "5px";
  679. capitalizeLabel.style.display = "block";
  680.  
  681. const capitalizeCheckbox = document.createElement("input");
  682. capitalizeCheckbox.type = "checkbox";
  683.  
  684. // 創建描述文本並設置綠色字體
  685. const descriptionText = document.createElement("span");
  686. descriptionText.textContent = currentLabels.capitalize; // 設置描述文本
  687.  
  688. // 定義函數來找到背景色
  689. function getBackgroundColor(element) {
  690. let bgColor = window.getComputedStyle(element).backgroundColor;
  691.  
  692. // 當背景顏色是透明或者無法檢測時,繼續查找父元素
  693. while (element && (bgColor === 'rgba(0, 0, 0, 0)' || bgColor === 'transparent')) {
  694. element = element.parentElement;
  695. if (element) {
  696. bgColor = window.getComputedStyle(element).backgroundColor;
  697. } else {
  698. break;
  699. }
  700. }
  701.  
  702. return bgColor;
  703. }
  704.  
  705. // 獲取背景色(從 body 開始檢測)
  706. const backgroundColor = getBackgroundColor(document.body);
  707.  
  708. // 將背景顏色轉換為 RGB 格式
  709. function getRGBValues(color) {
  710. if (color.startsWith('rgb')) {
  711. // 如果是 rgb/rgba 顏色,解析 RGB 數值
  712. return color.match(/\d+/g).map(Number);
  713. } else if (color.startsWith('#')) {
  714. // 如果是 hex 顏色,將 hex 轉換為 RGB
  715. let hex = color.replace('#', '');
  716. if (hex.length === 3) {
  717. hex = hex.split('').map(h => h + h).join('');
  718. }
  719. const bigint = parseInt(hex, 16);
  720. return [(bigint >> 16) & 255, (bigint >> 8) & 255, bigint & 255];
  721. }
  722. return [255, 255, 255]; // 默認為白色(避免異常情況)
  723. }
  724.  
  725. const rgb = getRGBValues(backgroundColor);
  726. const brightness = (0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2]); // 計算亮度
  727.  
  728. // 根據亮度設置文本顏色
  729. descriptionText.style.color = brightness > 186 ? "black" : "white";
  730.  
  731. capitalizeLabel.appendChild(capitalizeCheckbox);
  732. capitalizeLabel.appendChild(descriptionText); // 添加描述文本
  733.  
  734. const suffixInput = document.createElement("input");
  735. suffixInput.placeholder = currentLabels.suffix; // 設置後綴的佔位符
  736. suffixInput.style.marginRight = "5px";
  737.  
  738. const btnDownload = document.createElement("button");
  739. btnDownload.innerText = currentLabels.download; // 設置按鈕文本
  740. btnDownload.className = 'download-icons-button';
  741. btnDownload.style.marginTop = '10px';
  742. btnDownload.addEventListener("click", (e) => {
  743. const prefix = prefixInput.value;
  744. const suffix = suffixInput.value;
  745. const capitalize = capitalizeCheckbox.checked;
  746. downloadIcons(container, header, prefix, suffix, capitalize);
  747. });
  748.  
  749. container.appendChild(prefixInput);
  750. container.appendChild(capitalizeLabel); // 把大寫選項移到前綴後面並包含描述
  751. container.appendChild(suffixInput);
  752. container.appendChild(btnDownload);
  753. }
  754. }
  755.  
  756. async function downloadIcons(container, header, prefix, suffix, capitalize) {
  757. const channelHandleXPath = "//*[@id=\"page-header\"]/yt-page-header-renderer/yt-page-header-view-model/div/div[1]/div/yt-content-metadata-view-model/div[1]/span";
  758. const channelHandleNode = document.evaluate(channelHandleXPath, document, null, XPathResult.STRING_TYPE, null);
  759. let channelHandle;
  760. if (!channelHandleNode || !channelHandleNode.stringValue) {
  761. channelHandle = "unknown_channel";
  762. console.log("YouTube updated the DOM again--needs update");
  763. } else {
  764. channelHandle = channelHandleNode.stringValue;
  765. }
  766. const folderName = channelHandle + "-" + header;
  767. const imgsContainer = document.evaluate(".//img", container, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  768. const { urls, metadata } = extractUrls(imgsContainer, prefix, suffix, capitalize);
  769.  
  770. const zip = new JSZip();
  771. const iconZip = zip.folder(folderName);
  772. const promises = [];
  773.  
  774. // 生成 metadata.json,保留原始的冒號 ':'
  775. const metadataJson = JSON.stringify(metadata, null, 2);
  776. iconZip.file("metadata.json", metadataJson);
  777.  
  778. for (let i = 0; i < urls.length; i++) {
  779. const iconObj = urls[i];
  780. const url = iconObj.url;
  781. const filename = iconObj.filename; // 保留原始文件名
  782.  
  783. const promise = new Promise(async (resolve, reject) => {
  784. try {
  785. const extension = await getExtensionFromURL(url);
  786. // 將文件名中的特殊字符替換為可顯示字符
  787. const sanitizedFilename = filename
  788. .replace(/\//g, '⧸')
  789. .replace(/\\/g, '\')
  790. .replace(/\?/g, '?')
  791. .replace(/%/g, '%')
  792. .replace(/\*/g, '*')
  793. .replace(/:/g, ':')
  794. .replace(/\|/g, '|')
  795. .replace(/</g, '<')
  796. .replace(/>/g, '>');
  797. const fullFilename = sanitizedFilename + "." + extension; // 最終文件名
  798.  
  799. JSZipUtils.getBinaryContent(url, function (err, data) {
  800. if (err) {
  801. reject(err);
  802. } else {
  803. iconZip.file(fullFilename, data);
  804. resolve();
  805. }
  806. });
  807. } catch (error) {
  808. reject(error);
  809. }
  810. });
  811.  
  812. promises.push(promise);
  813. }
  814.  
  815. Promise.all(promises).then(function () {
  816. zip.generateAsync({
  817. type: "blob",
  818. compression: "DEFLATE"
  819. }).then(function (blob) {
  820. saveAs(blob, folderName + ".zip");
  821. }, function (err) {
  822. alert("Failed. See the log for details.");
  823. console.log(err);
  824. });
  825. }).catch(function(error) {
  826. alert("An error occurred during the download process. See the log for details.");
  827. console.error(error);
  828. });
  829. }
  830. })();

QingJ © 2025

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