UNPKG

@lzwme/m3u8-dl

Version:

Batch download of m3u8 files and convert to mp4

109 lines (108 loc) 4.85 kB
"use strict"; 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; }); }