add 字幕下载,但是还没有正确打包
Browse files- youtube_sub.js +94 -9
youtube_sub.js
CHANGED
|
@@ -8,9 +8,12 @@
|
|
| 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 |
// @require https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.6/purify.min.js
|
|
|
|
| 14 |
// @run-at document-end
|
| 15 |
// ==/UserScript==
|
| 16 |
|
|
@@ -670,6 +673,79 @@ GM_addStyle(`
|
|
| 670 |
this.downloadFile('mixed.srt', srt);
|
| 671 |
}));
|
| 672 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 673 |
|
| 674 |
|
| 675 |
|
|
@@ -752,15 +828,24 @@ GM_addStyle(`
|
|
| 752 |
}
|
| 753 |
// Add helper methods to class
|
| 754 |
downloadFile(filename, content) {
|
| 755 |
-
|
| 756 |
-
|
| 757 |
-
|
| 758 |
-
|
| 759 |
-
|
| 760 |
-
|
| 761 |
-
|
| 762 |
-
|
| 763 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 764 |
}
|
| 765 |
|
| 766 |
|
|
|
|
| 8 |
// @match https://www.youtube.com/*
|
| 9 |
// @grant GM_addStyle
|
| 10 |
// @grant GM_xmlhttpRequest
|
| 11 |
+
// @grant GM_download
|
| 12 |
+
// @connect *
|
| 13 |
// @connect sonygod-flash.hf.space
|
| 14 |
// @require https://cdn.jsdelivr.net/npm/marked/marked.min.js
|
| 15 |
// @require https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.6/purify.min.js
|
| 16 |
+
// @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js
|
| 17 |
// @run-at document-end
|
| 18 |
// ==/UserScript==
|
| 19 |
|
|
|
|
| 673 |
this.downloadFile('mixed.srt', srt);
|
| 674 |
}));
|
| 675 |
|
| 676 |
+
// Add export button after existing exports
|
| 677 |
+
exportDiv.appendChild(createExportButton('Export Words by Letter (ZIP)', async () => {
|
| 678 |
+
try {
|
| 679 |
+
console.log('Starting ZIP export...');
|
| 680 |
+
const words = [...this.loadNewWordsCache()].sort();
|
| 681 |
+
console.log(`Got ${words.length} words`);
|
| 682 |
+
|
| 683 |
+
// Create ZIP
|
| 684 |
+
const zip = new JSZip();
|
| 685 |
+
|
| 686 |
+
// Group and add files
|
| 687 |
+
const groups = words.reduce((acc, word) => {
|
| 688 |
+
const letter = word[0].toLowerCase();
|
| 689 |
+
if (/[a-z]/.test(letter)) {
|
| 690 |
+
if (!acc[letter]) acc[letter] = [];
|
| 691 |
+
acc[letter].push(word);
|
| 692 |
+
}
|
| 693 |
+
return acc;
|
| 694 |
+
}, {});
|
| 695 |
+
|
| 696 |
+
Object.entries(groups).forEach(([letter, words]) => {
|
| 697 |
+
zip.file(`${letter}.txt`, words.join('\n'));
|
| 698 |
+
console.log(`Added ${letter}.txt with ${words.length} words`);
|
| 699 |
+
});
|
| 700 |
+
|
| 701 |
+
// Try TamperMonkey GM_download first
|
| 702 |
+
try {
|
| 703 |
+
const base64 = await zip.generateAsync({
|
| 704 |
+
type: "base64",
|
| 705 |
+
compression: "DEFLATE"
|
| 706 |
+
});
|
| 707 |
+
|
| 708 |
+
console.log('ZIP generated in base64');
|
| 709 |
+
|
| 710 |
+
// Define download handler
|
| 711 |
+
const downloadHandler = {
|
| 712 |
+
url: "data:application/zip;base64," + base64,
|
| 713 |
+
name: "words.zip",
|
| 714 |
+
saveAs: true,
|
| 715 |
+
onload: () => console.log('Download started'),
|
| 716 |
+
onerror: (err) => {
|
| 717 |
+
console.error('GM_download failed:', err);
|
| 718 |
+
throw err;
|
| 719 |
+
}
|
| 720 |
+
};
|
| 721 |
+
|
| 722 |
+
console.log('Initiating GM_download...');
|
| 723 |
+
GM_download(downloadHandler);
|
| 724 |
+
|
| 725 |
+
} catch (gmError) {
|
| 726 |
+
console.error('GM_download failed, falling back to blob:', gmError);
|
| 727 |
+
|
| 728 |
+
// Fallback to Blob approach
|
| 729 |
+
const blob = await zip.generateAsync({
|
| 730 |
+
type: "blob",
|
| 731 |
+
compression: "DEFLATE"
|
| 732 |
+
});
|
| 733 |
+
|
| 734 |
+
const url = URL.createObjectURL(blob);
|
| 735 |
+
const link = document.createElement('a');
|
| 736 |
+
link.href = url;
|
| 737 |
+
link.download = 'words.zip';
|
| 738 |
+
document.body.appendChild(link);
|
| 739 |
+
link.click();
|
| 740 |
+
document.body.removeChild(link);
|
| 741 |
+
URL.revokeObjectURL(url);
|
| 742 |
+
}
|
| 743 |
+
|
| 744 |
+
} catch (error) {
|
| 745 |
+
console.error('ZIP export failed:', error);
|
| 746 |
+
alert('Failed to export ZIP file: ' + error.message);
|
| 747 |
+
}
|
| 748 |
+
}));
|
| 749 |
|
| 750 |
|
| 751 |
|
|
|
|
| 828 |
}
|
| 829 |
// Add helper methods to class
|
| 830 |
downloadFile(filename, content) {
|
| 831 |
+
try {
|
| 832 |
+
console.log('downloadFile started:', filename, content instanceof Blob);
|
| 833 |
+
const url = content instanceof Blob ?
|
| 834 |
+
URL.createObjectURL(content) :
|
| 835 |
+
URL.createObjectURL(new Blob([content], { type: 'text/plain;charset=utf-8' }));
|
| 836 |
+
|
| 837 |
+
const link = document.createElement('a');
|
| 838 |
+
link.href = url;
|
| 839 |
+
link.download = filename;
|
| 840 |
+
document.body.appendChild(link);
|
| 841 |
+
link.click();
|
| 842 |
+
document.body.removeChild(link);
|
| 843 |
+
URL.revokeObjectURL(url);
|
| 844 |
+
console.log('Download completed');
|
| 845 |
+
} catch (error) {
|
| 846 |
+
console.error('Download failed:', error);
|
| 847 |
+
alert('Failed to download file: ' + error.message);
|
| 848 |
+
}
|
| 849 |
}
|
| 850 |
|
| 851 |
|