2 Commits

Author SHA1 Message Date
Martin
d6280f3ce8 fix: built-in downloader prefers separate streams over 360p muxed (v1.0.0.16)
All checks were successful
Publish Release / release (push) Successful in 24s
When YouTube offered a muxed stream, it was always taken, but muxed streams
are 360p only. Use muxed only when the separate video+audio streams are
missing or not better.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-05 21:39:49 -04:00
gitea-actions
43e002fcdd chore: update manifest.json for v1.0.0.15 2026-10-05 22:28:03 +00:00
4 changed files with 35 additions and 22 deletions

View File

@@ -3,8 +3,8 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<RootNamespace>Jellyfin.Plugin.CinemaTrailers4Jellyfins</RootNamespace> <RootNamespace>Jellyfin.Plugin.CinemaTrailers4Jellyfins</RootNamespace>
<AssemblyVersion>1.0.0.15</AssemblyVersion> <AssemblyVersion>1.0.0.16</AssemblyVersion>
<FileVersion>1.0.0.15</FileVersion> <FileVersion>1.0.0.16</FileVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<GenerateDocumentationFile>false</GenerateDocumentationFile> <GenerateDocumentationFile>false</GenerateDocumentationFile>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors> <TreatWarningsAsErrors>false</TreatWarningsAsErrors>

View File

@@ -90,31 +90,37 @@ namespace Jellyfin.Plugin.CinemaTrailers4Jellyfins.Services
.GetManifestAsync($"https://www.youtube.com/watch?v={key}", ct) .GetManifestAsync($"https://www.youtube.com/watch?v={key}", ct)
.ConfigureAwait(false); .ConfigureAwait(false);
// Muxed streams include audio+video in one file. YouTube rarely serves them // Best video-only stream at or below the height limit. MP4 (H.264) is preferred for
// anymore, but use one when it exists since it needs no merge. // client compatibility; any container is the fallback.
var videoStreams = manifest.GetVideoOnlyStreams().ToList();
var audioStreams = manifest.GetAudioOnlyStreams().ToList();
var mp4Video = videoStreams.Where(s => s.Container == Container.Mp4).ToList();
var video = videoStreams.Count > 0
? PickByHeight(mp4Video.Count > 0 ? mp4Video : videoStreams, preferredHeight)
: null;
// Muxed streams (audio+video in one file) need no merge, but YouTube only serves
// them at 360p. Use one only when the separate streams can't do better.
var muxedStreams = manifest.GetMuxedStreams().ToList(); var muxedStreams = manifest.GetMuxedStreams().ToList();
if (muxedStreams.Count > 0) if (muxedStreams.Count > 0)
{ {
var muxed = PickByHeight(muxedStreams, preferredHeight); var muxed = PickByHeight(muxedStreams, preferredHeight);
if (video == null || audioStreams.Count == 0
|| muxed.VideoQuality.MaxHeight >= video.VideoQuality.MaxHeight)
{
_logger.LogInformation( _logger.LogInformation(
"|CinemaTrailers4Jellyfins| Downloading {Key} at {Quality} (muxed) to {Path}", "|CinemaTrailers4Jellyfins| Downloading {Key} at {Quality} (muxed) to {Path}",
key, muxed.VideoQuality.Label, outputPath); key, muxed.VideoQuality.Label, outputPath);
await youtube.Videos.Streams.DownloadAsync(muxed, outputPath, cancellationToken: ct).ConfigureAwait(false); await youtube.Videos.Streams.DownloadAsync(muxed, outputPath, cancellationToken: ct).ConfigureAwait(false);
return true; return true;
} }
}
// Otherwise download the best video-only and audio-only streams and merge them. if (video == null || audioStreams.Count == 0)
// MP4 (H.264/AAC) is preferred for client compatibility; any container is the fallback.
var videoStreams = manifest.GetVideoOnlyStreams().ToList();
var audioStreams = manifest.GetAudioOnlyStreams().ToList();
if (videoStreams.Count == 0 || audioStreams.Count == 0)
{ {
_logger.LogWarning("|CinemaTrailers4Jellyfins| No usable video/audio streams for {Key}.", key); _logger.LogWarning("|CinemaTrailers4Jellyfins| No usable video/audio streams for {Key}.", key);
return false; return false;
} }
var mp4Video = videoStreams.Where(s => s.Container == Container.Mp4).ToList();
var video = PickByHeight(mp4Video.Count > 0 ? mp4Video : videoStreams, preferredHeight);
var mp4Audio = audioStreams.Where(s => s.Container == Container.Mp4).ToList(); var mp4Audio = audioStreams.Where(s => s.Container == Container.Mp4).ToList();
var audio = (mp4Audio.Count > 0 ? mp4Audio : audioStreams).GetWithHighestBitrate(); var audio = (mp4Audio.Count > 0 ? mp4Audio : audioStreams).GetWithHighestBitrate();

View File

@@ -1,5 +1,5 @@
--- ---
version: 1.0.0.15 version: 1.0.0.16
name: CinemaTrailers4Jellyfins name: CinemaTrailers4Jellyfins
guid: b581493e-1046-40ed-b6dc-cb8027624984 guid: b581493e-1046-40ed-b6dc-cb8027624984
description: > description: >
@@ -12,10 +12,9 @@ category: General
owner: 514mart owner: 514mart
targetAbi: 10.11.0.0 targetAbi: 10.11.0.0
changelog: changelog:
- Trailer Languages now also checks the original language of the movie or - The built-in downloader no longer picks YouTube's 360p combined file
show. Before, only the trailer's own language tag was checked, and when separate video and audio streams give a better picture. This
TMDB often tags subtitled foreign trailers as English, so Korean, mostly showed up when yt-dlp failed and the built-in downloader took over
Chinese or Japanese trailers got through
dotnetProjects: dotnetProjects:
- name: Jellyfin.Plugin.CinemaTrailers4Jellyfins - name: Jellyfin.Plugin.CinemaTrailers4Jellyfins

View File

@@ -8,6 +8,14 @@
"owner": "514mart", "owner": "514mart",
"imageUrl": "https://www.git.quarantinedstudio.com/mvezina/CinemaTrailers4Jellyfins/raw/branch/main/Jellyfin.Plugin.CinemaTrailers4Jellyfins/Images/logo.svg", "imageUrl": "https://www.git.quarantinedstudio.com/mvezina/CinemaTrailers4Jellyfins/raw/branch/main/Jellyfin.Plugin.CinemaTrailers4Jellyfins/Images/logo.svg",
"versions": [ "versions": [
{
"checksum": "211f58d992857f9e91263293306fbd0d",
"changelog": "- Trailer Languages now also checks the original language of the movie or show. Before, only the trailer's own language tag was checked, and TMDB often tags subtitled foreign trailers as English, so Korean, Chinese or Japanese trailers got through\n",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://www.git.quarantinedstudio.com/mvezina/CinemaTrailers4Jellyfins/releases/download/v1.0.0.15/cinematrailers4jellyfins_1.0.0.15.zip",
"timestamp": "2026-10-05T22:28:03Z",
"version": "1.0.0.15"
},
{ {
"checksum": "10ecbc35b84e98bade61576bbfc41864", "checksum": "10ecbc35b84e98bade61576bbfc41864",
"changelog": "- When yt-dlp fails part-way, its partial download files (.part, .ytdl, separate video/audio) are now deleted instead of being left in the trailer folder\n", "changelog": "- When yt-dlp fails part-way, its partial download files (.part, .ytdl, separate video/audio) are now deleted instead of being left in the trailer folder\n",