using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using Jellyfin.Data.Enums; using Jellyfin.Extensions; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Dto; namespace Jellyfin.Model.Tests.Dlna; public class LegacyStreamInfo : StreamInfo { public LegacyStreamInfo(Guid itemId, DlnaProfileType mediaType) { ItemId = itemId; MediaType = mediaType; } /// /// The 10.6 ToUrl code from StreamInfo.cs with which to compare new version. /// /// The base url to use. /// The Access token. /// A url. public string ToUrl_Original(string baseUrl, string? accessToken) { ArgumentException.ThrowIfNullOrEmpty(baseUrl); var list = new List(); foreach (NameValuePair pair in BuildParams(this, accessToken)) { if (string.IsNullOrEmpty(pair.Value)) { continue; } // Try to keep the url clean by omitting defaults if (string.Equals(pair.Name, "StartTimeTicks", StringComparison.OrdinalIgnoreCase) && string.Equals(pair.Value, "0", StringComparison.OrdinalIgnoreCase)) { continue; } if (string.Equals(pair.Name, "SubtitleStreamIndex", StringComparison.OrdinalIgnoreCase) && string.Equals(pair.Value, "-1", StringComparison.OrdinalIgnoreCase)) { continue; } if (string.Equals(pair.Name, "Static", StringComparison.OrdinalIgnoreCase) && string.Equals(pair.Value, "false", StringComparison.OrdinalIgnoreCase)) { continue; } var encodedValue = pair.Value.Replace(" ", "%20", StringComparison.Ordinal); list.Add(string.Format(CultureInfo.InvariantCulture, "{0}={1}", pair.Name, encodedValue)); } string queryString = string.Join('&', list); return GetUrl(baseUrl, queryString); } private string GetUrl(string baseUrl, string queryString) { ArgumentException.ThrowIfNullOrEmpty(baseUrl); string extension = string.IsNullOrEmpty(Container) ? string.Empty : "." + Container; baseUrl = baseUrl.TrimEnd('/'); if (MediaType == DlnaProfileType.Audio) { if (SubProtocol == MediaStreamProtocol.hls) { return string.Format(CultureInfo.InvariantCulture, "{0}/audio/{1}/master.m3u8?{2}", baseUrl, ItemId, queryString); } return string.Format(CultureInfo.InvariantCulture, "{0}/audio/{1}/stream{2}?{3}", baseUrl, ItemId, extension, queryString); } if (SubProtocol == MediaStreamProtocol.hls) { return string.Format(CultureInfo.InvariantCulture, "{0}/videos/{1}/master.m3u8?{2}", baseUrl, ItemId, queryString); } return string.Format(CultureInfo.InvariantCulture, "{0}/videos/{1}/stream{2}?{3}", baseUrl, ItemId, extension, queryString); } private static List BuildParams(StreamInfo item, string? accessToken) { List list = []; string audioCodecs = item.AudioCodecs.Count == 0 ? string.Empty : string.Join(',', item.AudioCodecs); string videoCodecs = item.VideoCodecs.Count == 0 ? string.Empty : string.Join(',', item.VideoCodecs); list.Add(new NameValuePair("DeviceProfileId", item.DeviceProfileId ?? string.Empty)); list.Add(new NameValuePair("DeviceId", item.DeviceId ?? string.Empty)); list.Add(new NameValuePair("MediaSourceId", item.MediaSourceId ?? string.Empty)); list.Add(new NameValuePair("Static", item.IsDirectStream.ToString(CultureInfo.InvariantCulture).ToLowerInvariant())); list.Add(new NameValuePair("VideoCodec", videoCodecs)); list.Add(new NameValuePair("AudioCodec", audioCodecs)); list.Add(new NameValuePair("AudioStreamIndex", item.AudioStreamIndex.HasValue ? item.AudioStreamIndex.Value.ToString(CultureInfo.InvariantCulture) : string.Empty)); list.Add(new NameValuePair("SubtitleStreamIndex", item.SubtitleStreamIndex.HasValue && (item.AlwaysBurnInSubtitleWhenTranscoding || item.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External) ? item.SubtitleStreamIndex.Value.ToString(CultureInfo.InvariantCulture) : string.Empty)); list.Add(new NameValuePair("VideoBitrate", item.VideoBitrate.HasValue ? item.VideoBitrate.Value.ToString(CultureInfo.InvariantCulture) : string.Empty)); list.Add(new NameValuePair("AudioBitrate", item.AudioBitrate.HasValue ? item.AudioBitrate.Value.ToString(CultureInfo.InvariantCulture) : string.Empty)); list.Add(new NameValuePair("AudioSampleRate", item.AudioSampleRate.HasValue ? item.AudioSampleRate.Value.ToString(CultureInfo.InvariantCulture) : string.Empty)); list.Add(new NameValuePair("MaxFramerate", item.MaxFramerate.HasValue ? item.MaxFramerate.Value.ToString(CultureInfo.InvariantCulture) : string.Empty)); list.Add(new NameValuePair("MaxWidth", item.MaxWidth.HasValue ? item.MaxWidth.Value.ToString(CultureInfo.InvariantCulture) : string.Empty)); list.Add(new NameValuePair("MaxHeight", item.MaxHeight.HasValue ? item.MaxHeight.Value.ToString(CultureInfo.InvariantCulture) : string.Empty)); long startPositionTicks = item.StartPositionTicks; if (item.SubProtocol == MediaStreamProtocol.hls) { list.Add(new NameValuePair("StartTimeTicks", string.Empty)); list.Add(new NameValuePair("SegmentContainer", item.Container ?? string.Empty)); if (item.SegmentLength.HasValue) { list.Add(new NameValuePair("SegmentLength", item.SegmentLength.Value.ToString(CultureInfo.InvariantCulture))); } if (item.MinSegments.HasValue) { list.Add(new NameValuePair("MinSegments", item.MinSegments.Value.ToString(CultureInfo.InvariantCulture))); } list.Add(new NameValuePair("BreakOnNonKeyFrames", item.BreakOnNonKeyFrames.ToString(CultureInfo.InvariantCulture))); } else { list.Add(new NameValuePair("StartTimeTicks", startPositionTicks.ToString(CultureInfo.InvariantCulture))); } list.Add(new NameValuePair("PlaySessionId", item.PlaySessionId ?? string.Empty)); list.Add(new NameValuePair("ApiKey", accessToken ?? string.Empty)); string? liveStreamId = item.MediaSource?.LiveStreamId; list.Add(new NameValuePair("LiveStreamId", liveStreamId ?? string.Empty)); if (!item.IsDirectStream) { if (item.RequireNonAnamorphic) { list.Add(new NameValuePair("RequireNonAnamorphic", item.RequireNonAnamorphic.ToString(CultureInfo.InvariantCulture).ToLowerInvariant())); } list.Add(new NameValuePair("TranscodingMaxAudioChannels", item.TranscodingMaxAudioChannels.HasValue ? item.TranscodingMaxAudioChannels.Value.ToString(CultureInfo.InvariantCulture) : string.Empty)); if (item.EnableSubtitlesInManifest) { list.Add(new NameValuePair("EnableSubtitlesInManifest", item.EnableSubtitlesInManifest.ToString(CultureInfo.InvariantCulture).ToLowerInvariant())); } if (item.EnableMpegtsM2TsMode) { list.Add(new NameValuePair("EnableMpegtsM2TsMode", item.EnableMpegtsM2TsMode.ToString(CultureInfo.InvariantCulture).ToLowerInvariant())); } if (item.EstimateContentLength) { list.Add(new NameValuePair("EstimateContentLength", item.EstimateContentLength.ToString(CultureInfo.InvariantCulture).ToLowerInvariant())); } if (item.TranscodeSeekInfo != TranscodeSeekInfo.Auto) { list.Add(new NameValuePair("TranscodeSeekInfo", item.TranscodeSeekInfo.ToString().ToLowerInvariant())); } if (item.CopyTimestamps) { list.Add(new NameValuePair("CopyTimestamps", item.CopyTimestamps.ToString(CultureInfo.InvariantCulture).ToLowerInvariant())); } list.Add(new NameValuePair("RequireAvc", item.RequireAvc.ToString(CultureInfo.InvariantCulture).ToLowerInvariant())); list.Add(new NameValuePair("EnableAudioVbrEncoding", item.EnableAudioVbrEncoding.ToString(CultureInfo.InvariantCulture).ToLowerInvariant())); } list.Add(new NameValuePair("Tag", item.MediaSource?.ETag ?? string.Empty)); string subtitleCodecs = item.SubtitleCodecs.Count == 0 ? string.Empty : string.Join(",", item.SubtitleCodecs); list.Add(new NameValuePair("SubtitleCodec", item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Embed ? subtitleCodecs : string.Empty)); list.Add(new NameValuePair("SubtitleMethod", item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External ? item.SubtitleDeliveryMethod.ToString() : string.Empty)); foreach (var pair in item.StreamOptions) { if (string.IsNullOrEmpty(pair.Value)) { continue; } // strip spaces to avoid having to encode h264 profile names list.Add(new NameValuePair(pair.Key, pair.Value.Replace(" ", string.Empty, StringComparison.Ordinal))); } var transcodeReasonsValues = item.TranscodeReasons.GetUniqueFlags().ToArray(); if (!item.IsDirectStream && transcodeReasonsValues.Length > 0) { list.Add(new NameValuePair("TranscodeReasons", item.TranscodeReasons.ToString())); } return list; } }