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,
|
// 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 processM3U8 = (m3u8Data, m3u8Url, baseUrl) => {
|
||||||
const lines = m3u8Data.split('\n');
|
const lines = m3u8Data.split('\n');
|
||||||
const processedLines = lines.map(line => {
|
const processedLines = lines.map(line => {
|
||||||
@@ -352,13 +353,17 @@ const processM3U8 = (m3u8Data, m3u8Url, baseUrl) => {
|
|||||||
}
|
}
|
||||||
if (uri.includes('.m3u8') && !uri.includes('key?url=')) {
|
if (uri.includes('.m3u8') && !uri.includes('key?url=')) {
|
||||||
uri = `${baseUrl}/m3u8?url=${encodeURIComponent(uri)}`;
|
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 `URI="${uri}"`;
|
||||||
});
|
});
|
||||||
return processed;
|
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('#')) {
|
if (!processed.startsWith('#')) {
|
||||||
let uri = processed;
|
let uri = processed;
|
||||||
if (!uri.startsWith('http')) {
|
if (!uri.startsWith('http')) {
|
||||||
@@ -366,6 +371,10 @@ const processM3U8 = (m3u8Data, m3u8Url, baseUrl) => {
|
|||||||
}
|
}
|
||||||
if (uri.includes('.m3u8')) {
|
if (uri.includes('.m3u8')) {
|
||||||
uri = `${baseUrl}/m3u8?url=${encodeURIComponent(uri)}`;
|
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;
|
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) => {
|
app.get('/key', async (req, res) => {
|
||||||
const keyUrl = req.query.url;
|
const keyUrl = req.query.url;
|
||||||
if (!keyUrl) return res.status(400).send('Missing url parameter');
|
if (!keyUrl) return res.status(400).send('Missing url parameter');
|
||||||
|
|||||||
Reference in New Issue
Block a user