sonygod commited on
Commit
0b147a7
·
1 Parent(s): 2295d31

正常版本,没有MARKDOWN

Browse files
Files changed (1) hide show
  1. youtube_sub.js +146 -13
youtube_sub.js CHANGED
@@ -1,3 +1,4 @@
 
1
  // ==UserScript==
2
  // @name YouTube Subtitle Manager
3
  // @namespace http://tampermonkey.net/
@@ -6,6 +7,9 @@
6
  // @author Your name
7
  // @match https://www.youtube.com/*
8
  // @grant GM_addStyle
 
 
 
9
  // @run-at document-end
10
  // ==/UserScript==
11
 
@@ -316,6 +320,38 @@ GM_addStyle(`
316
  color: #000;
317
  opacity: 1;
318
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319
  `;
320
 
321
  // Apply main styles
@@ -703,7 +739,7 @@ GM_addStyle(`
703
  if (sub.words && sub.words.length > 0) {
704
  const line = document.createElement('div');
705
  line.className = 'subtitle-line';
706
-
707
  // Add prefix buttons
708
  const prefixControls = document.createElement('div');
709
  prefixControls.className = 'line-controls';
@@ -718,11 +754,11 @@ GM_addStyle(`
718
  prefixControls.appendChild(btn);
719
  });
720
  line.appendChild(prefixControls);
721
-
722
  // Add subtitle text container
723
  const textContainer = document.createElement('div');
724
  textContainer.className = 'subtitle-text';
