Skip to content

Instantly share code, notes, and snippets.

@xiaohuohumax
Last active May 17, 2025 05:37
Show Gist options
  • Save xiaohuohumax/ac4ad6494bcd6e29d66ebb0463854126 to your computer and use it in GitHub Desktop.
Save xiaohuohumax/ac4ad6494bcd6e29d66ebb0463854126 to your computer and use it in GitHub Desktop.
油猴脚本-文件下载器(支持跨域, 多文件Zip打包, 并发限制)
import FileSaver from 'file-saver';
import JSZip from 'jszip';
import mime from 'mime';
import pLimit, { LimitFunction } from 'p-limit';
import parseHeaders from 'parse-headers';
// vite-plugin-monkey
import { GM_xmlhttpRequest } from '$';
export interface DFile {
url: string;
name: string;
}
export async function downloadAndZip(files: DFile | DFile[], zipFileName: string, concurrency: number = 10): Promise<void> {
const zip = new JSZip();
const limit: LimitFunction = pLimit(concurrency);
const fileArr = Array.isArray(files) ? files : [files];
function fetchFile(file: DFile): Promise<void> {
return new Promise<void>((resolve, reject) => {
GM_xmlhttpRequest({
method: 'GET',
url: file.url,
responseType: 'blob',
onload: (response) => {
if (response.status === 200) {
const headers = parseHeaders(response.responseHeaders);
const contentType = headers['content-type'] as string | undefined;
const extension = mime.getExtension(contentType || '');
const fileName = extension ? `${file.name}.${extension}` : file.name;
zip.file(fileName, response.response);
resolve();
} else {
reject(new Error(`Failed to fetch ${file.url} with status ${response.status}: ${response.statusText}`));
}
},
onerror: (error) => reject(error)
});
});
}
const promises = fileArr.map(file => limit(() => fetchFile(file)));
await Promise.all(promises);
const content = await zip.generateAsync({ type: 'blob' });
FileSaver.saveAs(content, zipFileName);
}
// 注意:
// JSZip 打包后会出现下载卡死问题
// 解决方法参考 https://github.com/lisonge/vite-plugin-monkey/issues/216#issuecomment-2745140560
// 示例:
const files = [
{ url: 'https://example.com/file1.txt', name: 'file1.txt' },
{ url: 'https://example.com/file2.txt', name: 'file2.txt' },
{ url: 'https://example.com/file3.txt', name: 'file3.txt' }
];
downloadAndZip(files, 'my-files.zip', 10)
.then(() => console.log('Done!'))
.catch(console.error);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment