en ch
Browse files- youtube_sub.js +83 -2
youtube_sub.js
CHANGED
|
@@ -661,6 +661,12 @@ GM_addStyle(`
|
|
| 661 |
this.currentTheme = this.currentTheme === 'dark' ? 'light' : 'dark';
|
| 662 |
this.container.dataset.theme = this.currentTheme;
|
| 663 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 664 |
|
| 665 |
setupUI() {
|
| 666 |
debug.log('Setting up UI');
|
|
@@ -863,9 +869,9 @@ GM_addStyle(`
|
|
| 863 |
RETURN_TRUSTED_TYPE: true
|
| 864 |
});
|
| 865 |
|
| 866 |
-
try{
|
| 867 |
temp.innerHTML = sanitizedHtml;
|
| 868 |
-
}catch(e){
|
| 869 |
console.error('DOMPurify error:', e);
|
| 870 |
}
|
| 871 |
|
|
@@ -1213,6 +1219,81 @@ GM_addStyle(`
|
|
| 1213 |
}
|
| 1214 |
}
|
| 1215 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1216 |
// 4. Display subtitles
|
| 1217 |
this.updateSubtitleDisplay();
|
| 1218 |
}
|
|
|
|
| 661 |
this.currentTheme = this.currentTheme === 'dark' ? 'light' : 'dark';
|
| 662 |
this.container.dataset.theme = this.currentTheme;
|
| 663 |
}
|
| 664 |
+
updateTabText(tabId, text) {
|
| 665 |
+
const tab = this.container.querySelector(`button[data-tab="${tabId}"]`);
|
| 666 |
+
if (tab) {
|
| 667 |
+
tab.textContent = text;
|
| 668 |
+
}
|
| 669 |
+
}
|
| 670 |
|
| 671 |
setupUI() {
|
| 672 |
debug.log('Setting up UI');
|
|
|
|
| 869 |
RETURN_TRUSTED_TYPE: true
|
| 870 |
});
|
| 871 |
|
| 872 |
+
try {
|
| 873 |
temp.innerHTML = sanitizedHtml;
|
| 874 |
+
} catch (e) {
|
| 875 |
console.error('DOMPurify error:', e);
|
| 876 |
}
|
| 877 |
|
|
|
|
| 1219 |
}
|
| 1220 |
}
|
| 1221 |
|
| 1222 |
+
this.updateSubtitleDisplay();
|
| 1223 |
+
|
| 1224 |
+
// If no Chinese subtitles, get translation
|
| 1225 |
+
if (this.subtitles.english.length > 0 && !this.subtitles.chinese.length) {
|
| 1226 |
+
// Format English subtitles as JSON
|
| 1227 |
+
const subtitleData = this.subtitles.english.map(sub => ({
|
| 1228 |
+
text: sub.words.map(word => word.text).join(' '),
|
| 1229 |
+
time: sub.startTime
|
| 1230 |
+
}));
|
| 1231 |
+
|
| 1232 |
+
this.updateTabText('chinese', '翻译中...');
|
| 1233 |
+
|
| 1234 |
+
try {
|
| 1235 |
+
const response = await new Promise((resolve, reject) => {
|
| 1236 |
+
GM_xmlhttpRequest({
|
| 1237 |
+
method: 'POST',
|
| 1238 |
+
url: 'https://sonygod-flash.hf.space/ask',
|
| 1239 |
+
headers: {
|
| 1240 |
+
'Content-Type': 'application/json',
|
| 1241 |
+
'Accept': 'application/json'
|
| 1242 |
+
},
|
| 1243 |
+
data: JSON.stringify({
|
| 1244 |
+
prompt: `请将以下英文字幕翻译成中文,保持JSON格式返回:
|
| 1245 |
+
${JSON.stringify(subtitleData, null, 2)}
|
| 1246 |
+
请返回格式:
|
| 1247 |
+
{
|
| 1248 |
+
"translations": [
|
| 1249 |
+
{
|
| 1250 |
+
"text": "中文翻译",
|
| 1251 |
+
"time": 原时间戳
|
| 1252 |
+
}
|
| 1253 |
+
]
|
| 1254 |
+
}`,
|
| 1255 |
+
model: 'GEMINI'
|
| 1256 |
+
}),
|
| 1257 |
+
onload: response => {
|
| 1258 |
+
if (response.status === 200) {
|
| 1259 |
+
resolve(JSON.parse(response.responseText));
|
| 1260 |
+
} else {
|
| 1261 |
+
reject(new Error(`HTTP error: ${response.status}`));
|
| 1262 |
+
}
|
| 1263 |
+
},
|
| 1264 |
+
onerror: error => reject(error)
|
| 1265 |
+
});
|
| 1266 |
+
});
|
| 1267 |
+
|
| 1268 |
+
const content = response.data.response;
|
| 1269 |
+
// const jsonMatch = content.match(/```json\s*([\s\S]*?)\s*```/);
|
| 1270 |
+
const jsonMatch = content.match(/(?:")?```json\s*([\s\S]*?)\s*```(?:")?/);
|
| 1271 |
+
|
| 1272 |
+
if (!jsonMatch) {
|
| 1273 |
+
throw new Error('No JSON content found in response');
|
| 1274 |
+
}
|
| 1275 |
+
|
| 1276 |
+
const parsedResponse = JSON.parse(jsonMatch[1]);
|
| 1277 |
+
const translations = parsedResponse.translations || [];
|
| 1278 |
+
|
| 1279 |
+
// Create Chinese subtitles array matching English structure
|
| 1280 |
+
this.subtitles.chinese = this.subtitles.english.map((sub, index) => ({
|
| 1281 |
+
startTime: sub.startTime,
|
| 1282 |
+
endTime: sub.endTime,
|
| 1283 |
+
words: [{
|
| 1284 |
+
text: translations[index]?.text || '',
|
| 1285 |
+
startTime: sub.startTime,
|
| 1286 |
+
endTime: sub.endTime
|
| 1287 |
+
}]
|
| 1288 |
+
}));
|
| 1289 |
+
|
| 1290 |
+
this.updateTabText('chinese', '中文');
|
| 1291 |
+
} catch (error) {
|
| 1292 |
+
this.updateTabText('chinese', '翻译失败');
|
| 1293 |
+
debug.error('Translation failed:', error);
|
| 1294 |
+
}
|
| 1295 |
+
}
|
| 1296 |
+
|
| 1297 |
// 4. Display subtitles
|
| 1298 |
this.updateSubtitleDisplay();
|
| 1299 |
}
|