From 88635e929e57c052a3cdd0f8c65467c80d6a77ca Mon Sep 17 00:00:00 2001 From: Scrub <72096833+ScrubN@users.noreply.github.com> Date: Sat, 20 Jan 2024 20:21:58 -0500 Subject: [PATCH] Improve handling of some source quality related edge cases (#953) * Always sort source quality to the top of the list regardless of video metadata * Return best quality when quality string contains "source" or "chunked" * Always include "Source" in the source stream's quality string because of Twitch API weirdness. Distinguishes between 720p60 (source) and 720p30 (transcoded) when framerates are not included in the M3U8 response. * Cleanup --- .../Extensions/M3U8Extensions.cs | 36 +++++++++++++++---- .../Tools/M3U8StreamQualityComparer.cs | 4 +++ 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/TwitchDownloaderCore/Extensions/M3U8Extensions.cs b/TwitchDownloaderCore/Extensions/M3U8Extensions.cs index 29571e15..a6fbcdd4 100644 --- a/TwitchDownloaderCore/Extensions/M3U8Extensions.cs +++ b/TwitchDownloaderCore/Extensions/M3U8Extensions.cs @@ -37,6 +37,11 @@ public static M3U8.Stream GetStreamOfQuality(this M3U8 m3u8, string qualityStrin return m3u8.BestQualityStream(); } + if (qualityString.Contains("source", StringComparison.OrdinalIgnoreCase) || qualityString.Contains("chunked", StringComparison.OrdinalIgnoreCase)) + { + return m3u8.BestQualityStream(); + } + if (qualityString.Contains("audio", StringComparison.OrdinalIgnoreCase) && streams.FirstOrDefault(x => x.MediaInfo.Name.Contains("audio", StringComparison.OrdinalIgnoreCase)) is { } audioStream) { @@ -84,25 +89,32 @@ public static M3U8.Stream GetStreamOfQuality(this M3U8 m3u8, string qualityStrin /// public static string GetResolutionFramerateString(this M3U8.Stream stream) { + const string RESOLUTION_FRAMERATE_PATTERN = /*lang=regex*/@"\d{3,4}p\d{2,3}"; + var mediaInfo = stream.MediaInfo; - if (mediaInfo.Name.Contains("audio", StringComparison.OrdinalIgnoreCase) || Regex.IsMatch(mediaInfo.Name, @"\d{3,4}p\d{2,3}")) + if (mediaInfo.Name.Contains("audio", StringComparison.OrdinalIgnoreCase) || Regex.IsMatch(mediaInfo.Name, RESOLUTION_FRAMERATE_PATTERN)) { return mediaInfo.Name; } var streamInfo = stream.StreamInfo; - if (Regex.IsMatch(streamInfo.Video, @"\d{3,4}p\d{2,3}")) + if (Regex.IsMatch(streamInfo.Video, RESOLUTION_FRAMERATE_PATTERN)) { return streamInfo.Video; } - if (Regex.IsMatch(mediaInfo.GroupId, @"\d{3,4}p\d{2,3}")) + if (Regex.IsMatch(mediaInfo.GroupId, RESOLUTION_FRAMERATE_PATTERN)) { return mediaInfo.GroupId; } if (streamInfo.Resolution == default) { + if (stream.IsSource()) + { + return "Source"; + } + return ""; } @@ -110,12 +122,22 @@ public static string GetResolutionFramerateString(this M3U8.Stream stream) if (streamInfo.Framerate == default) { + if (stream.IsSource()) + { + return $"{frameHeight}p (Source)"; + } + return $"{frameHeight}p"; } // Some M3U8 responses have framerate values up to 2fps more/less than the typical framerate. var frameRate = (uint)(Math.Round(streamInfo.Framerate / 10) * 10); + if (stream.IsSource()) + { + return $"{frameHeight}p{frameRate} (Source)"; + } + return $"{frameHeight}p{frameRate}"; } @@ -124,10 +146,12 @@ public static string GetResolutionFramerateString(this M3U8.Stream stream) /// public static M3U8.Stream BestQualityStream(this M3U8 m3u8) { - var source = Array.Find( - m3u8.Streams, x => x.MediaInfo.Name.Contains("source", StringComparison.OrdinalIgnoreCase) || - x.MediaInfo.GroupId.Equals("chunked", StringComparison.OrdinalIgnoreCase)); + var source = Array.Find(m3u8.Streams, x => x.IsSource()); return source ?? m3u8.Streams.MaxBy(x => x.StreamInfo.Resolution.Width * x.StreamInfo.Resolution.Height * x.StreamInfo.Framerate); } + + internal static bool IsSource(this M3U8.Stream stream) + => stream.MediaInfo.Name.Contains("source", StringComparison.OrdinalIgnoreCase) || + stream.MediaInfo.GroupId.Equals("chunked", StringComparison.OrdinalIgnoreCase); } } \ No newline at end of file diff --git a/TwitchDownloaderCore/Tools/M3U8StreamQualityComparer.cs b/TwitchDownloaderCore/Tools/M3U8StreamQualityComparer.cs index a9ec0a6a..af6cd062 100644 --- a/TwitchDownloaderCore/Tools/M3U8StreamQualityComparer.cs +++ b/TwitchDownloaderCore/Tools/M3U8StreamQualityComparer.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using TwitchDownloaderCore.Extensions; namespace TwitchDownloaderCore.Tools { @@ -14,6 +15,9 @@ public int Compare(M3U8.Stream x, M3U8.Stream y) if (y?.StreamInfo is null) return 1; + if (x.IsSource()) return -1; + if (y.IsSource()) return 1; + var xResolution = x.StreamInfo.Resolution; var yResolution = y.StreamInfo.Resolution; var xTotalPixels = xResolution.Width * xResolution.Height;