@lzwme/m3u8-dl
Version:
Batch download of m3u8 files and convert to mp4
86 lines (85 loc) • 4.05 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.localPlay = localPlay;
exports.toLocalM3u8 = toLocalM3u8;
const fe_utils_1 = require("@lzwme/fe-utils");
const console_log_colors_1 = require("console-log-colors");
const node_fs_1 = require("node:fs");
const node_http_1 = require("node:http");
const node_path_1 = require("node:path");
const utils_1 = require("./utils");
/**
* 边下边看
*/
async function localPlay(m3u8Info, options) {
if (!m3u8Info?.length)
return null;
const cacheDir = (0, node_path_1.dirname)(m3u8Info[0].tsOut);
const cacheDirname = (0, node_path_1.basename)(cacheDir);
const info = await createLocalServer((0, node_path_1.dirname)(cacheDir));
const filename = (0, node_path_1.basename)(options.filename).slice(0, options.filename.lastIndexOf('.')) + `.m3u8`;
await toLocalM3u8(m3u8Info, (0, node_path_1.resolve)(cacheDir, filename), `/${cacheDirname}`);
const playUrl = `https://lzw.me/x/m3u8-player?url=${encodeURIComponent(`${info.origin}/${cacheDirname}/${filename}`)}`;
const cmd = `${process.platform === 'win32' ? 'start' : 'open'} ${playUrl}`;
(0, fe_utils_1.execSync)(cmd);
return info;
}
async function toLocalM3u8(m3u8Info, filepath, host = '') {
const m3u8ContentList = [
`#EXTM3U`,
`#EXT-X-VERSION:3`,
`#EXT-X-ALLOW-CACHE:YES`,
`#EXT-X-TARGETDURATION:${Math.max(...m3u8Info.map(d => d.duration))}`,
`#EXT-X-MEDIA-SEQUENCE:0`,
// `#EXT-X-KEY:METHOD=AES-128,URI="/api/aes/enc.key"`,
];
m3u8Info.forEach(d => {
if (d.tsOut)
m3u8ContentList.push(`#EXTINF:${Number(d.duration).toFixed(6)},`, `${host}/${(0, node_path_1.basename)(d.tsOut)}`);
});
m3u8ContentList.push(`#EXT-X-ENDLIST`);
const m3u8Content = m3u8ContentList.join('\n');
await node_fs_1.promises.writeFile(filepath, m3u8Content, 'utf8');
}
async function createLocalServer(baseDir) {
baseDir = (0, node_path_1.resolve)(baseDir);
const port = await (0, fe_utils_1.findFreePort)();
const origin = `http://localhost:${port}`;
const server = (0, node_http_1.createServer)((req, res) => {
const filename = (0, node_path_1.join)(baseDir, decodeURIComponent(req.url));
utils_1.logger.debug('[req]', req.url, filename);
if ((0, node_fs_1.existsSync)(filename)) {
const stats = (0, node_fs_1.statSync)(filename);
const ext = (0, node_path_1.extname)(filename);
if (stats.isFile()) {
if (ext === '.m3u8')
res.setHeader('Cache-Control', 'no-cache');
res.writeHead(200, {
'Last-Modified': stats.mtime.toUTCString(),
'Access-Control-Allow-Headers': '*',
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
'Access-Control-Allow-Origin': '*',
'Content-Length': String(stats.size),
'Content-Type': ext === '.ts' ? 'video/mp2t' : ext === '.m3u8' ? 'application/vnd.apple.mpegurl' : 'text/plain',
});
(0, node_fs_1.createReadStream)(filename).pipe(res);
return;
}
else if (stats.isDirectory()) {
const html = (0, node_fs_1.readdirSync)(filename).map(filepath => {
const rpath = (0, node_path_1.resolve)(filename, filepath).replace(baseDir, '');
return `<li><a href="${rpath}">${rpath}</a></li>`;
});
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(`<ol>${html.join('')}</ol>`);
return;
}
}
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('Not found');
}).listen(port, () => {
console.log();
utils_1.logger.info('Created Local Server:', console_log_colors_1.color.greenBright(origin));
});
return { port, origin, server };
}
;