update
This commit is contained in:
@@ -325,7 +325,8 @@ const filterMasterPlaylist = async (m3u8Data, m3u8Url) => {
|
||||
};
|
||||
|
||||
// Helper: processes an M3U8 playlist by converting any relative URLs to absolute,
|
||||
// proxying sub-playlists (.m3u8), and proxying decryption keys.
|
||||
// proxying sub-playlists (.m3u8), proxying decryption keys, and proxying segment files (.m4s, .m4v)
|
||||
// to bypass FFmpeg's strict extension security checks.
|
||||
const processM3U8 = (m3u8Data, m3u8Url, baseUrl) => {
|
||||
const lines = m3u8Data.split('\n');
|
||||
const processedLines = lines.map(line => {
|
||||
@@ -352,13 +353,17 @@ const processM3U8 = (m3u8Data, m3u8Url, baseUrl) => {
|
||||
}
|
||||
if (uri.includes('.m3u8') && !uri.includes('key?url=')) {
|
||||
uri = `${baseUrl}/m3u8?url=${encodeURIComponent(uri)}`;
|
||||
} else if (uri.includes('.m4s') || uri.includes('.m4v')) {
|
||||
// Proxy fragmented MP4 files to bypass FFmpeg's strict extension checks
|
||||
const filename = uri.split('/').pop().split('?')[0].replace(/\.(m4s|m4v)$/, '.mp4');
|
||||
uri = `${baseUrl}/segment/${filename}?url=${encodeURIComponent(uri)}`;
|
||||
}
|
||||
return `URI="${uri}"`;
|
||||
});
|
||||
return processed;
|
||||
}
|
||||
|
||||
// 3. Rewrite main segment/variant playlist URLs to be absolute (and proxy variant playlists)
|
||||
// 3. Rewrite main segment/variant playlist URLs to be absolute (and proxy variant playlists/segments)
|
||||
if (!processed.startsWith('#')) {
|
||||
let uri = processed;
|
||||
if (!uri.startsWith('http')) {
|
||||
@@ -366,6 +371,10 @@ const processM3U8 = (m3u8Data, m3u8Url, baseUrl) => {
|
||||
}
|
||||
if (uri.includes('.m3u8')) {
|
||||
uri = `${baseUrl}/m3u8?url=${encodeURIComponent(uri)}`;
|
||||
} else if (uri.includes('.m4s') || uri.includes('.m4v')) {
|
||||
// Proxy fragmented MP4 files to bypass FFmpeg's strict extension checks
|
||||
const filename = uri.split('/').pop().split('?')[0].replace(/\.(m4s|m4v)$/, '.mp4');
|
||||
uri = `${baseUrl}/segment/${filename}?url=${encodeURIComponent(uri)}`;
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
@@ -433,6 +442,41 @@ app.get('/m3u8', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/segment/:filename', async (req, res) => {
|
||||
const segmentUrl = req.query.url;
|
||||
if (!segmentUrl) return res.status(400).send('Missing url parameter');
|
||||
|
||||
try {
|
||||
const response = await axios.get(segmentUrl, {
|
||||
headers: buildHeaders(),
|
||||
responseType: 'stream',
|
||||
timeout: 10000
|
||||
});
|
||||
|
||||
if (response.headers['content-type']) {
|
||||
res.header('Content-Type', response.headers['content-type']);
|
||||
} else {
|
||||
res.header('Content-Type', 'video/mp4');
|
||||
}
|
||||
if (response.headers['content-length']) {
|
||||
res.header('Content-Length', response.headers['content-length']);
|
||||
}
|
||||
|
||||
response.data.pipe(res);
|
||||
|
||||
req.on('close', () => {
|
||||
if (response.data && typeof response.data.destroy === 'function') {
|
||||
response.data.destroy();
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`Error proxying segment: ${error.message}`);
|
||||
if (!res.headersSent) {
|
||||
res.status(500).send('Error proxying segment');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/key', async (req, res) => {
|
||||
const keyUrl = req.query.url;
|
||||
if (!keyUrl) return res.status(400).send('Missing url parameter');
|
||||
|
||||
Reference in New Issue
Block a user