- 按 URL 扩展名自动识别插件(.m3u8→hls.js,.flv/.ts/.m2ts→mpegts.js),iOS 上 m3u8 仍走原生 HLS - flv 播放改由 mpegts.js 承担,移除 flv.js 依赖,plug:'flv.js' 保留兼容别名 - 修复 plug:'dash.js' 调用不存在函数的死代码 bug - mpegts 能力判断由 mseLivePlayback 放宽为 isSupported()(修复部分浏览器点播被误杀) - 移动端:iOS 原生全屏状态同步、iPad/iPod UA 识别、X5 同层播放属性、进度/音量条触摸拖动、触摸坐标滚动偏移修正 - 新增 Playwright 冒烟测试(npm test)与支持 Range 的本地服务器(npm run serve) - 文档说明:测试禁用 python http.server(不支持 Range,mp4 无法 seek)
44 lines
1.8 KiB
JavaScript
44 lines
1.8 KiB
JavaScript
/*
|
|
* 支持 Range 请求的静态文件服务器(测试用)
|
|
* python3 -m http.server 不支持 Range,会导致 mp4 无法 seek,故用此替代
|
|
* 用法:node scripts/serve.js [端口]
|
|
*/
|
|
const http = require('http');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const root = path.resolve(__dirname, '..');
|
|
const port = parseInt(process.argv[2] || '8931', 10);
|
|
const mime = {
|
|
'.html': 'text/html', '.js': 'text/javascript', '.css': 'text/css',
|
|
'.png': 'image/png', '.mp4': 'video/mp4', '.json': 'application/json',
|
|
'.map': 'application/json', '.ico': 'image/x-icon'
|
|
};
|
|
|
|
http.createServer((req, res) => {
|
|
const urlPath = decodeURIComponent(req.url.split('?')[0]);
|
|
let file = path.join(root, urlPath === '/' ? 'index.html' : urlPath);
|
|
if (!file.startsWith(root)) { res.writeHead(403); res.end(); return; }
|
|
fs.stat(file, (err, stat) => {
|
|
if (err || !stat.isFile()) { res.writeHead(404); res.end('404'); return; }
|
|
const type = mime[path.extname(file).toLowerCase()] || 'application/octet-stream';
|
|
const range = req.headers.range;
|
|
if (range) {
|
|
const m = /bytes=(\d*)-(\d*)/.exec(range);
|
|
let start = m && m[1] ? parseInt(m[1], 10) : 0;
|
|
let end = m && m[2] ? parseInt(m[2], 10) : stat.size - 1;
|
|
end = Math.min(end, stat.size - 1);
|
|
res.writeHead(206, {
|
|
'Content-Type': type,
|
|
'Content-Range': `bytes ${start}-${end}/${stat.size}`,
|
|
'Accept-Ranges': 'bytes',
|
|
'Content-Length': end - start + 1
|
|
});
|
|
fs.createReadStream(file, { start, end }).pipe(res);
|
|
} else {
|
|
res.writeHead(200, { 'Content-Type': type, 'Accept-Ranges': 'bytes', 'Content-Length': stat.size });
|
|
fs.createReadStream(file).pipe(res);
|
|
}
|
|
});
|
|
}).listen(port, () => console.log(`静态服务器(支持 Range): http://localhost:${port}`));
|