diff options
Diffstat (limited to 'MediaBrowser.Controller')
57 files changed, 413 insertions, 259 deletions
diff --git a/MediaBrowser.Controller/Collections/ICollectionManager.cs b/MediaBrowser.Controller/Collections/ICollectionManager.cs index b8c33ee5a..38a78a67b 100644 --- a/MediaBrowser.Controller/Collections/ICollectionManager.cs +++ b/MediaBrowser.Controller/Collections/ICollectionManager.cs @@ -56,5 +56,12 @@ namespace MediaBrowser.Controller.Collections /// <param name="user">The user.</param> /// <returns>IEnumerable{BaseItem}.</returns> IEnumerable<BaseItem> CollapseItemsWithinBoxSets(IEnumerable<BaseItem> items, User user); + + /// <summary> + /// Gets the folder where collections are stored. + /// </summary> + /// <param name="createIfNeeded">Will create the collection folder on the storage if set to true.</param> + /// <returns>The folder instance referencing the collection storage.</returns> + Task<Folder?> GetCollectionsFolder(bool createIfNeeded); } } diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index 11afdc4ae..45ac5c3a8 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -4,7 +4,6 @@ using System.Net; using MediaBrowser.Common; -using MediaBrowser.Common.Net; using MediaBrowser.Model.System; using Microsoft.AspNetCore.Http; @@ -75,10 +74,10 @@ namespace MediaBrowser.Controller /// <summary> /// Gets an URL that can be used to access the API over LAN. /// </summary> - /// <param name="hostname">An optional hostname to use.</param> + /// <param name="ipAddress">An optional IP address to use.</param> /// <param name="allowHttps">A value indicating whether to allow HTTPS.</param> /// <returns>The API URL.</returns> - string GetApiUrlForLocalAccess(IPObject hostname = null, bool allowHttps = true); + string GetApiUrlForLocalAccess(IPAddress ipAddress = null, bool allowHttps = true); /// <summary> /// Gets a local (LAN) URL that can be used to access the API. diff --git a/MediaBrowser.Controller/Lyrics/ILyricParser.cs b/MediaBrowser.Controller/Lyrics/ILyricParser.cs new file mode 100644 index 000000000..65a9471a3 --- /dev/null +++ b/MediaBrowser.Controller/Lyrics/ILyricParser.cs @@ -0,0 +1,28 @@ +using MediaBrowser.Controller.Resolvers; +using MediaBrowser.Providers.Lyric; + +namespace MediaBrowser.Controller.Lyrics; + +/// <summary> +/// Interface ILyricParser. +/// </summary> +public interface ILyricParser +{ + /// <summary> + /// Gets a value indicating the provider name. + /// </summary> + string Name { get; } + + /// <summary> + /// Gets the priority. + /// </summary> + /// <value>The priority.</value> + ResolverPriority Priority { get; } + + /// <summary> + /// Parses the raw lyrics into a response. + /// </summary> + /// <param name="lyrics">The raw lyrics content.</param> + /// <returns>The parsed lyrics or null if invalid.</returns> + LyricResponse? ParseLyrics(LyricFile lyrics); +} diff --git a/MediaBrowser.Controller/Lyrics/ILyricProvider.cs b/MediaBrowser.Controller/Lyrics/ILyricProvider.cs deleted file mode 100644 index 2a04c6152..000000000 --- a/MediaBrowser.Controller/Lyrics/ILyricProvider.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Collections.Generic; -using System.Threading.Tasks; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Resolvers; - -namespace MediaBrowser.Controller.Lyrics; - -/// <summary> -/// Interface ILyricsProvider. -/// </summary> -public interface ILyricProvider -{ - /// <summary> - /// Gets a value indicating the provider name. - /// </summary> - string Name { get; } - - /// <summary> - /// Gets the priority. - /// </summary> - /// <value>The priority.</value> - ResolverPriority Priority { get; } - - /// <summary> - /// Gets the supported media types for this provider. - /// </summary> - /// <value>The supported media types.</value> - IReadOnlyCollection<string> SupportedMediaTypes { get; } - - /// <summary> - /// Gets the lyrics. - /// </summary> - /// <param name="item">The media item.</param> - /// <returns>A task representing found lyrics.</returns> - Task<LyricResponse?> GetLyrics(BaseItem item); -} diff --git a/MediaBrowser.Controller/Lyrics/LyricFile.cs b/MediaBrowser.Controller/Lyrics/LyricFile.cs new file mode 100644 index 000000000..ede89403c --- /dev/null +++ b/MediaBrowser.Controller/Lyrics/LyricFile.cs @@ -0,0 +1,28 @@ +namespace MediaBrowser.Providers.Lyric; + +/// <summary> +/// The information for a raw lyrics file before parsing. +/// </summary> +public class LyricFile +{ + /// <summary> + /// Initializes a new instance of the <see cref="LyricFile"/> class. + /// </summary> + /// <param name="name">The name.</param> + /// <param name="content">The content, must not be empty.</param> + public LyricFile(string name, string content) + { + Name = name; + Content = content; + } + + /// <summary> + /// Gets or sets the name of the lyrics file. This must include the file extension. + /// </summary> + public string Name { get; set; } + + /// <summary> + /// Gets or sets the contents of the file. + /// </summary> + public string Content { get; set; } +} diff --git a/MediaBrowser.Controller/Lyrics/LyricInfo.cs b/MediaBrowser.Controller/Lyrics/LyricInfo.cs deleted file mode 100644 index 6ec6df582..000000000 --- a/MediaBrowser.Controller/Lyrics/LyricInfo.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.IO; -using Jellyfin.Extensions; - -namespace MediaBrowser.Controller.Lyrics; - -/// <summary> -/// Lyric helper methods. -/// </summary> -public static class LyricInfo -{ - /// <summary> - /// Gets matching lyric file for a requested item. - /// </summary> - /// <param name="lyricProvider">The lyricProvider interface to use.</param> - /// <param name="itemPath">Path of requested item.</param> - /// <returns>Lyric file path if passed lyric provider's supported media type is found; otherwise, null.</returns> - public static string? GetLyricFilePath(this ILyricProvider lyricProvider, string itemPath) - { - // Ensure we have a provider - if (lyricProvider is null) - { - return null; - } - - // Ensure the path to the item is not null - string? itemDirectoryPath = Path.GetDirectoryName(itemPath); - if (itemDirectoryPath is null) - { - return null; - } - - // Ensure the directory path exists - if (!Directory.Exists(itemDirectoryPath)) - { - return null; - } - - foreach (var lyricFilePath in Directory.GetFiles(itemDirectoryPath, $"{Path.GetFileNameWithoutExtension(itemPath)}.*")) - { - if (lyricProvider.SupportedMediaTypes.Contains(Path.GetExtension(lyricFilePath.AsSpan())[1..], StringComparison.OrdinalIgnoreCase)) - { - return lyricFilePath; - } - } - - return null; - } -} diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs index 89cf55b78..750713694 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs @@ -46,6 +46,7 @@ namespace MediaBrowser.Controller.MediaEncoding private readonly Version _minFFmpegImplictHwaccel = new Version(6, 0); private readonly Version _minFFmpegHwaUnsafeOutput = new Version(6, 0); private readonly Version _minFFmpegOclCuTonemapMode = new Version(5, 1, 3); + private readonly Version _minFFmpegSvtAv1Params = new Version(5, 1); private static readonly string[] _videoProfilesH264 = new[] { @@ -65,6 +66,13 @@ namespace MediaBrowser.Controller.MediaEncoding "Main10" }; + private static readonly string[] _videoProfilesAv1 = new[] + { + "Main", + "High", + "Professional", + }; + private static readonly HashSet<string> _mp4ContainerNames = new(StringComparer.OrdinalIgnoreCase) { "mp4", @@ -116,12 +124,15 @@ namespace MediaBrowser.Controller.MediaEncoding private static partial Regex WhiteSpaceRegex(); public string GetH264Encoder(EncodingJobInfo state, EncodingOptions encodingOptions) - => GetH264OrH265Encoder("libx264", "h264", state, encodingOptions); + => GetH26xOrAv1Encoder("libx264", "h264", state, encodingOptions); public string GetH265Encoder(EncodingJobInfo state, EncodingOptions encodingOptions) - => GetH264OrH265Encoder("libx265", "hevc", state, encodingOptions); + => GetH26xOrAv1Encoder("libx265", "hevc", state, encodingOptions); + + public string GetAv1Encoder(EncodingJobInfo state, EncodingOptions encodingOptions) + => GetH26xOrAv1Encoder("libsvtav1", "av1", state, encodingOptions); - private string GetH264OrH265Encoder(string defaultEncoder, string hwEncoder, EncodingJobInfo state, EncodingOptions encodingOptions) + private string GetH26xOrAv1Encoder(string defaultEncoder, string hwEncoder, EncodingJobInfo state, EncodingOptions encodingOptions) { // Only use alternative encoders for video files. // When using concat with folder rips, if the mfx session fails to initialize, ffmpeg will be stuck retrying and will not exit gracefully @@ -212,8 +223,8 @@ namespace MediaBrowser.Controller.MediaEncoding } if (string.Equals(state.VideoStream.Codec, "hevc", StringComparison.OrdinalIgnoreCase) - && string.Equals(state.VideoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase) - && string.Equals(state.VideoStream.VideoRangeType, "DOVI", StringComparison.OrdinalIgnoreCase)) + && state.VideoStream.VideoRange == VideoRange.HDR + && state.VideoStream.VideoRangeType == VideoRangeType.DOVI) { // Only native SW decoder and HW accelerator can parse dovi rpu. var vidDecoder = GetHardwareVideoDecoder(state, options) ?? string.Empty; @@ -224,9 +235,9 @@ namespace MediaBrowser.Controller.MediaEncoding return isSwDecoder || isNvdecDecoder || isVaapiDecoder || isD3d11vaDecoder; } - return string.Equals(state.VideoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase) - && (string.Equals(state.VideoStream.VideoRangeType, "HDR10", StringComparison.OrdinalIgnoreCase) - || string.Equals(state.VideoStream.VideoRangeType, "HLG", StringComparison.OrdinalIgnoreCase)); + return state.VideoStream.VideoRange == VideoRange.HDR + && (state.VideoStream.VideoRangeType == VideoRangeType.HDR10 + || state.VideoStream.VideoRangeType == VideoRangeType.HLG); } private bool IsVulkanHwTonemapAvailable(EncodingJobInfo state, EncodingOptions options) @@ -238,7 +249,7 @@ namespace MediaBrowser.Controller.MediaEncoding // libplacebo has partial Dolby Vision to SDR tonemapping support. return options.EnableTonemapping - && string.Equals(state.VideoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase) + && state.VideoStream.VideoRange == VideoRange.HDR && GetVideoColorBitDepth(state) == 10; } @@ -253,8 +264,8 @@ namespace MediaBrowser.Controller.MediaEncoding // Native VPP tonemapping may come to QSV in the future. - return string.Equals(state.VideoStream.VideoRange, "HDR", StringComparison.OrdinalIgnoreCase) - && string.Equals(state.VideoStream.VideoRangeType, "HDR10", StringComparison.OrdinalIgnoreCase); + return state.VideoStream.VideoRange == VideoRange.HDR + && state.VideoStream.VideoRangeType == VideoRangeType.HDR10; } /// <summary> @@ -269,6 +280,11 @@ namespace MediaBrowser.Controller.MediaEncoding if (!string.IsNullOrEmpty(codec)) { + if (string.Equals(codec, "av1", StringComparison.OrdinalIgnoreCase)) + { + return GetAv1Encoder(state, encodingOptions); + } + if (string.Equals(codec, "h265", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "hevc", StringComparison.OrdinalIgnoreCase)) { @@ -568,6 +584,11 @@ namespace MediaBrowser.Controller.MediaEncoding return Array.FindIndex(_videoProfilesH265, x => string.Equals(x, profile, StringComparison.OrdinalIgnoreCase)); } + if (string.Equals("av1", videoCodec, StringComparison.OrdinalIgnoreCase)) + { + return Array.FindIndex(_videoProfilesAv1, x => string.Equals(x, profile, StringComparison.OrdinalIgnoreCase)); + } + return -1; } @@ -1207,6 +1228,11 @@ namespace MediaBrowser.Controller.MediaEncoding return FormattableString.Invariant($" -b:v {bitrate}"); } + if (string.Equals(videoCodec, "libsvtav1", StringComparison.OrdinalIgnoreCase)) + { + return FormattableString.Invariant($" -b:v {bitrate} -bufsize {bufsize}"); + } + if (string.Equals(videoCodec, "libx264", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "libx265", StringComparison.OrdinalIgnoreCase)) { @@ -1214,14 +1240,16 @@ namespace MediaBrowser.Controller.MediaEncoding } if (string.Equals(videoCodec, "h264_amf", StringComparison.OrdinalIgnoreCase) - || string.Equals(videoCodec, "hevc_amf", StringComparison.OrdinalIgnoreCase)) + || string.Equals(videoCodec, "hevc_amf", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoCodec, "av1_amf", StringComparison.OrdinalIgnoreCase)) { // Override the too high default qmin 18 in transcoding preset return FormattableString.Invariant($" -rc cbr -qmin 0 -qmax 32 -b:v {bitrate} -maxrate {bitrate} -bufsize {bufsize}"); } if (string.Equals(videoCodec, "h264_vaapi", StringComparison.OrdinalIgnoreCase) - || string.Equals(videoCodec, "hevc_vaapi", StringComparison.OrdinalIgnoreCase)) + || string.Equals(videoCodec, "hevc_vaapi", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoCodec, "av1_vaapi", StringComparison.OrdinalIgnoreCase)) { // VBR in i965 driver may result in pixelated output. if (_mediaEncoder.IsVaapiDeviceInteli965) @@ -1239,14 +1267,23 @@ namespace MediaBrowser.Controller.MediaEncoding { if (double.TryParse(level, CultureInfo.InvariantCulture, out double requestLevel)) { - if (string.Equals(state.ActualOutputVideoCodec, "hevc", StringComparison.OrdinalIgnoreCase) - || string.Equals(state.ActualOutputVideoCodec, "h265", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(state.ActualOutputVideoCodec, "av1", StringComparison.OrdinalIgnoreCase)) + { + // Transcode to level 5.3 (15) and lower for maximum compatibility. + // https://en.wikipedia.org/wiki/AV1#Levels + if (requestLevel < 0 || requestLevel >= 15) + { + return "15"; + } + } + else if (string.Equals(state.ActualOutputVideoCodec, "hevc", StringComparison.OrdinalIgnoreCase) + || string.Equals(state.ActualOutputVideoCodec, "h265", StringComparison.OrdinalIgnoreCase)) { // Transcode to level 5.0 and lower for maximum compatibility. // Level 5.0 is suitable for up to 4k 30fps hevc encoding, otherwise let the encoder to handle it. // https://en.wikipedia.org/wiki/High_Efficiency_Video_Coding_tiers_and_levels // MaxLumaSampleRate = 3840*2160*30 = 248832000 < 267386880. - if (requestLevel >= 150) + if (requestLevel < 0 || requestLevel >= 150) { return "150"; } @@ -1256,7 +1293,7 @@ namespace MediaBrowser.Controller.MediaEncoding // Transcode to level 5.1 and lower for maximum compatibility. // h264 4k 30fps requires at least level 5.1 otherwise it will break on safari fmp4. // https://en.wikipedia.org/wiki/Advanced_Video_Coding#Levels - if (requestLevel >= 51) + if (requestLevel < 0 || requestLevel >= 51) { return "51"; } @@ -1394,14 +1431,18 @@ namespace MediaBrowser.Controller.MediaEncoding || string.Equals(codec, "h264_amf", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "hevc_qsv", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "hevc_nvenc", StringComparison.OrdinalIgnoreCase) - || string.Equals(codec, "hevc_amf", StringComparison.OrdinalIgnoreCase)) + || string.Equals(codec, "av1_qsv", StringComparison.OrdinalIgnoreCase) + || string.Equals(codec, "av1_nvenc", StringComparison.OrdinalIgnoreCase) + || string.Equals(codec, "av1_amf", StringComparison.OrdinalIgnoreCase) + || string.Equals(codec, "libsvtav1", StringComparison.OrdinalIgnoreCase)) { args += gopArg; } else if (string.Equals(codec, "libx264", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "libx265", StringComparison.OrdinalIgnoreCase) || string.Equals(codec, "h264_vaapi", StringComparison.OrdinalIgnoreCase) - || string.Equals(codec, "hevc_vaapi", StringComparison.OrdinalIgnoreCase)) + || string.Equals(codec, "hevc_vaapi", StringComparison.OrdinalIgnoreCase) + || string.Equals(codec, "av1_vaapi", StringComparison.OrdinalIgnoreCase)) { args += keyFrameArg; @@ -1416,6 +1457,13 @@ namespace MediaBrowser.Controller.MediaEncoding args += keyFrameArg + gopArg; } + // global_header produced by AMD VA-API encoder causes non-playable fMP4 on iOS + if (codec.Contains("vaapi", StringComparison.OrdinalIgnoreCase) + && _mediaEncoder.IsVaapiDeviceAmd) + { + args += " -flags:v -global_header"; + } + return args; } @@ -1537,18 +1585,60 @@ namespace MediaBrowser.Controller.MediaEncoding param += " -crf " + defaultCrf; } } + else if (string.Equals(videoEncoder, "libsvtav1", StringComparison.OrdinalIgnoreCase)) + { + // Default to use the recommended preset 10. + // Omit presets < 5, which are too slow for on the fly encoding. + // https://gitlab.com/AOMediaCodec/SVT-AV1/-/blob/master/Docs/Ffmpeg.md + param += encodingOptions.EncoderPreset switch + { + "veryslow" => " -preset 5", + "slower" => " -preset 6", + "slow" => " -preset 7", + "medium" => " -preset 8", + "fast" => " -preset 9", + "faster" => " -preset 10", + "veryfast" => " -preset 11", + "superfast" => " -preset 12", + "ultrafast" => " -preset 13", + _ => " -preset 10" + }; + } + else if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoEncoder, "hevc_vaapi", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoEncoder, "av1_vaapi", StringComparison.OrdinalIgnoreCase)) + { + // -compression_level is not reliable on AMD. + if (_mediaEncoder.IsVaapiDeviceInteliHD) + { + param += encodingOptions.EncoderPreset switch + { + "veryslow" => " -compression_level 1", + "slower" => " -compression_level 2", + "slow" => " -compression_level 3", + "medium" => " -compression_level 4", + "fast" => " -compression_level 5", + "faster" => " -compression_level 6", + "veryfast" => " -compression_level 7", + "superfast" => " -compression_level 7", + "ultrafast" => " -compression_level 7", + _ => string.Empty + }; + } + } else if (string.Equals(videoEncoder, "h264_qsv", StringComparison.OrdinalIgnoreCase) // h264 (h264_qsv) - || string.Equals(videoEncoder, "hevc_qsv", StringComparison.OrdinalIgnoreCase)) // hevc (hevc_qsv) + || string.Equals(videoEncoder, "hevc_qsv", StringComparison.OrdinalIgnoreCase) // hevc (hevc_qsv) + || string.Equals(videoEncoder, "av1_qsv", StringComparison.OrdinalIgnoreCase)) // av1 (av1_qsv) { - string[] valid_h264_qsv = { "veryslow", "slower", "slow", "medium", "fast", "faster", "veryfast" }; + string[] valid_presets = { "veryslow", "slower", "slow", "medium", "fast", "faster", "veryfast" }; - if (valid_h264_qsv.Contains(encodingOptions.EncoderPreset, StringComparison.OrdinalIgnoreCase)) + if (valid_presets.Contains(encodingOptions.EncoderPreset, StringComparison.OrdinalIgnoreCase)) { param += " -preset " + encodingOptions.EncoderPreset; } else { - param += " -preset 7"; + param += " -preset veryfast"; } // Only h264_qsv has look_ahead option @@ -1558,7 +1648,8 @@ namespace MediaBrowser.Controller.MediaEncoding } } else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) // h264 (h264_nvenc) - || string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase)) // hevc (hevc_nvenc) + || string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase) // hevc (hevc_nvenc) + || string.Equals(videoEncoder, "av1_nvenc", StringComparison.OrdinalIgnoreCase)) // av1 (av1_nvenc) { switch (encodingOptions.EncoderPreset) { @@ -1598,7 +1689,8 @@ namespace MediaBrowser.Controller.MediaEncoding } } else if (string.Equals(videoEncoder, "h264_amf", StringComparison.OrdinalIgnoreCase) // h264 (h264_amf) - || string.Equals(videoEncoder, "hevc_amf", StringComparison.OrdinalIgnoreCase)) // hevc (hevc_amf) + || string.Equals(videoEncoder, "hevc_amf", StringComparison.OrdinalIgnoreCase) // hevc (hevc_amf) + || string.Equals(videoEncoder, "av1_amf", StringComparison.OrdinalIgnoreCase)) // av1 (av1_amf) { switch (encodingOptions.EncoderPreset) { @@ -1625,9 +1717,15 @@ namespace MediaBrowser.Controller.MediaEncoding break; } + if (string.Equals(videoEncoder, "hevc_amf", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoEncoder, "av1_amf", StringComparison.OrdinalIgnoreCase)) + { + param += " -header_insertion_mode gop"; + } + if (string.Equals(videoEncoder, "hevc_amf", StringComparison.OrdinalIgnoreCase)) { - param += " -header_insertion_mode gop -gops_per_idr 1"; + param += " -gops_per_idr 1"; } } else if (string.Equals(videoEncoder, "libvpx", StringComparison.OrdinalIgnoreCase)) // vp8 @@ -1758,6 +1856,14 @@ namespace MediaBrowser.Controller.MediaEncoding profile = "high"; } + // We only need Main profile of AV1 encoders. + if (videoEncoder.Contains("av1", StringComparison.OrdinalIgnoreCase) + && (profile.Contains("high", StringComparison.OrdinalIgnoreCase) + || profile.Contains("professional", StringComparison.OrdinalIgnoreCase))) + { + profile = "main"; + } + // h264_vaapi does not support Baseline profile, force Constrained Baseline in this case, // which is compatible (and ugly). if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) @@ -1825,19 +1931,41 @@ namespace MediaBrowser.Controller.MediaEncoding param += " -level " + (hevcLevel / 3); } } + else if (string.Equals(videoEncoder, "av1_qsv", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoEncoder, "libsvtav1", StringComparison.OrdinalIgnoreCase)) + { + // libsvtav1 and av1_qsv use -level 60 instead of -level 16 + // https://aomedia.org/av1/specification/annex-a/ + if (int.TryParse(level, NumberStyles.Any, CultureInfo.InvariantCulture, out int av1Level)) + { + var x = 2 + (av1Level >> 2); + var y = av1Level & 3; + var res = (x * 10) + y; + param += " -level " + res; + } + } else if (string.Equals(videoEncoder, "h264_amf", StringComparison.OrdinalIgnoreCase) - || string.Equals(videoEncoder, "hevc_amf", StringComparison.OrdinalIgnoreCase)) + || string.Equals(videoEncoder, "hevc_amf", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoEncoder, "av1_amf", StringComparison.OrdinalIgnoreCase)) { param += " -level " + level; } else if (string.Equals(videoEncoder, "h264_nvenc", StringComparison.OrdinalIgnoreCase) || string.Equals(videoEncoder, "hevc_nvenc", StringComparison.OrdinalIgnoreCase) - || string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) - || string.Equals(videoEncoder, "hevc_vaapi", StringComparison.OrdinalIgnoreCase)) + || string.Equals(videoEncoder, "av1_nvenc", StringComparison.OrdinalIgnoreCase)) { // level option may cause NVENC to fail. // NVENC cannot adjust the given level, just throw an error. + } + else if (string.Equals(videoEncoder, "h264_vaapi", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoEncoder, "hevc_vaapi", StringComparison.OrdinalIgnoreCase) + || string.Equals(videoEncoder, "av1_vaapi", StringComparison.OrdinalIgnoreCase)) + { // level option may cause corrupted frames on AMD VAAPI. + if (_mediaEncoder.IsVaapiDeviceInteliHD || _mediaEncoder.IsVaapiDeviceInteli965) + { + param += " -level " + level; + } } else if (!string.Equals(videoEncoder, "libx265", StringComparison.OrdinalIgnoreCase)) { @@ -1859,6 +1987,12 @@ namespace MediaBrowser.Controller.MediaEncoding param += " -x265-params:0 no-info=1"; } + if (string.Equals(videoEncoder, "libsvtav1", StringComparison.OrdinalIgnoreCase) + && _mediaEncoder.EncoderVersion >= _minFFmpegSvtAv1Params) + { + param += " -svtav1-params:0 rc=1:tune=0:film-grain=0:enable-overlays=1:enable-tf=0"; + } + return param; } @@ -1937,12 +2071,12 @@ namespace MediaBrowser.Controller.MediaEncoding var requestedRangeTypes = state.GetRequestedRangeTypes(videoStream.Codec); if (requestedRangeTypes.Length > 0) { - if (string.IsNullOrEmpty(videoStream.VideoRangeType)) + if (videoStream.VideoRangeType == VideoRangeType.Unknown) { return false; } - if (!requestedRangeTypes.Contains(videoStream.VideoRangeType, StringComparison.OrdinalIgnoreCase)) + if (!requestedRangeTypes.Contains(videoStream.VideoRangeType.ToString(), StringComparison.OrdinalIgnoreCase)) { return false; } @@ -3648,7 +3782,7 @@ namespace MediaBrowser.Controller.MediaEncoding mainFilters.Add(swDeintFilter); } - var outFormat = doOclTonemap ? "yuv420p10le" : "yuv420p"; + var outFormat = doOclTonemap ? "yuv420p10le" : (hasGraphicalSubs ? "yuv420p" : "nv12"); var swScaleFilter = GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH); // sw scale mainFilters.Add(swScaleFilter); @@ -3849,7 +3983,7 @@ namespace MediaBrowser.Controller.MediaEncoding mainFilters.Add(swDeintFilter); } - var outFormat = doOclTonemap ? "yuv420p10le" : "yuv420p"; + var outFormat = doOclTonemap ? "yuv420p10le" : (hasGraphicalSubs ? "yuv420p" : "nv12"); var swScaleFilter = GetSwScaleFilter(state, options, vidEncoder, inW, inH, threeDFormat, reqW, reqH, reqMaxW, reqMaxH); // sw scale mainFilters.Add(swScaleFilter); @@ -5813,19 +5947,25 @@ namespace MediaBrowser.Controller.MediaEncoding private void ShiftVideoCodecsIfNeeded(List<string> videoCodecs, EncodingOptions encodingOptions) { - // Shift hevc/h265 to the end of list if hevc encoding is not allowed. - if (encodingOptions.AllowHevcEncoding) + // No need to shift if there is only one supported video codec. + if (videoCodecs.Count < 2) { return; } - // No need to shift if there is only one supported video codec. - if (videoCodecs.Count < 2) + // Shift codecs to the end of list if it's not allowed. + var shiftVideoCodecs = new List<string>(); + if (!encodingOptions.AllowHevcEncoding) { - return; + shiftVideoCodecs.Add("hevc"); + shiftVideoCodecs.Add("h265"); + } + + if (!encodingOptions.AllowAv1Encoding) + { + shiftVideoCodecs.Add("av1"); } - var shiftVideoCodecs = new[] { "hevc", "h265" }; if (videoCodecs.All(i => shiftVideoCodecs.Contains(i, StringComparison.OrdinalIgnoreCase))) { return; diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs index a6b541660..17813559a 100644 --- a/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs +++ b/MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Dto; @@ -367,22 +368,21 @@ namespace MediaBrowser.Controller.MediaEncoding /// <summary> /// Gets the target video range type. /// </summary> - public string TargetVideoRangeType + public VideoRangeType TargetVideoRangeType { get { if (BaseRequest.Static || EncodingHelper.IsCopyCodec(OutputVideoCodec)) { - return VideoStream?.VideoRangeType; + return VideoStream?.VideoRangeType ?? VideoRangeType.Unknown; } - var requestedRangeType = GetRequestedRangeTypes(ActualOutputVideoCodec).FirstOrDefault(); - if (!string.IsNullOrEmpty(requestedRangeType)) + if (Enum.TryParse(GetRequestedRangeTypes(ActualOutputVideoCodec).FirstOrDefault() ?? "Unknown", true, out VideoRangeType requestedRangeType)) { return requestedRangeType; } - return null; + return VideoRangeType.Unknown; } } diff --git a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs index 0524999c7..8f38d4976 100644 --- a/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs +++ b/MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs @@ -9,7 +9,7 @@ using System.Linq; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Net; +using MediaBrowser.Controller.Net.WebSocketMessages; using MediaBrowser.Model.Session; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; @@ -169,9 +169,8 @@ namespace MediaBrowser.Controller.Net if (data is not null) { await connection.SendAsync( - new WebSocketMessage<TReturnDataType> + new OutboundWebSocketMessage<TReturnDataType> { - MessageId = Guid.NewGuid(), MessageType = Type, Data = data }, diff --git a/MediaBrowser.Controller/Net/IWebSocketConnection.cs b/MediaBrowser.Controller/Net/IWebSocketConnection.cs index 4f2492b89..79f0846b4 100644 --- a/MediaBrowser.Controller/Net/IWebSocketConnection.cs +++ b/MediaBrowser.Controller/Net/IWebSocketConnection.cs @@ -5,7 +5,7 @@ using System.Net; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Model.Net; +using MediaBrowser.Controller.Net.WebSocketMessages; namespace MediaBrowser.Controller.Net { @@ -49,12 +49,21 @@ namespace MediaBrowser.Controller.Net /// <summary> /// Sends a message asynchronously. /// </summary> + /// <param name="message">The message.</param> + /// <param name="cancellationToken">The cancellation token.</param> + /// <returns>Task.</returns> + /// <exception cref="ArgumentNullException">The message is null.</exception> + Task SendAsync(OutboundWebSocketMessage message, CancellationToken cancellationToken); + + /// <summary> + /// Sends a message asynchronously. + /// </summary> /// <typeparam name="T">The type of websocket message data.</typeparam> /// <param name="message">The message.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> /// <exception cref="ArgumentNullException">The message is null.</exception> - Task SendAsync<T>(WebSocketMessage<T> message, CancellationToken cancellationToken); + Task SendAsync<T>(OutboundWebSocketMessage<T> message, CancellationToken cancellationToken); Task ProcessAsync(CancellationToken cancellationToken = default); } diff --git a/MediaBrowser.Controller/Net/WebSocketMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessage.cs index c02bcd70b..92183e792 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessage.cs @@ -1,4 +1,3 @@ -using System; using System.Text.Json.Serialization; using MediaBrowser.Model.Session; @@ -16,11 +15,6 @@ public abstract class WebSocketMessage public virtual SessionMessageType MessageType { get; set; } /// <summary> - /// Gets or sets the message id. - /// </summary> - public Guid MessageId { get; set; } - - /// <summary> /// Gets or sets the server id. /// </summary> [JsonIgnore] diff --git a/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs b/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs index 6f7ebf156..f7a9ccc44 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessageInfo.cs @@ -1,13 +1,13 @@ #nullable disable -using MediaBrowser.Model.Net; +using MediaBrowser.Controller.Net.WebSocketMessages; namespace MediaBrowser.Controller.Net { /// <summary> /// Class WebSocketMessageInfo. /// </summary> - public class WebSocketMessageInfo : WebSocketMessage<string> + public class WebSocketMessageInfo : InboundWebSocketMessage<string> { /// <summary> /// Gets or sets the connection. diff --git a/MediaBrowser.Controller/Net/WebSocketMessageOfT.cs b/MediaBrowser.Controller/Net/WebSocketMessageOfT.cs index 7c35c8010..11e5a6bb2 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessageOfT.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessageOfT.cs @@ -6,13 +6,12 @@ namespace MediaBrowser.Controller.Net; /// Class WebSocketMessage. /// </summary> /// <typeparam name="T">The type of the data.</typeparam> -// TODO make this abstract, remove empty ctor. -public class WebSocketMessage<T> : WebSocketMessage +public abstract class WebSocketMessage<T> : WebSocketMessage { /// <summary> /// Initializes a new instance of the <see cref="WebSocketMessage{T}"/> class. /// </summary> - public WebSocketMessage() + protected WebSocketMessage() { } diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ActivityLogEntryStartMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ActivityLogEntryStartMessage.cs index b9f71b922..b3a60199a 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ActivityLogEntryStartMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ActivityLogEntryStartMessage.cs @@ -1,20 +1,20 @@ -using System.Collections.Generic; using System.ComponentModel; -using MediaBrowser.Model.Activity; using MediaBrowser.Model.Session; namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound; /// <summary> /// Activity log entry start message. +/// Data is the timing data encoded as "$initialDelay,$interval" in ms. /// </summary> -public class ActivityLogEntryStartMessage : WebSocketMessage<IReadOnlyCollection<ActivityLogEntry>>, IInboundWebSocketMessage +public class ActivityLogEntryStartMessage : InboundWebSocketMessage<string> { /// <summary> /// Initializes a new instance of the <see cref="ActivityLogEntryStartMessage"/> class. + /// Data is the timing data encoded as "$initialDelay,$interval" in ms. /// </summary> - /// <param name="data">Collection of activity log entries.</param> - public ActivityLogEntryStartMessage(IReadOnlyCollection<ActivityLogEntry> data) + /// <param name="data">The timing data encoded as "$initialDelay,$interval".</param> + public ActivityLogEntryStartMessage(string data) : base(data) { } diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ActivityLogEntryStopMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ActivityLogEntryStopMessage.cs index eac129b20..6f65cb2c7 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ActivityLogEntryStopMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ActivityLogEntryStopMessage.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; using System.ComponentModel; -using MediaBrowser.Model.Activity; using MediaBrowser.Model.Session; namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound; @@ -8,17 +6,8 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound; /// <summary> /// Activity log entry stop message. /// </summary> -public class ActivityLogEntryStopMessage : WebSocketMessage<IReadOnlyCollection<ActivityLogEntry>>, IInboundWebSocketMessage +public class ActivityLogEntryStopMessage : InboundWebSocketMessage { - /// <summary> - /// Initializes a new instance of the <see cref="ActivityLogEntryStopMessage"/> class. - /// </summary> - /// <param name="data">Collection of activity log entries.</param> - public ActivityLogEntryStopMessage(IReadOnlyCollection<ActivityLogEntry> data) - : base(data) - { - } - /// <inheritdoc /> [DefaultValue(SessionMessageType.ActivityLogEntryStop)] public override SessionMessageType MessageType => SessionMessageType.ActivityLogEntryStop; diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/InboundKeepAliveMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/InboundKeepAliveMessage.cs new file mode 100644 index 000000000..fec7cb4e4 --- /dev/null +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/InboundKeepAliveMessage.cs @@ -0,0 +1,14 @@ +using System.ComponentModel; +using MediaBrowser.Model.Session; + +namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound; + +/// <summary> +/// Keep alive websocket messages. +/// </summary> +public class InboundKeepAliveMessage : InboundWebSocketMessage +{ + /// <inheritdoc /> + [DefaultValue(SessionMessageType.KeepAlive)] + public override SessionMessageType MessageType => SessionMessageType.KeepAlive; +} diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ScheduledTasksInfoStartMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ScheduledTasksInfoStartMessage.cs index dd2a7145e..bf98470bf 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ScheduledTasksInfoStartMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ScheduledTasksInfoStartMessage.cs @@ -1,20 +1,19 @@ -using System.Collections.Generic; using System.ComponentModel; using MediaBrowser.Model.Session; -using MediaBrowser.Model.Tasks; namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound; /// <summary> /// Scheduled tasks info start message. +/// Data is the timing data encoded as "$initialDelay,$interval" in ms. /// </summary> -public class ScheduledTasksInfoStartMessage : WebSocketMessage<IReadOnlyCollection<TaskInfo>>, IInboundWebSocketMessage +public class ScheduledTasksInfoStartMessage : InboundWebSocketMessage<string> { /// <summary> /// Initializes a new instance of the <see cref="ScheduledTasksInfoStartMessage"/> class. /// </summary> - /// <param name="data">Collection of task info.</param> - public ScheduledTasksInfoStartMessage(IReadOnlyCollection<TaskInfo> data) + /// <param name="data">The timing data encoded as $initialDelay,$interval.</param> + public ScheduledTasksInfoStartMessage(string data) : base(data) { } diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ScheduledTasksInfoStopMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ScheduledTasksInfoStopMessage.cs index 84e1f0166..f36739c70 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ScheduledTasksInfoStopMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ScheduledTasksInfoStopMessage.cs @@ -1,24 +1,13 @@ -using System.Collections.Generic; using System.ComponentModel; using MediaBrowser.Model.Session; -using MediaBrowser.Model.Tasks; namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound; /// <summary> /// Scheduled tasks info stop message. /// </summary> -public class ScheduledTasksInfoStopMessage : WebSocketMessage<IReadOnlyCollection<TaskInfo>>, IInboundWebSocketMessage +public class ScheduledTasksInfoStopMessage : InboundWebSocketMessage { - /// <summary> - /// Initializes a new instance of the <see cref="ScheduledTasksInfoStopMessage"/> class. - /// </summary> - /// <param name="data">Collection of task info.</param> - public ScheduledTasksInfoStopMessage(IReadOnlyCollection<TaskInfo> data) - : base(data) - { - } - /// <inheritdoc /> [DefaultValue(SessionMessageType.ScheduledTasksInfoStop)] public override SessionMessageType MessageType => SessionMessageType.ScheduledTasksInfoStop; diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/SessionsStartMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/SessionsStartMessage.cs index e35a5dc3a..a40a0c79e 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/SessionsStartMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/SessionsStartMessage.cs @@ -1,19 +1,19 @@ using System.ComponentModel; -using MediaBrowser.Controller.Session; using MediaBrowser.Model.Session; namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound; /// <summary> /// Sessions start message. +/// Data is the timing data encoded as "$initialDelay,$interval" in ms. /// </summary> -public class SessionsStartMessage : WebSocketMessage<SessionInfo>, IInboundWebSocketMessage +public class SessionsStartMessage : InboundWebSocketMessage<string> { /// <summary> /// Initializes a new instance of the <see cref="SessionsStartMessage"/> class. /// </summary> - /// <param name="data">Session info.</param> - public SessionsStartMessage(SessionInfo data) + /// <param name="data">The timing data encoded as $initialDelay,$interval.</param> + public SessionsStartMessage(string data) : base(data) { } diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/SessionsStopMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/SessionsStopMessage.cs index 7e3582d64..288d111c5 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/SessionsStopMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Inbound/SessionsStopMessage.cs @@ -1,5 +1,4 @@ using System.ComponentModel; -using MediaBrowser.Controller.Session; using MediaBrowser.Model.Session; namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound; @@ -7,17 +6,8 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Inbound; /// <summary> /// Sessions stop message. /// </summary> -public class SessionsStopMessage : WebSocketMessage<SessionInfo>, IInboundWebSocketMessage +public class SessionsStopMessage : InboundWebSocketMessage { - /// <summary> - /// Initializes a new instance of the <see cref="SessionsStopMessage"/> class. - /// </summary> - /// <param name="data">Session info.</param> - public SessionsStopMessage(SessionInfo data) - : base(data) - { - } - /// <inheritdoc /> [DefaultValue(SessionMessageType.SessionsStop)] public override SessionMessageType MessageType => SessionMessageType.SessionsStop; diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/InboundWebSocketMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/InboundWebSocketMessage.cs index 20ca888e1..8d6e821df 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/InboundWebSocketMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/InboundWebSocketMessage.cs @@ -1,9 +1,8 @@ -namespace MediaBrowser.Controller.Net.WebSocketMessages; +namespace MediaBrowser.Controller.Net.WebSocketMessages; /// <summary> -/// Class representing the list of outbound websocket message types. -/// Only used in openapi generation. +/// Inbound websocket message. /// </summary> -public class InboundWebSocketMessage : WebSocketMessage +public class InboundWebSocketMessage : WebSocketMessage, IInboundWebSocketMessage { } diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/InboundWebSocketMessageOfT.cs b/MediaBrowser.Controller/Net/WebSocketMessages/InboundWebSocketMessageOfT.cs new file mode 100644 index 000000000..4da5e7d31 --- /dev/null +++ b/MediaBrowser.Controller/Net/WebSocketMessages/InboundWebSocketMessageOfT.cs @@ -0,0 +1,26 @@ +#pragma warning disable SA1649 // File name must equal class name. + +namespace MediaBrowser.Controller.Net.WebSocketMessages; + +/// <summary> +/// Inbound websocket message with data. +/// </summary> +/// <typeparam name="T">The data type.</typeparam> +public class InboundWebSocketMessage<T> : WebSocketMessage<T>, IInboundWebSocketMessage +{ + /// <summary> + /// Initializes a new instance of the <see cref="InboundWebSocketMessage{T}"/> class. + /// </summary> + public InboundWebSocketMessage() + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="InboundWebSocketMessage{T}"/> class. + /// </summary> + /// <param name="data">The data to send.</param> + protected InboundWebSocketMessage(T data) + { + Data = data; + } +} diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ActivityLogEntryMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ActivityLogEntryMessage.cs index 5650ee4bb..2a098615d 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ActivityLogEntryMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ActivityLogEntryMessage.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Activity log created message. /// </summary> -public class ActivityLogEntryMessage : WebSocketMessage<IReadOnlyList<ActivityLogEntry>>, IOutboundWebSocketMessage +public class ActivityLogEntryMessage : OutboundWebSocketMessage<IReadOnlyList<ActivityLogEntry>> { /// <summary> /// Initializes a new instance of the <see cref="ActivityLogEntryMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ForceKeepAliveMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ForceKeepAliveMessage.cs index 94ade5e81..ca55340a0 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ForceKeepAliveMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ForceKeepAliveMessage.cs @@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Force keep alive websocket messages. /// </summary> -public class ForceKeepAliveMessage : WebSocketMessage<int>, IOutboundWebSocketMessage +public class ForceKeepAliveMessage : OutboundWebSocketMessage<int> { /// <summary> /// Initializes a new instance of the <see cref="ForceKeepAliveMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/GeneralCommandMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/GeneralCommandMessage.cs index 6c71e73f9..5fbbb0624 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/GeneralCommandMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/GeneralCommandMessage.cs @@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// General command websocket message. /// </summary> -public class GeneralCommandMessage : WebSocketMessage<GeneralCommand>, IOutboundWebSocketMessage +public class GeneralCommandMessage : OutboundWebSocketMessage<GeneralCommand> { /// <summary> /// Initializes a new instance of the <see cref="GeneralCommandMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/LibraryChangedMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/LibraryChangedMessage.cs index 6432ae8ef..47417c405 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/LibraryChangedMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/LibraryChangedMessage.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Library changed message. /// </summary> -public class LibraryChangedMessage : WebSocketMessage<LibraryUpdateInfo>, IOutboundWebSocketMessage +public class LibraryChangedMessage : OutboundWebSocketMessage<LibraryUpdateInfo> { /// <summary> /// Initializes a new instance of the <see cref="LibraryChangedMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/OutboundKeepAliveMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/OutboundKeepAliveMessage.cs new file mode 100644 index 000000000..d907dcff9 --- /dev/null +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/OutboundKeepAliveMessage.cs @@ -0,0 +1,14 @@ +using System.ComponentModel; +using MediaBrowser.Model.Session; + +namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; + +/// <summary> +/// Keep alive websocket messages. +/// </summary> +public class OutboundKeepAliveMessage : OutboundWebSocketMessage +{ + /// <inheritdoc /> + [DefaultValue(SessionMessageType.KeepAlive)] + public override SessionMessageType MessageType => SessionMessageType.KeepAlive; +} diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PlayMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PlayMessage.cs index 7f943bda1..86ee2ff90 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PlayMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PlayMessage.cs @@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Play command websocket message. /// </summary> -public class PlayMessage : WebSocketMessage<PlayRequest>, IOutboundWebSocketMessage +public class PlayMessage : OutboundWebSocketMessage<PlayRequest> { /// <summary> /// Initializes a new instance of the <see cref="PlayMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PlaystateMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PlaystateMessage.cs index 804ccb37d..cd6d28cb3 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PlaystateMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PlaystateMessage.cs @@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Playstate message. /// </summary> -public class PlaystateMessage : WebSocketMessage<PlaystateRequest>, IOutboundWebSocketMessage +public class PlaystateMessage : OutboundWebSocketMessage<PlaystateRequest> { /// <summary> /// Initializes a new instance of the <see cref="PlaystateMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationCancelledMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationCancelledMessage.cs index 3d7dc5c93..17fd25938 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationCancelledMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationCancelledMessage.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Plugin installation cancelled message. /// </summary> -public class PluginInstallationCancelledMessage : WebSocketMessage<InstallationInfo>, IOutboundWebSocketMessage +public class PluginInstallationCancelledMessage : OutboundWebSocketMessage<InstallationInfo> { /// <summary> /// Initializes a new instance of the <see cref="PluginInstallationCancelledMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationCompletedMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationCompletedMessage.cs index 81268007f..3e60198ba 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationCompletedMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationCompletedMessage.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Plugin installation completed message. /// </summary> -public class PluginInstallationCompletedMessage : WebSocketMessage<InstallationInfo>, IOutboundWebSocketMessage +public class PluginInstallationCompletedMessage : OutboundWebSocketMessage<InstallationInfo> { /// <summary> /// Initializes a new instance of the <see cref="PluginInstallationCompletedMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationFailedMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationFailedMessage.cs index 9177f1293..40032f16e 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationFailedMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationFailedMessage.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Plugin installation failed message. /// </summary> -public class PluginInstallationFailedMessage : WebSocketMessage<InstallationInfo>, IOutboundWebSocketMessage +public class PluginInstallationFailedMessage : OutboundWebSocketMessage<InstallationInfo> { /// <summary> /// Initializes a new instance of the <see cref="PluginInstallationFailedMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallingMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallingMessage.cs index e371440a0..28861896f 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallingMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallingMessage.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Package installing message. /// </summary> -public class PluginInstallingMessage : WebSocketMessage<InstallationInfo>, IOutboundWebSocketMessage +public class PluginInstallingMessage : OutboundWebSocketMessage<InstallationInfo> { /// <summary> /// Initializes a new instance of the <see cref="PluginInstallingMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginUninstalledMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginUninstalledMessage.cs index b2994fc95..ca4959119 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginUninstalledMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginUninstalledMessage.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Plugin uninstalled message. /// </summary> -public class PluginUninstalledMessage : WebSocketMessage<PluginInfo>, IOutboundWebSocketMessage +public class PluginUninstalledMessage : OutboundWebSocketMessage<PluginInfo> { /// <summary> /// Initializes a new instance of the <see cref="PluginUninstalledMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/RefreshProgressMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/RefreshProgressMessage.cs index 42dbc3029..41b3cd46a 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/RefreshProgressMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/RefreshProgressMessage.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Refresh progress message. /// </summary> -public class RefreshProgressMessage : WebSocketMessage<Dictionary<string, string>>, IOutboundWebSocketMessage +public class RefreshProgressMessage : OutboundWebSocketMessage<Dictionary<string, string>> { /// <summary> /// Initializes a new instance of the <see cref="RefreshProgressMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/RestartRequiredMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/RestartRequiredMessage.cs index 3f3d9e4c8..a89f19b61 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/RestartRequiredMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/RestartRequiredMessage.cs @@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Restart required. /// </summary> -public class RestartRequiredMessage : WebSocketMessage, IOutboundWebSocketMessage +public class RestartRequiredMessage : OutboundWebSocketMessage { /// <inheritdoc /> [DefaultValue(SessionMessageType.RestartRequired)] diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ScheduledTaskEndedMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ScheduledTaskEndedMessage.cs index d69662b00..afa36fb72 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ScheduledTaskEndedMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ScheduledTaskEndedMessage.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Scheduled task ended message. /// </summary> -public class ScheduledTaskEndedMessage : WebSocketMessage<TaskResult>, IOutboundWebSocketMessage +public class ScheduledTaskEndedMessage : OutboundWebSocketMessage<TaskResult> { /// <summary> /// Initializes a new instance of the <see cref="ScheduledTaskEndedMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ScheduledTasksInfoMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ScheduledTasksInfoMessage.cs index 41a05b0de..c7360779f 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ScheduledTasksInfoMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ScheduledTasksInfoMessage.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Scheduled tasks info message. /// </summary> -public class ScheduledTasksInfoMessage : WebSocketMessage<IReadOnlyList<TaskInfo>>, IOutboundWebSocketMessage +public class ScheduledTasksInfoMessage : OutboundWebSocketMessage<IReadOnlyList<TaskInfo>> { /// <summary> /// Initializes a new instance of the <see cref="ScheduledTasksInfoMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SeriesTimerCancelledMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SeriesTimerCancelledMessage.cs index d4950b8b6..f832c8935 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SeriesTimerCancelledMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SeriesTimerCancelledMessage.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Series timer cancelled message. /// </summary> -public class SeriesTimerCancelledMessage : WebSocketMessage<TimerEventInfo>, IOutboundWebSocketMessage +public class SeriesTimerCancelledMessage : OutboundWebSocketMessage<TimerEventInfo> { /// <summary> /// Initializes a new instance of the <see cref="SeriesTimerCancelledMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SeriesTimerCreatedMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SeriesTimerCreatedMessage.cs index 091c10be6..450b4c799 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SeriesTimerCreatedMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SeriesTimerCreatedMessage.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Series timer created message. /// </summary> -public class SeriesTimerCreatedMessage : WebSocketMessage<TimerEventInfo>, IOutboundWebSocketMessage +public class SeriesTimerCreatedMessage : OutboundWebSocketMessage<TimerEventInfo> { /// <summary> /// Initializes a new instance of the <see cref="SeriesTimerCreatedMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ServerRestartingMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ServerRestartingMessage.cs index a465d8b00..8f09c802f 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ServerRestartingMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ServerRestartingMessage.cs @@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Server restarting down message. /// </summary> -public class ServerRestartingMessage : WebSocketMessage, IOutboundWebSocketMessage +public class ServerRestartingMessage : OutboundWebSocketMessage { /// <inheritdoc /> [DefaultValue(SessionMessageType.ServerRestarting)] diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ServerShuttingDownMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ServerShuttingDownMessage.cs index 0b998a523..485e71b6e 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ServerShuttingDownMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ServerShuttingDownMessage.cs @@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Server shutting down message. /// </summary> -public class ServerShuttingDownMessage : WebSocketMessage, IOutboundWebSocketMessage +public class ServerShuttingDownMessage : OutboundWebSocketMessage { /// <inheritdoc /> [DefaultValue(SessionMessageType.ServerShuttingDown)] diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SessionsMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SessionsMessage.cs index 4c91e0bca..3504831b8 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SessionsMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SessionsMessage.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.ComponentModel; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Session; @@ -7,13 +8,13 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Sessions message. /// </summary> -public class SessionsMessage : WebSocketMessage<SessionInfo>, IOutboundWebSocketMessage +public class SessionsMessage : OutboundWebSocketMessage<IReadOnlyList<SessionInfo>> { /// <summary> /// Initializes a new instance of the <see cref="SessionsMessage"/> class. /// </summary> /// <param name="data">Session info.</param> - public SessionsMessage(SessionInfo data) + public SessionsMessage(IReadOnlyList<SessionInfo> data) : base(data) { } diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayCommandMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayCommandMessage.cs index 17a0fc66e..d0624ec01 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayCommandMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayCommandMessage.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Sync play command. /// </summary> -public class SyncPlayCommandMessage : WebSocketMessage<SendCommand>, IOutboundWebSocketMessage +public class SyncPlayCommandMessage : OutboundWebSocketMessage<SendCommand> { /// <summary> /// Initializes a new instance of the <see cref="SyncPlayCommandMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandMessage.cs index d145d0e01..6a501aa7e 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandMessage.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Untyped sync play command. /// </summary> -public class SyncPlayGroupUpdateCommandMessage : WebSocketMessage<GroupUpdate>, IOutboundWebSocketMessage +public class SyncPlayGroupUpdateCommandMessage : OutboundWebSocketMessage<GroupUpdate> { /// <summary> /// Initializes a new instance of the <see cref="SyncPlayGroupUpdateCommandMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfGroupInfoMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfGroupInfoMessage.cs index 668392c66..47f706e2a 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfGroupInfoMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfGroupInfoMessage.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// Sync play group update command with group info. /// GroupUpdateTypes: GroupJoined. /// </summary> -public class SyncPlayGroupUpdateCommandOfGroupInfoMessage : WebSocketMessage<GroupUpdate<GroupInfoDto>>, IOutboundWebSocketMessage +public class SyncPlayGroupUpdateCommandOfGroupInfoMessage : OutboundWebSocketMessage<GroupUpdate<GroupInfoDto>> { /// <summary> /// Initializes a new instance of the <see cref="SyncPlayGroupUpdateCommandOfGroupInfoMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfGroupStateUpdateMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfGroupStateUpdateMessage.cs index ec8c3344f..11ddb1e25 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfGroupStateUpdateMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfGroupStateUpdateMessage.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// Sync play group update command with group state update. /// GroupUpdateTypes: StateUpdate. /// </summary> -public class SyncPlayGroupUpdateCommandOfGroupStateUpdateMessage : WebSocketMessage<GroupUpdate<GroupStateUpdate>>, IOutboundWebSocketMessage +public class SyncPlayGroupUpdateCommandOfGroupStateUpdateMessage : OutboundWebSocketMessage<GroupUpdate<GroupStateUpdate>> { /// <summary> /// Initializes a new instance of the <see cref="SyncPlayGroupUpdateCommandOfGroupStateUpdateMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfPlayQueueUpdateMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfPlayQueueUpdateMessage.cs index 465363f14..7e73399b1 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfPlayQueueUpdateMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfPlayQueueUpdateMessage.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// Sync play group update command with play queue update. /// GroupUpdateTypes: PlayQueue. /// </summary> -public class SyncPlayGroupUpdateCommandOfPlayQueueUpdateMessage : WebSocketMessage<GroupUpdate<PlayQueueUpdate>>, IOutboundWebSocketMessage +public class SyncPlayGroupUpdateCommandOfPlayQueueUpdateMessage : OutboundWebSocketMessage<GroupUpdate<PlayQueueUpdate>> { /// <summary> /// Initializes a new instance of the <see cref="SyncPlayGroupUpdateCommandOfPlayQueueUpdateMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfStringMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfStringMessage.cs index b87e9bf71..5b5ccd3ed 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfStringMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfStringMessage.cs @@ -8,7 +8,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// Sync play group update command with string. /// GroupUpdateTypes: GroupDoesNotExist (error), LibraryAccessDenied (error), NotInGroup (error), GroupLeft (groupId), UserJoined (username), UserLeft (username). /// </summary> -public class SyncPlayGroupUpdateCommandOfStringMessage : WebSocketMessage<GroupUpdate<string>>, IOutboundWebSocketMessage +public class SyncPlayGroupUpdateCommandOfStringMessage : OutboundWebSocketMessage<GroupUpdate<string>> { /// <summary> /// Initializes a new instance of the <see cref="SyncPlayGroupUpdateCommandOfStringMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/TimerCancelledMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/TimerCancelledMessage.cs index 0e70549ef..f44fd126b 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/TimerCancelledMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/TimerCancelledMessage.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Timer cancelled message. /// </summary> -public class TimerCancelledMessage : WebSocketMessage<TimerEventInfo>, IOutboundWebSocketMessage +public class TimerCancelledMessage : OutboundWebSocketMessage<TimerEventInfo> { /// <summary> /// Initializes a new instance of the <see cref="TimerCancelledMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/TimerCreatedMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/TimerCreatedMessage.cs index 295b3081c..8c1e102eb 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/TimerCreatedMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/TimerCreatedMessage.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// Timer created message. /// </summary> -public class TimerCreatedMessage : WebSocketMessage<TimerEventInfo>, IOutboundWebSocketMessage +public class TimerCreatedMessage : OutboundWebSocketMessage<TimerEventInfo> { /// <summary> /// Initializes a new instance of the <see cref="TimerCreatedMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserDataChangedMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserDataChangedMessage.cs index b60769540..6a053643d 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserDataChangedMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserDataChangedMessage.cs @@ -6,7 +6,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// User data changed message. /// </summary> -public class UserDataChangedMessage : WebSocketMessage<UserDataChangeInfo>, IOutboundWebSocketMessage +public class UserDataChangedMessage : OutboundWebSocketMessage<UserDataChangeInfo> { /// <summary> /// Initializes a new instance of the <see cref="UserDataChangedMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserDeletedMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserDeletedMessage.cs index 6d527be7f..add3f7771 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserDeletedMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserDeletedMessage.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// User deleted message. /// </summary> -public class UserDeletedMessage : WebSocketMessage<Guid>, IOutboundWebSocketMessage +public class UserDeletedMessage : OutboundWebSocketMessage<Guid> { /// <summary> /// Initializes a new instance of the <see cref="UserDeletedMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserUpdatedMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserUpdatedMessage.cs index 99e9a1f91..9a72deae1 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserUpdatedMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserUpdatedMessage.cs @@ -7,7 +7,7 @@ namespace MediaBrowser.Controller.Net.WebSocketMessages.Outbound; /// <summary> /// User updated message. /// </summary> -public class UserUpdatedMessage : WebSocketMessage<UserDto>, IOutboundWebSocketMessage +public class UserUpdatedMessage : OutboundWebSocketMessage<UserDto> { /// <summary> /// Initializes a new instance of the <see cref="UserUpdatedMessage"/> class. diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/OutboundWebSocketMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/OutboundWebSocketMessage.cs index dba3c8392..178245851 100644 --- a/MediaBrowser.Controller/Net/WebSocketMessages/OutboundWebSocketMessage.cs +++ b/MediaBrowser.Controller/Net/WebSocketMessages/OutboundWebSocketMessage.cs @@ -1,9 +1,14 @@ +using System; + namespace MediaBrowser.Controller.Net.WebSocketMessages; /// <summary> -/// Class representing the list of outbound websocket message types. -/// Only used in openapi generation. +/// Outbound websocket message. /// </summary> -public class OutboundWebSocketMessage : WebSocketMessage +public class OutboundWebSocketMessage : WebSocketMessage, IOutboundWebSocketMessage { + /// <summary> + /// Gets or sets the message id. + /// </summary> + public Guid MessageId { get; set; } = Guid.NewGuid(); } diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/OutboundWebSocketMessageOfT.cs b/MediaBrowser.Controller/Net/WebSocketMessages/OutboundWebSocketMessageOfT.cs new file mode 100644 index 000000000..cce331805 --- /dev/null +++ b/MediaBrowser.Controller/Net/WebSocketMessages/OutboundWebSocketMessageOfT.cs @@ -0,0 +1,33 @@ +#pragma warning disable SA1649 // File name must equal class name. + +using System; + +namespace MediaBrowser.Controller.Net.WebSocketMessages; + +/// <summary> +/// Outbound websocket message with data. +/// </summary> +/// <typeparam name="T">The data type.</typeparam> +public class OutboundWebSocketMessage<T> : WebSocketMessage<T>, IOutboundWebSocketMessage +{ + /// <summary> + /// Initializes a new instance of the <see cref="OutboundWebSocketMessage{T}"/> class. + /// </summary> + public OutboundWebSocketMessage() + { + } + + /// <summary> + /// Initializes a new instance of the <see cref="OutboundWebSocketMessage{T}"/> class. + /// </summary> + /// <param name="data">The data to send.</param> + protected OutboundWebSocketMessage(T data) + { + Data = data; + } + + /// <summary> + /// Gets or sets the message id. + /// </summary> + public Guid MessageId { get; set; } = Guid.NewGuid(); +} diff --git a/MediaBrowser.Controller/Net/WebSocketMessages/Shared/KeepAliveMessage.cs b/MediaBrowser.Controller/Net/WebSocketMessages/Shared/KeepAliveMessage.cs deleted file mode 100644 index 7f636212c..000000000 --- a/MediaBrowser.Controller/Net/WebSocketMessages/Shared/KeepAliveMessage.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System.ComponentModel; -using MediaBrowser.Model.Session; - -namespace MediaBrowser.Controller.Net.WebSocketMessages.Shared; - -/// <summary> -/// Keep alive websocket messages. -/// </summary> -public class KeepAliveMessage : WebSocketMessage<int>, IInboundWebSocketMessage, IOutboundWebSocketMessage -{ - /// <summary> - /// Initializes a new instance of the <see cref="KeepAliveMessage"/> class. - /// </summary> - /// <param name="data">The seconds to keep alive for.</param> - public KeepAliveMessage(int data) - : base(data) - { - } - - /// <inheritdoc /> - [DefaultValue(SessionMessageType.KeepAlive)] - public override SessionMessageType MessageType => SessionMessageType.KeepAlive; -} |
