From d7fe3c34e8de5c1f2a0615c8b591b71a2a923b3d Mon Sep 17 00:00:00 2001 From: npeter83 Date: Fri, 3 Jul 2026 04:08:53 +0200 Subject: [PATCH] improvement(downloads): no-embed builtin presets + 1080p default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Embedding (thumbnail/chapters) rewrote the whole file — a 10 GB video spent minutes making a 10 GB temp copy — while the Plex .nfo + poster sidecars already carry that metadata. So: - builtin presets no longer embed (migration 0040 re-seeds them; formats._DEFAULTS embed off); only the tiny FFmpegThumbnailsConvertor (for poster.jpg) remains, so downloads go video -> audio -> merge -> done with no full-file rewrite - default preset is now 1080p (Best stays available, second in the list) so a long video doesn't silently pull ~10 GB and blow the quota Users who want self-contained files can enable embedding in a custom profile. --- .../versions/0040_reset_builtin_profiles.py | 72 +++++++++++++++++++ backend/app/downloads/formats.py | 7 +- 2 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 backend/alembic/versions/0040_reset_builtin_profiles.py diff --git a/backend/alembic/versions/0040_reset_builtin_profiles.py b/backend/alembic/versions/0040_reset_builtin_profiles.py new file mode 100644 index 0000000..ed3de02 --- /dev/null +++ b/backend/alembic/versions/0040_reset_builtin_profiles.py @@ -0,0 +1,72 @@ +"""reset builtin download profiles: no embedding, 1080p default + +Revision ID: 0040_reset_profiles +Revises: 0039_title_normalize +Create Date: 2026-07-03 + +Redefines the shipped presets: embedding (thumbnail/chapters/subs) is OFF (it rewrites the whole +file — expensive on large videos — and the Plex .nfo/poster sidecars already carry the metadata), +and the default is now 1080p (Best stays available but no longer first). Re-seeds the builtin +rows so both fresh installs (0037 then this) and existing DBs converge on the same set. Existing +jobs are unaffected (they snapshot their spec; profile_id just SET NULLs if it pointed at a +replaced row). +""" +from typing import Sequence, Union + +import sqlalchemy as sa +from alembic import op + +revision: str = "0040_reset_profiles" +down_revision: Union[str, None] = "0039_title_normalize" +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, + } + + +# Default first (1080p), then Best, then the rest. +_BUILTINS = [ + ("1080p (MP4)", _spec("av", 1080, "mp4"), 10), + ("Best (MP4)", _spec("av", None, "mp4"), 20), + ("720p (MP4)", _spec("av", 720, "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 was seeded by 0037; not worth reconstructing. + pass diff --git a/backend/app/downloads/formats.py b/backend/app/downloads/formats.py index 8fc710d..02e1f71 100644 --- a/backend/app/downloads/formats.py +++ b/backend/app/downloads/formats.py @@ -35,9 +35,12 @@ _DEFAULTS = { "container": "mp4", "audio_format": "m4a", "vcodec": None, + # Embedding is OFF by default: it rewrites the whole file (doubles I/O — a 10 GB video + # gets a 10 GB temp copy), and the Plex `.nfo` + poster sidecars already carry the + # metadata/thumbnail. Users who want self-contained files opt in via a custom profile. "embed_subs": False, - "embed_chapters": True, - "embed_thumbnail": True, + "embed_chapters": False, + "embed_thumbnail": False, "sponsorblock": False, }