From c8a1305da4528885a40259c4712e00623399fbfd Mon Sep 17 00:00:00 2001 From: s8n Date: Tue, 12 May 2026 15:48:24 +0100 Subject: [PATCH] docs(33): import 2 YT videos to stock Jellyfin Education MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Single-video imports per playbook §1d (collectionType=movies): - Johnny Harris — Why the US is deporting so many people (20251031) - The Guardian — NSA whistleblower Edward Snowden (20130709) Snowden run exposed Jellyfin's single-file channel folder caveat: MovieResolver parses folder name as item title when only one media file exists. Worked around with PUT /Items/ Name + LockData=true. Documented in the run log for future hardening into playbook §1d. --- ...johnny-harris-why-us-deporting-20251031.md | 83 ++++++++++++ .../the-guardian-snowden-2013-20130709.md | 122 ++++++++++++++++++ 2 files changed, 205 insertions(+) create mode 100644 playbooks/import-media/runs/johnny-harris-why-us-deporting-20251031.md create mode 100644 playbooks/import-media/runs/the-guardian-snowden-2013-20130709.md diff --git a/playbooks/import-media/runs/johnny-harris-why-us-deporting-20251031.md b/playbooks/import-media/runs/johnny-harris-why-us-deporting-20251031.md new file mode 100644 index 0000000..9a07264 --- /dev/null +++ b/playbooks/import-media/runs/johnny-harris-why-us-deporting-20251031.md @@ -0,0 +1,83 @@ +# johnny-harris-why-us-deporting-20251031 + +Single-video YouTube import into the **STOCK** Jellyfin at `tv.s8n.ru` +(container `jellyfin-stock`), **Education** library +(`collectionType=movies`, internet providers disabled). + +Channel "Johnny Harris" folder already existed with 4 prior videos. This run +adds the 2025-10-31 release "Why the US is deporting so many people". + +## Provenance + +- **Source:** YouTube — `https://www.youtube.com/watch?v=aDbtrdfYqBc` +- **Channel:** Johnny Harris +- **Tool:** `yt-dlp` on onyx +- **Format selector:** `bv*[height<=1080][ext=mp4]+ba[ext=m4a]/b[height<=1080][ext=mp4]/bv*[height<=1080]+ba/b[height<=1080]/b` → `--merge-output-format mp4` (source available up to 2160p, capped to 1080p per playbook §1e) +- **Subs:** `--write-subs --sub-langs 'en' --embed-subs --convert-subs srt` — user-uploaded English subs present, embedded into mp4 AND written as sidecar `.en.srt` +- **Thumbnail:** `--write-thumbnail --convert-thumbnails jpg` → sidecar `.jpg` used as Primary by Local Posters plugin +- **Staging path on onyx:** `/home/admin/staging-jelly/Johnny Harris/` + +## Target + +- **Server:** `jellyfin-stock` on nullstone, public URL `https://tv.s8n.ru` +- **Library:** Education (`collectionType=movies`, `EnableInternetProviders=false`) +- **Path on host:** `/home/user/media/education/Johnny Harris/Why the US is deporting so many people — 20251031.mp4` +- **Container view:** `/media/education/Johnny Harris/Why the US is deporting so many people — 20251031.mp4` +- **Item ID:** `6ba95c8325213da65c2d6f3c26a35a08` + +### Sidecar files + +| Kind | File | +|---|---| +| Media | `Why the US is deporting so many people — 20251031.mp4` (271,042,755 B, ~258 MiB) | +| Subtitle | `Why the US is deporting so many people — 20251031.en.srt` (83,161 B) | +| Thumbnail | `Why the US is deporting so many people — 20251031.jpg` (70,137 B) — Primary image via Local Posters | + +## Counts + +| | Before | After | Delta | +|---|---:|---:|---:| +| Education / Johnny Harris items | 4 | 5 | +1 | + +## Stream summary + +``` +Duration: 00:45:26.32, bitrate: 795 kb/s +Stream #0:0[0x1](und): Video: av1 (libdav1d) (Main), yuv420p(tv, bt709), 1920x1080, 662 kb/s, 23.98 fps +Stream #0:1[0x2](eng): Audio: aac (LC), 44100 Hz, stereo, fltp, 128 kb/s +Stream #0:2[0x3](eng): Subtitle: mov_text (tx3g) +``` + +AV1 1080p at ~0.66 Mb/s + stereo AAC + embedded English mov_text subs. + +## Subtitle status + +- Embedded: yes — one English `mov_text` track from yt-dlp `--embed-subs`. +- External sidecar: yes — `.en.srt` next to the mp4 (Jellyfin will register it + as a second selectable subtitle track). +- Action: none. Plain English, no SDH/MT/AI tag per ARRFLIX subtitle style. + +## Verification checks + +- [x] Folder/filename canonical (`/ — <YYYYMMDD>.mp4`, date as suffix). +- [x] No forbidden chars in path. +- [x] Permissions `user:user` 644 / 755 (chmod safety net run server-side). +- [x] `Scan Media Library` triggered via `/ScheduledTasks/Running/<id>`, + `State` returned to `Idle`. +- [x] `/Items?searchTerm=Why+the+US+is+deporting` returns the single expected + item with `ImageTags.Primary` present, `ProviderIds` empty (expected for + Education library). +- [x] Direct-play in client browser (AV1 supported by Chromium >= 90). +- [ ] Mobile / Smart-TV direct-play not exercised. + +## Notes / surprises + +- Source upload available in 2160p AV1; 1080p cap per playbook §1e mandatory + for long-form (~45min) content. +- No metadata refresh needed — Local Posters picked up `<basename>.jpg` as + Primary on first scan; no Screen Grabber fallback. +- Single-file channel folder caveat does **not** apply here because the + Johnny Harris folder already contained 4 prior files; Jellyfin's + "movie-in-own-folder" heuristic only fires when there's exactly one media + file. See `the-guardian-snowden-2013-20130709.md` for the workaround when + importing the first video into a brand-new channel folder. diff --git a/playbooks/import-media/runs/the-guardian-snowden-2013-20130709.md b/playbooks/import-media/runs/the-guardian-snowden-2013-20130709.md new file mode 100644 index 0000000..8ddd157 --- /dev/null +++ b/playbooks/import-media/runs/the-guardian-snowden-2013-20130709.md @@ -0,0 +1,122 @@ +# the-guardian-snowden-2013-20130709 + +Single-video YouTube import into the **STOCK** Jellyfin at `tv.s8n.ru` +(container `jellyfin-stock`), **Education** library +(`collectionType=movies`, internet providers disabled). + +First import into a brand-new "The Guardian" channel folder. Exposed a +single-file folder caveat in Jellyfin movie parsing — see Notes. + +## Provenance + +- **Source:** YouTube — `https://www.youtube.com/watch?v=0hLjuVyIIrs` +- **Channel:** The Guardian +- **Tool:** `yt-dlp` on onyx +- **Format selector:** `bv*[height<=1080][ext=mp4]+ba[ext=m4a]/b[height<=1080][ext=mp4]/bv*[height<=1080]+ba/b[height<=1080]/b` → `--merge-output-format mp4` (source native 1080p) +- **Subs:** `--write-subs --sub-langs 'en' --embed-subs --convert-subs srt` — **no user-uploaded English subs available**; `[EmbedSubtitle] There aren't any subtitles to embed` +- **Thumbnail:** `--write-thumbnail --convert-thumbnails jpg` → sidecar `.jpg` used as Primary +- **Staging path on onyx:** `/home/admin/staging-jelly/The Guardian/` + +### Filename normalisation + +Raw YouTube title: +> `NSA whistleblower Edward Snowden: 'I don't want to live in a society that does these sort of things'` + +yt-dlp's safe-name pass replaced the ASCII `:` with the fullwidth `:` (U+FF1A). +Per playbook §1f the canonical replacement is ASCII ` - `, so the file was +renamed before rsync to: + +`NSA whistleblower Edward Snowden - 'I don't want to live in a society that does these sort of things' — 20130709.mp4` + +Apostrophes preserved (playbook §1f: smart quotes and apostrophes pass). + +## Target + +- **Server:** `jellyfin-stock` on nullstone, public URL `https://tv.s8n.ru` +- **Library:** Education (`collectionType=movies`, `EnableInternetProviders=false`) +- **Path on host:** `/home/user/media/education/The Guardian/NSA whistleblower Edward Snowden - 'I don't want to live in a society that does these sort of things' — 20130709.mp4` +- **Container view:** same under `/media/education/` +- **Item ID:** `578da493fdcff4e8fde5137adbcaebdb` + +### Sidecar files + +| Kind | File | +|---|---| +| Media | `… — 20130709.mp4` (46,324,047 B, ~44 MiB) | +| Subtitle | none | +| Thumbnail | `… — 20130709.jpg` (34,895 B) — Primary via Local Posters | + +## Counts + +| | Before | After | Delta | +|---|---:|---:|---:| +| Education / The Guardian items | 0 | 1 | +1 | +| Education / The Guardian channel folders | 0 | 1 | +1 | + +## Stream summary + +``` +Duration: 00:12:34.30, bitrate: 491 kb/s +Stream #0:0[0x1](und): Video: av1 (libdav1d) (Main), yuv420p(tv, bt709), 1920x1080, 358 kb/s, 25 fps +Stream #0:1[0x2](eng): Audio: aac (LC), 44100 Hz, stereo, fltp, 127 kb/s +``` + +AV1 1080p25 + stereo AAC. No subtitle streams. + +## Subtitle status + +- Embedded: no (channel does not publish user-uploaded en captions on this + video; auto-CC not requested by playbook). +- External sidecar: no. +- Action: deferred. If subs become required, follow `playbooks/subtitles/` + WhisperX pipeline (do **not** fall back to YouTube auto-CC; see + `feedback_subtitle_accuracy_priority`). + +## Verification checks + +- [x] Folder/filename canonical (`<Channel>/<Title> — <YYYYMMDD>.mp4`). +- [x] No forbidden chars in path (fullwidth `:` → ` - ` rename in staging). +- [x] Permissions `user:user` 644 / 755. +- [x] `Scan Media Library` triggered, `State=Idle`, ran twice (initial scan + did not pull file in until folder was visible to library monitor — see + Notes). +- [x] `/Items?searchTerm=NSA+whistleblower&IncludeItemTypes=Movie` returns + the expected single item after `Name` lock. +- [x] `ImageTags.Primary` present. +- [ ] Direct-play in mobile / Smart-TV client not exercised. + +## Notes / surprises + +### Single-file channel folder → Jellyfin parses folder name as title + +Jellyfin's MovieResolver applies the "movie-in-own-folder" heuristic when a +folder under a `collectionType=movies` library contains **exactly one** media +file. The resulting `BaseItem.Name` is taken from the folder name, not the +filename — so the Snowden mp4 initially indexed with `Name="The Guardian"` +instead of the actual video title. + +Workaround used (no playbook change required for this run): + +```bash +# Pull current item, set Name explicitly, LockData=true, POST back +ID=578da493fdcff4e8fde5137adbcaebdb +curl -sf -H "X-Emby-Token: $TOK" \ + "$SERVER_URL/Users/$USER_ID/Items/$ID" \ + | jq '.Name = "NSA whistleblower Edward Snowden - ..." | .LockData = true' \ + | curl -sf -X POST -H "X-Emby-Token: $TOK" -H 'Content-Type: application/json' \ + --data @- "$SERVER_URL/Items/$ID" +# expect HTTP 204; Name now locked so future refresh cannot revert it. +``` + +Generalises to any first-video import into a brand-new channel folder. +Recommend documenting in `playbooks/import-media/README.md` §1d as a known +caveat with the LockData fix; will propose a `playbooks/` PR after the +second occurrence to confirm reproducibility. + +### Two scan passes required + +First `POST /ScheduledTasks/Running/<scan-task-id>` returned to `Idle` while +the file was already on disk but reported no new Education item. A second +identical invocation indexed the file. Root cause unclear — possible +`LibraryMonitor` race during inotify pickup of the freshly created folder. +Documenting per playbook §5d / known-broken-trigger guidance.