Prefer h264 formats for saves so cached copies play on every device
This commit is contained in:
@@ -760,6 +760,20 @@ async function assertNotLive(videoId) {
|
||||
}
|
||||
}
|
||||
|
||||
// Format selectors for saves. `[ext=mp4]` alone is NOT enough: YouTube ships
|
||||
// AV1 in mp4 containers too, and the bot-check fallback clients (web_embedded)
|
||||
// rank the AV1 ladder as "bestvideo" — an AV1 save plays on almost nothing
|
||||
// (iOS Safari has no AV1 decoder), so cached copies errored and fell back to
|
||||
// streaming. Demand h264 (`vcodec^=avc1`) + m4a/aac first; anything exotic is
|
||||
// a last resort for videos with no avc ladder at all.
|
||||
const SAVE_MUX_FORMAT =
|
||||
'bv*[height<=720][vcodec^=avc1]+ba[ext=m4a]/bv*[height<=720][vcodec^=avc1]+ba/'
|
||||
+ 'b[ext=mp4][vcodec^=avc1]/bv*[height<=720]+ba/b[ext=mp4]/b';
|
||||
const SAVE_DEFAULT_FORMAT =
|
||||
'best[ext=mp4][vcodec^=avc1][acodec!=none]/'
|
||||
+ 'bv*[height<=720][vcodec^=avc1]+ba[ext=m4a]/bv*[height<=720][vcodec^=avc1]+ba/'
|
||||
+ 'best[ext=mp4][acodec!=none]/bv*[height<=720]+ba/b';
|
||||
|
||||
// Same video + same format args requested while a download is already in
|
||||
// flight (the OPFS worker retries, then the main-thread fallback retries
|
||||
// again) share ONE yt-dlp run instead of spawning another each time.
|
||||
@@ -849,7 +863,7 @@ async function ytdlpEditedDownloadResponse(videoId, fp, keep, signal) {
|
||||
await withSaveSlot(() => runYtdlpResilient([
|
||||
`https://www.youtube.com/watch?v=${videoId}`,
|
||||
'--no-warnings', '--no-playlist',
|
||||
'-f', 'bv*[height<=720][ext=mp4]+ba[ext=m4a]/bv*[height<=720]+ba/b[ext=mp4]/b',
|
||||
'-f', SAVE_MUX_FORMAT,
|
||||
'--merge-output-format', 'mp4',
|
||||
'--limit-rate', DOWNLOAD_RATE,
|
||||
'-o', srcTmp,
|
||||
@@ -916,7 +930,7 @@ app.get('/api/download/:videoId', async (c) => {
|
||||
if (c.req.query('mux') === '1') {
|
||||
try {
|
||||
return await ytdlpDownloadResponse(videoId, fp, [
|
||||
'-f', 'bv*[height<=720][ext=mp4]+ba[ext=m4a]/bv*[height<=720]+ba/b[ext=mp4]/b',
|
||||
'-f', SAVE_MUX_FORMAT,
|
||||
'--merge-output-format', 'mp4',
|
||||
], c.req.raw.signal);
|
||||
} catch (err) {
|
||||
@@ -931,8 +945,7 @@ app.get('/api/download/:videoId', async (c) => {
|
||||
// "Requested format is not available".
|
||||
try {
|
||||
return await ytdlpDownloadResponse(videoId, fp, [
|
||||
'-f', 'bestvideo[ext=mp4][acodec!=none]/bestvideo[acodec!=none]/best[ext=mp4][acodec!=none]/'
|
||||
+ 'bv*[height<=720][ext=mp4]+ba[ext=m4a]/bv*[height<=720]+ba/b',
|
||||
'-f', SAVE_DEFAULT_FORMAT,
|
||||
'--merge-output-format', 'mp4',
|
||||
], c.req.raw.signal);
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user