@lzwme/m3u8-dl
Version:
Batch download of m3u8 files and convert to mp4
109 lines (108 loc) • 4.85 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.m3u8BatchDownload = m3u8BatchDownload;
/*
* @Author: renxia lzwy0820@qq.com
* @Date: 2024-07-30 08:57:58
* @LastEditors: renxia
* @LastEditTime: 2025-05-30 10:16:45
* @FilePath: \m3u8-dl\src\m3u8-batch-download.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
const node_fs_1 = require("node:fs");
const node_path_1 = require("node:path");
const console_log_colors_1 = require("console-log-colors");
const file_download_1 = require("./lib/file-download");
const format_options_1 = require("./lib/format-options");
const m3u8_download_1 = require("./lib/m3u8-download");
const utils_1 = require("./lib/utils");
const video_parser_1 = require("./video-parser");
async function formatUrls(urls, options) {
const taskset = new Map();
for (const url of urls) {
if (!url)
continue;
if ((0, node_fs_1.existsSync)(url)) {
const content = await node_fs_1.promises.readFile(url, 'utf8');
if (content.includes('.m3u8')) {
const list = content
.split('\n')
.filter(d => d.includes('.m3u8'))
.map((href, idx) => (href.startsWith('http') ? `${idx}|${href}` : href));
const o = { ...options };
if (!o.filename)
o.filename = (0, node_path_1.basename)(url).split('.')[0];
const t = await formatUrls(list, o);
for (const d of t.entries())
taskset.set(d[0], d[1]);
continue;
}
}
const r = (0, format_options_1.formatOptions)(url, options);
taskset.set(r.url, r.options);
}
return taskset;
}
async function m3u8BatchDownload(urls, options) {
const tasks = await formatUrls(urls, options);
let workPoll;
return new Promise(rs => {
let preDLing = false;
const afterDownload = (r, url) => {
const success = r.filepath && (0, node_fs_1.existsSync)(r.filepath);
if (success) {
if (r.isExist)
utils_1.logger.info('文件已存在:', (0, console_log_colors_1.gray)(r.filepath));
utils_1.logger.debug('下载完成:', (0, console_log_colors_1.gray)(url), (0, console_log_colors_1.gray)(r.filepath));
}
else {
utils_1.logger.error('下载失败:', (0, console_log_colors_1.red)(r.errmsg || '未知错误'), (0, console_log_colors_1.gray)(url));
}
if (tasks.size === 0)
rs(r.filepath && (0, node_fs_1.existsSync)(r.filepath));
else
run();
};
const run = () => {
const [url, urlNext] = [...tasks.keys()];
if (url) {
const o = tasks.get(url);
const onProgress = o.onProgress;
tasks.delete(url);
o.onInited = (s, _i, wp) => {
if (workPoll)
workPoll = wp;
if (o.type === 'parser') {
utils_1.logger.info('视频解析完成:', s.filename, (0, console_log_colors_1.gray)(s.url));
}
};
o.onProgress = (finished, total, info, stats) => {
if (onProgress)
onProgress(finished, total, info, stats);
if (o.type === 'm3u8' && !preDLing && urlNext && tasks.size && workPoll.freeNum > 1 && total - finished < options.threadNum) {
utils_1.logger.debug('\n[预下载下一集]', 'freeNum:', workPoll.freeNum, 'totalNum:', workPoll.totalNum, 'totalTask:', workPoll.totalTask, tasks.size);
preDLing = true;
(0, m3u8_download_1.preDownLoad)(urlNext, options, workPoll).then(() => {
preDLing = false;
});
}
};
if (o.type === 'parser') {
const vp = new video_parser_1.VideoParser();
vp.download(url, o).then(r => afterDownload(r, url));
}
else if (o.type === 'file') {
(0, file_download_1.fileDownload)(url, o).then(r => afterDownload(r, url));
}
else {
(0, m3u8_download_1.m3u8Download)(url, o).then(r => afterDownload(r, url));
}
}
};
run();
}).then(d => {
if (workPoll && workPoll.freeNum === workPoll.numThreads)
workPoll.close();
return d;
});
}
;