sonygod commited on
Commit
8998663
·
1 Parent(s): 501e832

修复网速慢,语音播放问题

Browse files
Files changed (1) hide show
  1. youtube_sub.js +91 -31
youtube_sub.js CHANGED
@@ -27,6 +27,8 @@ GM_addStyle(`
27
  if (window.subtitleManagerInstance) {
28
  window.subtitleManagerInstance.cleanup();
29
  }
 
 
30
 
31
  // 增强的样式定义,添加过渡效果
32
  const styles = `
@@ -901,6 +903,69 @@ GM_addStyle(`
901
  this.container.classList.toggle('collapsed', this.isCollapsed);
902
  }
903
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
904
  // Update displaySingleLanguage method
905
  displaySingleLanguage(container, subtitles) {
906
  subtitles.forEach((sub, index) => {
@@ -969,7 +1034,7 @@ GM_addStyle(`
969
  speakerBtn = document.createElement('button');
970
  speakerBtn.className = 'speaker-btn';
971
  speakerBtn.textContent = '🔊';
972
- speakerBtn.onclick = (e) => {
973
  e.stopPropagation();
974
  try {
975
  const utterance = new SpeechSynthesisUtterance(wordText);
@@ -977,7 +1042,22 @@ GM_addStyle(`
977
  utterance.rate = 0.9;
978
 
979
  // Get voices and select based on click count
980
- const voices = speechSynthesis.getVoices();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
981
  const isFemaleTurn = this.speakerClickCount % 2 === 1;
982
  const voice = voices.find(v =>
983
  v.lang.includes('en') &&
@@ -985,11 +1065,18 @@ GM_addStyle(`
985
  );
986
 
987
  if (voice) {
 
988
  utterance.voice = voice;
 
 
989
  }
990
 
 
 
 
 
991
  speechSynthesis.speak(utterance);
992
- this.speakerClickCount++; // Increment counter
993
  } catch (error) {
994
  console.error('TTS failed:', error);
995
  }
@@ -1044,34 +1131,7 @@ GM_addStyle(`
1044
  // });
1045
  // });
1046
 
1047
- const response = await new Promise((resolve, reject) => {
1048
- GM_xmlhttpRequest({
1049
- method: 'GET',
1050
- url: `https://sonygod-flash.hf.space/translate/${encodeURIComponent(word.text.trim())}`,
1051
- headers: {
1052
- 'Accept': 'application/json',
1053
- 'Origin': 'https://www.youtube.com'
1054
- },
1055
- onload: function (response) {
1056
- if (response.status >= 200 && response.status < 300) {
1057
- try {
1058
- resolve(JSON.parse(response.responseText));
1059
- } catch (e) {
1060
- reject(new Error('Invalid JSON response'));
1061
- }
1062
- } else {
1063
- reject(new Error(`HTTP error! status: ${response.status}`));
1064
- }
1065
- },
1066
- onerror: function (error) {
1067
- reject(new Error('Network request failed: ' + error.error));
1068
- },
1069
- ontimeout: function () {
1070
- reject(new Error('Request timed out'));
1071
- }
1072
- });
1073
- });
1074
-
1075
  console.log('API Response:', response);
1076
 
1077
  const content = response?.data?.response;
 
27
  if (window.subtitleManagerInstance) {
28
  window.subtitleManagerInstance.cleanup();
29
  }
30
+ const WORD_CACHE_EXPIRY = 7 * 24 * 60 * 60 * 1000; // 7 days in ms
31
+ const WORD_CACHE_KEY = 'youtube_subtitle_word_cache';
32
 
33
  // 增强的样式定义,添加过渡效果
