From 4145e1f1ddb9986dc014cb690dd217a88f4bf75b Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 5 Oct 2026 18:01:33 -0400 Subject: [PATCH] feat: yt-dlp prefers H.264, falls back to built-in, no pipe hang (v1.0.0.13) - Format string prefers avc1 video + m4a audio, then any codec. The RTX 2070 host can hardware-transcode H.264 but not AV1. - Pass Jellyfin's ffmpeg via --ffmpeg-location instead of relying on PATH. - If yt-dlp fails, retry with the built-in YoutubeExplode downloader. - Read stdout/stderr while yt-dlp runs (and add --no-progress); before, stdout was never read, so a full pipe buffer could block yt-dlp forever. Co-Authored-By: Claude Opus 5.5 --- ...fin.Plugin.CinemaTrailers4Jellyfins.csproj | 4 ++-- .../Services/TrailerDownloadService.cs | 21 +++++++++++++------ build.yaml | 14 ++++++------- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/Jellyfin.Plugin.CinemaTrailers4Jellyfins/Jellyfin.Plugin.CinemaTrailers4Jellyfins.csproj b/Jellyfin.Plugin.CinemaTrailers4Jellyfins/Jellyfin.Plugin.CinemaTrailers4Jellyfins.csproj index 98fa8e3..6c73986 100644 --- a/Jellyfin.Plugin.CinemaTrailers4Jellyfins/Jellyfin.Plugin.CinemaTrailers4Jellyfins.csproj +++ b/Jellyfin.Plugin.CinemaTrailers4Jellyfins/Jellyfin.Plugin.CinemaTrailers4Jellyfins.csproj @@ -3,8 +3,8 @@ net9.0 Jellyfin.Plugin.CinemaTrailers4Jellyfins - 1.0.0.12 - 1.0.0.12 + 1.0.0.13 + 1.0.0.13 enable false false diff --git a/Jellyfin.Plugin.CinemaTrailers4Jellyfins/Services/TrailerDownloadService.cs b/Jellyfin.Plugin.CinemaTrailers4Jellyfins/Services/TrailerDownloadService.cs index c6d7aa1..a699318 100644 --- a/Jellyfin.Plugin.CinemaTrailers4Jellyfins/Services/TrailerDownloadService.cs +++ b/Jellyfin.Plugin.CinemaTrailers4Jellyfins/Services/TrailerDownloadService.cs @@ -63,8 +63,10 @@ namespace Jellyfin.Plugin.CinemaTrailers4Jellyfins.Services if (!string.IsNullOrWhiteSpace(ytDlpPath) && File.Exists(ytDlpPath)) { - return await DownloadWithYtDlpAsync(youtubeKey, outputPath, preferredHeight, ytDlpPath, ct) - .ConfigureAwait(false); + if (await DownloadWithYtDlpAsync(youtubeKey, outputPath, preferredHeight, ytDlpPath, ct).ConfigureAwait(false)) + return true; + + _logger.LogWarning("|CinemaTrailers4Jellyfins| yt-dlp failed for {Key}; falling back to the built-in downloader.", youtubeKey); } return await DownloadWithYoutubeExplodeAsync(youtubeKey, outputPath, preferredHeight, ct) @@ -224,13 +226,16 @@ namespace Jellyfin.Plugin.CinemaTrailers4Jellyfins.Services { try { - // Format selects the best video at or below preferredHeight merged with the best audio. - // --merge-output-format mp4 ensures the output is always an mp4. + // Format selects the best video at or below preferredHeight merged with the best audio, + // preferring H.264 + AAC (plays or hardware-transcodes on every client; VP9/AV1 often + // need a CPU transcode). --merge-output-format mp4 ensures the output is always an mp4. var args = string.Join(" ", - $"-f \"bestvideo[height<={preferredHeight}]+bestaudio/best[height<={preferredHeight}]\"", + $"-f \"bestvideo[height<={preferredHeight}][vcodec^=avc1]+bestaudio[ext=m4a]/bestvideo[height<={preferredHeight}]+bestaudio/best[height<={preferredHeight}]\"", "--merge-output-format mp4", "--no-playlist", "--no-warnings", + "--no-progress", + $"--ffmpeg-location \"{FfmpegLocator.Path}\"", $"-o \"{outputPath}\"", $"\"https://www.youtube.com/watch?v={key}\""); @@ -252,11 +257,15 @@ namespace Jellyfin.Plugin.CinemaTrailers4Jellyfins.Services }; process.Start(); + // Drain both pipes while yt-dlp runs so a full buffer can never block it. + var stdoutTask = process.StandardOutput.ReadToEndAsync(ct); + var stderrTask = process.StandardError.ReadToEndAsync(ct); await process.WaitForExitAsync(ct).ConfigureAwait(false); + await stdoutTask.ConfigureAwait(false); + var stderr = await stderrTask.ConfigureAwait(false); if (process.ExitCode != 0) { - var stderr = await process.StandardError.ReadToEndAsync(ct).ConfigureAwait(false); _logger.LogError("|CinemaTrailers4Jellyfins| yt-dlp exited with code {Code} for {Key}: {Error}", process.ExitCode, key, stderr); return false; diff --git a/build.yaml b/build.yaml index 1c3c8de..eb4023d 100644 --- a/build.yaml +++ b/build.yaml @@ -1,5 +1,5 @@ --- -version: 1.0.0.12 +version: 1.0.0.13 name: CinemaTrailers4Jellyfins guid: b581493e-1046-40ed-b6dc-cb8027624984 description: > @@ -12,12 +12,12 @@ category: General owner: 514mart targetAbi: 10.11.0.0 changelog: - - Anime trailers now only play before anime. Western animation (Pixar, - Disney, ...) is no longer blocked and follows the normal genre filter - again. A trailer counts as anime when TMDB tags it "anime" or "based on - manga", or it is animation in Japanese, Chinese or Korean; it is marked - with a ct4j-anime tag in its NFO at download time. Your anime is - recognised by the "Anime" genre or the same TMDB keywords + - yt-dlp now prefers H.264 + AAC (plays or hardware-transcodes on every + client; VP9/AV1 often needed a CPU transcode) and uses Jellyfin's own + ffmpeg for the merge + - If yt-dlp fails, the built-in downloader is tried instead + - Fix a possible hang: yt-dlp's output is now read while it runs, so a + full output buffer can no longer block it dotnetProjects: - name: Jellyfin.Plugin.CinemaTrailers4Jellyfins