725
-
726
  sub.words.forEach((word, i) => {
727
  if (word.text && word.text.trim()) {
728
  const wordBtn = document.createElement('button');
@@ -730,23 +766,120 @@ GM_addStyle(`
730
  wordBtn.textContent = word.text.trim();
731
  wordBtn.dataset.start = word.startTime;
732
  wordBtn.dataset.end = word.endTime;
733
- wordBtn.onclick = (e) => {
734
- e.stopPropagation(); // Prevent line click
735
- // const video = document.querySelector('video');
736
- // if (video) {
737
- // video.currentTime = parseFloat(word.startTime);
738
- // }
739
  console.log(`You click "${word.text.trim()}" word`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
740
  };
741
  textContainer.appendChild(wordBtn);
742
-
743
  if (i < sub.words.length - 1) {
744
  textContainer.appendChild(document.createTextNode(' '));
745
  }
746
  }
747
  });
748
  line.appendChild(textContainer);
749
-
750
  // Add suffix buttons
751
  const suffixControls = document.createElement('div');
752
  suffixControls.className = 'line-controls';
@@ -761,13 +894,13 @@ GM_addStyle(`
761
  suffixControls.appendChild(btn);
762
  });
763
  line.appendChild(suffixControls);
764
-
765
  // Add timestamp
766
  const timestamp = document.createElement('span');
767
  timestamp.className = 'timestamp';
768
  timestamp.textContent = this.formatTime(sub.startTime);
769
  line.appendChild(timestamp);
770
-
771
  line.dataset.time = sub.startTime;
772
  line.dataset.index = index;
773
  container.appendChild(line);
 
1
+ // Update userscript headers
2
  // ==UserScript==
3
  // @name YouTube Subtitle Manager
4
  // @namespace http://tampermonkey.net/
 
7
  // @author Your name
8
  // @match https://www.youtube.com/*
9
  // @grant GM_addStyle
10
+ // @grant GM_xmlhttpRequest
11
+ // @connect sonygod-flash.hf.space
12
+ // @require https://cdn.jsdelivr.net/npm/marked/marked.min.js
13
  // @run-at document-end
14
  // ==/UserScript==
15
 
 
320
  color: #000;
321
  opacity: 1;
322
  }
323
+
324
+ .word-definition-popup {
325
+ position: fixed;
326
+ right: -400px;
327
+ top: 50%;
328
+ transform: translateY(-50%);
329
+ width: 380px;
330
+ background: rgba(33, 33, 33, 0.95);
331
+ border-radius: 8px;
332
+ padding: 20px;
333
+ color: white;
334
+ transition: right 0.3s ease;
335
+ z-index: 10000;
336
+ max-height: 80vh;
337
+ overflow-y: auto;
338
+ }
339
+
340
+ .word-definition-popup.show {
341
+ right: 460px;
342
+ }
343
+
344
+ .word-definition-popup .markdown {
345
+ font-size: 14px;
346
+ line-height: 1.6;
347
+ }
348
+ `;
349
+
350
+ // Add popup HTML
351
+ const popupHTML = `
352
+ <div class="word-definition-popup">
353
+ <div class="markdown"></div>
354
+ </div>
355
  `;
356
 
357
  // Apply main styles
 
739
  if (sub.words && sub.words.length > 0) {
740
  const line = document.createElement('div');
741
  line.className = 'subtitle-line';
742
+
743
  // Add prefix buttons
744
  const prefixControls = document.createElement('div');
745
  prefixControls.className = 'line-controls';
 
754
  prefixControls.appendChild(btn);
755
  });
756
  line.appendChild(prefixControls);
757
+
758
  // Add subtitle text container
759
  const textContainer = document.createElement('div');
760
  textContainer.className = 'subtitle-text';
761
+
762
  sub.words.forEach((word, i) => {
763
  if (word.text && word.text.trim()) {
764
  const wordBtn = document.createElement('button');
 
766
  wordBtn.textContent = word.text.trim();
767
  wordBtn.dataset.start = word.startTime;
768
  wordBtn.dataset.end = word.endTime;
769
+ wordBtn.onclick = async (e) => {
770
+ e.stopPropagation();
 
 
 
 
771
  console.log(`You click "${word.text.trim()}" word`);
772
+
773
+ let popup = document.querySelector('.word-definition-popup');
774
+ if (!popup) {
775
+ // Create popup container
776
+ popup = document.createElement('div');
777
+ popup.className = 'word-definition-popup';
778
+
779
+ // Create markdown container
780
+ const markdownDiv = document.createElement('div');
781
+ markdownDiv.className = 'markdown';
782
+ popup.appendChild(markdownDiv);
783
+
784
+ // Add popup to document
785
+ document.body.appendChild(popup);
786
+ }
787
+
788
+ // Ensure markdown container exists
789
+ let markdownContainer = popup.querySelector('.markdown');
790
+ if (!markdownContainer) {
791
+ markdownContainer = document.createElement('div');
792
+ markdownContainer.className = 'markdown';
793
+ popup.appendChild(markdownContainer);
794
+ }
795
+
796
+ try {
797
+ // Use GM_xmlhttpRequest with updated config
798
+ const response = await new Promise((resolve, reject) => {
799
+ GM_xmlhttpRequest({
800
+ method: 'POST',
801
+ url: 'https://sonygod-flash.hf.space/ask',
802
+ headers: {
803
+ 'Content-Type': 'application/json',
804
+ 'Accept': 'application/json',
805
+ 'Origin': 'https://www.youtube.com'
806
+ },
807
+ data: JSON.stringify({
808
+ prompt: `中文翻译 "${word.text.trim()}"并详细介绍,100字以内,包括对应的英文近义词,英文反义词`,
809
+ model: 'GEMINI'
810
+ }),
811
+ onload: function (response) {
812
+ // Handle different status codes
813
+ if (response.status === 405) {
814
+ reject(new Error('API endpoint does not accept POST method. Try GET instead.'));
815
+ } else if (response.status >= 200 && response.status < 300) {
816
+ try {
817
+ resolve(JSON.parse(response.responseText));
818
+ } catch (e) {
819
+ reject(new Error('Invalid JSON response'));
820
+ }
821
+ } else {
822
+ reject(new Error(`HTTP error! status: ${response.status}`));
823
+ }
824
+ },
825
+ onerror: function (error) {
826
+ reject(new Error('Network request failed: ' + error.error));
827
+ },
828
+ ontimeout: function () {
829
+ reject(new Error('Request timed out'));
830
+ }
831
+ });
832
+ });
833
+
834
+ console.log('API Response:', response);
835
+
836
+ const content = response?.data?.response;
837
+ if (!content) {
838
+ throw new Error('No content in API response');
839
+ }
840
+
841
+ // Create text node instead of using innerHTML
842
+ const markdownContent = marked.parse(content);
843
+ if (markdownContent) {
844
+ // Clear existing content
845
+ while (markdownContainer.firstChild) {
846
+ markdownContainer.removeChild(markdownContainer.firstChild);
847
+ }
848
+
849
+ // Create temporary container
850
+ const temp = document.createElement('div');
851
+ temp.textContent = markdownContent;
852
+
853
+ // Safely append text content
854
+ const fragment = document.createDocumentFragment();
855
+ fragment.appendChild(temp);
856
+ markdownContainer.appendChild(fragment);
857
+
858
+ popup.classList.add('show');
859
+ } else {
860
+ throw new Error('Failed to parse markdown content');
861
+ }
862
+
863
+ } catch (error) {
864
+ console.error('API call failed:', error);
865
+ popup.querySelector('.markdown').innerHTML = `
866
+ <div style="color: red">
867
+ Error: ${error.message}<br>
868
+ Please check console for details.
869
+ </div>
870
+ `;
871
+ popup.classList.add('show');
872
+ }
873
  };
874
  textContainer.appendChild(wordBtn);
875
+
876
  if (i < sub.words.length - 1) {
877
  textContainer.appendChild(document.createTextNode(' '));
878
  }
879
  }
880
  });
881
  line.appendChild(textContainer);
882
+
883
  // Add suffix buttons
884
  const suffixControls = document.createElement('div');
885
  suffixControls.className = 'line-controls';
 
894
  suffixControls.appendChild(btn);
895
  });
896
  line.appendChild(suffixControls);
897
+
898
  // Add timestamp
899
  const timestamp = document.createElement('span');
900
  timestamp.className = 'timestamp';
901
  timestamp.textContent = this.formatTime(sub.startTime);
902
  line.appendChild(timestamp);
903
+
904
  line.dataset.time = sub.startTime;
905
  line.dataset.index = index;
906
  container.appendChild(line);