1document.addEventListener('DOMContentLoaded', async function () { 2 const userLang = getUserLangFromBrowser(); 3 window.userLang = userLang; 4 5 const observedElements = new Set(); 6 7 // åå§ç¿»è¯ 8 const fyelements = Array.from(document.querySelectorAll('p.title a,h2.page-title,div.video-tags-list ul li a,span.profile-name,ul.tags-list li a b')) 9 fyelements.forEach(element => { 10 if (!observedElements.has(element)) { 11 translateText(element); 12 observedElements.add(element); 13 } 14 }); 15 16 const observer = new MutationObserver(() => { 17 const newElements = Array.from(document.querySelectorAll('p.title a,h2.page-title,div.video-tags-list ul li a,span.profile-name,ul.tags-list li a b')) 18 newElements.forEach(element => { 19 if (!observedElements.has(element)) { 20 translateText(element); 21 observedElements.add(element); 22 } 23 }); 24 }); 25 26 observer.observe(document.body, { 27 childList: true, 28 subtree: true 29 }); 30}); 31 32function getUserLangFromBrowser() { 33 const langRaw = (navigator.language || '').toLowerCase(); 34 const langCode = langRaw.split('-')[0]; // å¦ "en-US" â "en" 35 36 const langMap = { 37 zh: 'zh-cn', 38 en: 'en', 39 ja: 'ja', 40 ko: 'ko', 41 fr: 'fr', 42 de: 'de', 43 es: 'es', 44 pt: 'pt', 45 ru: 'ru', 46 hi: 'hi', 47 vi: 'vi', 48 th: 'th', 49 id: 'id', 50 it: 'it', 51 tr: 'tr', 52 ar: 'ar', 53 fa: 'fa', 54 ur: 'ur', 55 pl: 'pl', 56 nl: 'nl', 57 sv: 'sv', 58 fi: 'fi', 59 da: 'da', 60 no: 'no', 61 cs: 'cs', 62 ro: 'ro', 63 hu: 'hu', 64 el: 'el', 65 uk: 'uk', 66 he: 'he', 67 ms: 'ms', 68 bn: 'bn', 69 tl: 'tl', 70 sw: 'sw', 71 bg: 'bg', 72 sk: 'sk', 73 sr: 'sr', 74 hr: 'hr', 75 sl: 'sl', 76 lv: 'lv', 77 lt: 'lt', 78 et: 'et', 79 ka: 'ka', 80 az: 'az', 81 hy: 'hy', 82 kk: 'kk', 83 uz: 'uz', 84 mn: 'mn', 85 ne: 'ne', 86 si: 'si', 87 km: 'km', 88 lo: 'lo', 89 my: 'my', 90 am: 'am', 91 tg: 'tg', 92 ky: 'ky', 93 tk: 'tk', 94 dz: 'dz', 95 dv: 'dv', 96 sm: 'sm', 97 to: 'to', 98 bi: 'bi', 99 is: 'is' 100 }; 101 102 return langMap[langCode] || 'zh-cn'; // é»è®¤ä½¿ç¨ç®ä½ä¸æ 103} 104 105 106 107function translateText(element) { 108 const textNodes = getTextNodes(element); 109 if (textNodes.length === 0) { 110 monitorElementForTextChanges(element); 111 return; 112 } 113 114 textNodes.forEach(textNode => { 115 const originalText = textNode.textContent.trim(); 116 if (!originalText) return; 117 118 const cacheKey = `translation:${window.userLang}:${originalText}`; 119 const cachedTranslation = localStorage.getItem(cacheKey); 120 if (cachedTranslation) { 121 textNode.textContent = cachedTranslation; 122 return; 123 } 124 125 requestTranslation(originalText, window.userLang) 126 .then(translatedText => { 127 textNode.textContent = translatedText; 128 localStorage.setItem(cacheKey, translatedText); 129 }) 130 .catch(err => console.error(err)); 131 }); 132} 133 134// 卿çå¬å ç´ çå 容åå 135function monitorElementForTextChanges(element) { 136 const observer = new MutationObserver(() => { 137 const textNodes = getTextNodes(element); 138 if (textNodes.length > 0) { 139 observer.disconnect(); 140 translateText(element); 141 } 142 }); 143 144 observer.observe(element, { 145 characterData: true, 146 subtree: true, 147 childList: true 148 }); 149} 150 151async function requestTranslation(originalText, lang = 'zh-cn', retries = 3) { 152 const encodedText = encodeURIComponent(originalText); 153 try { 154 const response = await fetch(`https://fy.playergo.top/lang?lang=${lang}&text=${encodedText}`); 155 const data = await response.json(); 156 if (data && data.translation) { 157 return data.translation; 158 } else if (retries > 0) { 159 return await requestTranslation(originalText, lang, retries - 1); 160 } else { 161 throw new Error(`Failed to translate: "${originalText}"`); 162 } 163 } catch (error) { 164 console.error(`Failed to translate: "${originalText}"`, error); 165 throw error; 166 } 167} 168 169function getTextNodes(element) { 170 let textNodes = []; 171 function walk(node) { 172 if (node.nodeType === Node.TEXT_NODE && node.textContent.trim()) { 173 textNodes.push(node); 174 } else if (node.nodeType === Node.ELEMENT_NODE) {
175 node.childNodes.forEach(walk); 176 } 177 } 178 179 walk(element); 180 return textNodes; 181}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.