fix(downloads): make shared files iOS-playable + default to 720p
Shared /watch links showed a "broken play button" on iPad (any iOS browser — all forced onto WebKit) while playing fine on desktop Chrome. Root cause: the stored mp4's video codec was AV1 (confirmed via ffprobe), which WebKit can't decode. The existing H.264 guard was only a format_sort *preference*, so a non-YouTube source (Facebook) that ships AV1 as its best video-only stream slipped through. - B1: for the mp4 compat profile, prefer H.264 at the SELECTION level with a progressive fallback (bestvideo[vcodec^=avc1]+bestaudio / best[vcodec^=avc1] / anything) so an avc1 progressive is chosen over an AV1-only video-only stream. - B2: re-encode the rare AV1/VP9-only result to H.264+AAC (+faststart) in the worker before storing, gated on the compat profile; corrects the asset codec metadata to match. - Bump _SIG_VERSION 2->3 so cached AV1 assets re-derive. - Default download preset is now 720p (migration 0058 re-seeds builtins 720p-first; ProfileEditor BLANK 1080->720). - Tests for the selector, compat opt-outs, and the transcode predicate.
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
"""reset builtin download profiles: 720p is now the default (first) preset
|
||||
|
||||
Revision ID: 0058_dl_default_720p
|
||||
Revises: 0057_plex_ppl_enriched
|
||||
Create Date: 2026-07-22
|
||||
|
||||
The download dialog preselects the first builtin (lowest sort_order). Make 720p that default —
|
||||
it plays everywhere, downloads faster, and is plenty for the shared /watch player — with 1080p and
|
||||
Best still one click away. Re-seeds the builtin rows so fresh installs and existing DBs converge
|
||||
(same mechanism as 0040). Existing jobs are unaffected (they snapshot their spec; a profile_id that
|
||||
pointed at a replaced row just SET NULLs).
|
||||
"""
|
||||
from typing import Sequence, Union
|
||||
|
||||
import sqlalchemy as sa
|
||||
from alembic import op
|
||||
|
||||
revision: str = "0058_dl_default_720p"
|
||||
down_revision: Union[str, None] = "0057_plex_ppl_enriched"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def _spec(mode, height=None, container=None, audio_format=None):
|
||||
return {
|
||||
"mode": mode,
|
||||
"max_height": height,
|
||||
"container": container,
|
||||
"audio_format": audio_format,
|
||||
"vcodec": None,
|
||||
"embed_subs": False,
|
||||
"embed_chapters": False,
|
||||
"embed_thumbnail": False,
|
||||
"sponsorblock": False,
|
||||
}
|
||||
|
||||
|
||||
# 720p first (the default preselection), then 1080p, Best, then the rest.
|
||||
_BUILTINS = [
|
||||
("720p (MP4)", _spec("av", 720, "mp4"), 10),
|
||||
("1080p (MP4)", _spec("av", 1080, "mp4"), 20),
|
||||
("Best (MP4)", _spec("av", None, "mp4"), 30),
|
||||
("Audio (M4A)", _spec("a", None, None, "m4a"), 40),
|
||||
("Audio (MP3)", _spec("a", None, None, "mp3"), 50),
|
||||
("Video only (MP4)", _spec("v", None, "mp4"), 60),
|
||||
]
|
||||
|
||||
_profiles = sa.table(
|
||||
"download_profiles",
|
||||
sa.column("user_id", sa.Integer),
|
||||
sa.column("name", sa.String),
|
||||
sa.column("spec", sa.JSON),
|
||||
sa.column("is_builtin", sa.Boolean),
|
||||
sa.column("sort_order", sa.Integer),
|
||||
)
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
op.execute("DELETE FROM download_profiles WHERE is_builtin = true")
|
||||
op.bulk_insert(
|
||||
_profiles,
|
||||
[
|
||||
{"user_id": None, "name": n, "spec": s, "is_builtin": True, "sort_order": o}
|
||||
for n, s, o in _BUILTINS
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
# No-op: the previous builtin set (1080p first) was seeded by 0040; not worth reconstructing.
|
||||
pass
|
||||
Reference in New Issue
Block a user