34
  const styles = `
 
903
  this.container.classList.toggle('collapsed', this.isCollapsed);
904
  }
905
 
906
+
907
+
908
+ // Get word translation with cache
909
+ async getWordTranslation(word) {
910
+ // Get cache
911
+ const cache = JSON.parse(localStorage.getItem(WORD_CACHE_KEY) || '{}');
912
+ const now = Date.now();
913
+ const cachedResult = cache[word];
914
+
915
+ // Check valid cache
916
+ if (cachedResult && now - cachedResult.timestamp < WORD_CACHE_EXPIRY) {
917
+ console.log('Cache hit:', word);
918
+ return cachedResult.data;
919
+ }
920
+
921
+ // Clear expired entries
922
+ Object.keys(cache).forEach(key => {
923
+ if (now - cache[key].timestamp > WORD_CACHE_EXPIRY) {
924
+ delete cache[key];
925
+ }
926
+ });
927
+
928
+ // API call
929
+ const response = await new Promise((resolve, reject) => {
930
+ GM_xmlhttpRequest({
931
+ method: 'GET',
932
+ url: `https://sonygod-flash.hf.space/translate/${encodeURIComponent(word.trim())}`,
933
+ headers: {
934
+ 'Accept': 'application/json',
935
+ 'Origin': 'https://www.youtube.com'
936
+ },
937
+ onload: function (response) {
938
+ if (response.status >= 200 && response.status < 300) {
939
+ try {
940
+ resolve(JSON.parse(response.responseText));
941
+ } catch (e) {
942
+ reject(new Error('Invalid JSON response'));
943
+ }
944
+ } else {
945
+ reject(new Error(`HTTP error! status: ${response.status}`));
946
+ }
947
+ },
948
+ onerror: error => reject(new Error('Network request failed: ' + error.error)),
949
+ ontimeout: () => reject(new Error('Request timed out'))
950
+ });
951
+ });
952
+
953
+ // Cache successful response
954
+ if (response?.data?.response) {
955
+ cache[word] = {
956
+ timestamp: now,
957
+ data: response
958
+ };
959
+ try {
960
+ localStorage.setItem(WORD_CACHE_KEY, JSON.stringify(cache));
961
+ } catch (e) {
962
+ console.error('Cache write failed:', e);
963
+ }
964
+ }
965
+
966
+ return response;
967
+ };
968
+
969
  // Update displaySingleLanguage method
970
  displaySingleLanguage(container, subtitles) {
971
  subtitles.forEach((sub, index) => {
 
1034
  speakerBtn = document.createElement('button');
1035
  speakerBtn.className = 'speaker-btn';
1036
  speakerBtn.textContent = '🔊';
1037
+ speakerBtn.onclick = async (e) => {
1038
  e.stopPropagation();
1039
  try {
1040
  const utterance = new SpeechSynthesisUtterance(wordText);
 
1042
  utterance.rate = 0.9;
1043
 
1044
  // Get voices and select based on click count
1045
+ let voices = speechSynthesis.getVoices();
1046
+ if (!voices.length) {
1047
+ await new Promise(resolve => {
1048
+ speechSynthesis.onvoiceschanged = () => {
1049
+ voices = speechSynthesis.getVoices();
1050
+ resolve();
1051
+ };
1052
+ });
1053
+ }
1054
+ // Log available voices
1055
+ console.log('Available voices:', voices.map(v => ({
1056
+ name: v.name,
1057
+ lang: v.lang,
1058
+ isFemale: v.name.toLowerCase().includes('female')
1059
+ })));
1060
+ // Select voice based on click count
1061
  const isFemaleTurn = this.speakerClickCount % 2 === 1;
1062
  const voice = voices.find(v =>
1063
  v.lang.includes('en') &&
 
1065
  );
1066
 
1067
  if (voice) {
1068
+ console.log('Selected voice:', voice.name);
1069
  utterance.voice = voice;
1070
+ } else {
1071
+ console.warn('No matching voice found, using default');
1072
  }
1073
 
1074
+ // Cancel any ongoing speech
1075
+ speechSynthesis.cancel();
1076
+
1077
+ // Speak the word
1078
  speechSynthesis.speak(utterance);
1079
+ this.speakerClickCount++;
1080
  } catch (error) {
1081
  console.error('TTS failed:', error);
1082
  }
 
1131
  // });
1132
  // });
1133
 
1134
+ const response = await this.getWordTranslation(wordText);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1135
  console.log('API Response:', response);
1136
 
1137
  const content = response?.data?.response;