aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Controller')
-rw-r--r--MediaBrowser.Controller/Collections/ICollectionManager.cs7
-rw-r--r--MediaBrowser.Controller/IServerApplicationHost.cs5
-rw-r--r--MediaBrowser.Controller/Lyrics/ILyricParser.cs28
-rw-r--r--MediaBrowser.Controller/Lyrics/ILyricProvider.cs36
-rw-r--r--MediaBrowser.Controller/Lyrics/LyricFile.cs28
-rw-r--r--MediaBrowser.Controller/Lyrics/LyricInfo.cs49
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs218
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingJobInfo.cs10
-rw-r--r--MediaBrowser.Controller/Net/BasePeriodicWebSocketListener.cs5
-rw-r--r--MediaBrowser.Controller/Net/IWebSocketConnection.cs13
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessage.cs6
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessageInfo.cs4
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessageOfT.cs5
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ActivityLogEntryStartMessage.cs10
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ActivityLogEntryStopMessage.cs13
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Inbound/InboundKeepAliveMessage.cs14
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ScheduledTasksInfoStartMessage.cs9
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Inbound/ScheduledTasksInfoStopMessage.cs13
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Inbound/SessionsStartMessage.cs8
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Inbound/SessionsStopMessage.cs12
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/InboundWebSocketMessage.cs7
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/InboundWebSocketMessageOfT.cs26
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ActivityLogEntryMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ForceKeepAliveMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/GeneralCommandMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/LibraryChangedMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/OutboundKeepAliveMessage.cs14
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PlayMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PlaystateMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationCancelledMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationCompletedMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallationFailedMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginInstallingMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/PluginUninstalledMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/RefreshProgressMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/RestartRequiredMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ScheduledTaskEndedMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ScheduledTasksInfoMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SeriesTimerCancelledMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SeriesTimerCreatedMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ServerRestartingMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/ServerShuttingDownMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SessionsMessage.cs5
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayCommandMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfGroupInfoMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfGroupStateUpdateMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfPlayQueueUpdateMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/SyncPlayGroupUpdateCommandOfStringMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/TimerCancelledMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/TimerCreatedMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserDataChangedMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserDeletedMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Outbound/UserUpdatedMessage.cs2
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/OutboundWebSocketMessage.cs11
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/OutboundWebSocketMessageOfT.cs33
-rw-r--r--MediaBrowser.Controller/Net/WebSocketMessages/Shared/KeepAliveMessage.cs23
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;
-}