Adds SAVE_MEDIA_AFTER_BULK_ACTION (env:
TUBESYNC_SAVE_MEDIA_AFTER_BULK_ACTION, default False). When enabled,
each admin bulk action queues a save_media task per changed item so
flags are re-evaluated without waiting for the next source edit or
indexing run. When disabled (the default) behaviour is unchanged:
re-evaluation happens on the next source edit/index pass.
Requested by tcely in review.
Addresses review feedback:
- truncate_filename_bytes parses stem/suffix with PurePosixPath instead
of str.rpartition; Media.filename splits directory/name with
PurePosixPath.with_name instead of string slicing
- non-str input now raises TypeError (was ValueError) to match the
type-error semantics
- new tests cover bytes known to cause encoding/decoding trouble: cuts
landing inside 4-byte emoji, combining sequences, ZWJ families,
mixed-width boundaries, RTL text, dotfiles, no-extension and
oversized-extension names — asserting byte budget, UTF-8 round-trip
validity, and non-empty results in every case
Managing large libraries through the Django admin required editing
every media item individually to toggle 'skip' or 'can download'
(#493). Add the standard admin bulk actions for exactly the two
fields requested there:
- Set / unset 'skip' — also sets manual_skip to match, so a bulk
un-skip is not immediately re-skipped by the filtering logic, and a
bulk skip is treated as the operator's explicit decision
- Set / unset 'can download'
Also adds list_filter for can_download/skip/downloaded so the items
to bulk-edit can actually be narrowed down first.
Uses queryset.update() so a bulk action on thousands of rows is a
single UPDATE, not thousands of model saves.
Tests cover both action pairs and the action registration.
Fixes#493
Filesystems limit each path component to 255 bytes, not characters.
Multi-byte titles (CJK, emoji) hit that with far fewer characters — a
98-character Japanese title is already 225+ bytes before TubeSync adds
prefixes and yt-dlp adds '.fNNN.mp4.part(-FragNN)' suffixes — and the
download then fails permanently with:
ERROR: unable to open for writing: [Errno 36] File name too long
(#522). The task retries and fails forever with no way out short of
renaming the source format.
Media.filename now clamps the final name component to a 200-byte
budget (leaving headroom for the suffixes appended during download):
- only the name component is shortened; directories from the format
string are preserved untouched
- bytes are removed from the middle of the stem, keeping its start
(the beginning of the title) and its end (the unique {key}/{format}
suffixes of the default media format), joined by '_..._' — so
uniqueness of generated names survives truncation
- truncation never splits a multi-byte character (partial sequences
are dropped when decoding)
- a warning is logged when a name is shortened
Names within the limit are returned byte-identical, so existing
installs see no change unless they were already broken.
Fixes#522