diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..3b2db81
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,200 @@
+# With more recent updates Visual Studio 2017 supports EditorConfig files out of the box
+# Visual Studio Code needs an extension: https://github.com/editorconfig/editorconfig-vscode
+# For emacs, vim, np++ and other editors, see here: https://github.com/editorconfig
+###############################
+# Core EditorConfig Options #
+###############################
+root = true
+# All files
+[*]
+indent_style = space
+indent_size = 4
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+end_of_line = lf
+max_line_length = off
+
+# YAML indentation
+[*.{yml,yaml}]
+indent_size = 2
+
+# XML indentation
+[*.{csproj,xml}]
+indent_size = 2
+
+###############################
+# .NET Coding Conventions #
+###############################
+[*.{cs,vb}]
+# Organize usings
+dotnet_sort_system_directives_first = true
+# this. preferences
+dotnet_style_qualification_for_field = false:silent
+dotnet_style_qualification_for_property = false:silent
+dotnet_style_qualification_for_method = false:silent
+dotnet_style_qualification_for_event = false:silent
+# Language keywords vs BCL types preferences
+dotnet_style_predefined_type_for_locals_parameters_members = true:silent
+dotnet_style_predefined_type_for_member_access = true:silent
+# Parentheses preferences
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
+# Modifier preferences
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
+dotnet_style_readonly_field = true:suggestion
+# Expression-level preferences
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
+dotnet_style_prefer_auto_properties = true:silent
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+
+###############################
+# Naming Conventions #
+###############################
+# Style Definitions (From Roslyn)
+
+# Non-private static fields are PascalCase
+dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields
+dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style
+
+dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field
+dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected_internal, private_protected
+dotnet_naming_symbols.non_private_static_fields.required_modifiers = static
+
+dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case
+
+# Constants are PascalCase
+dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants
+dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style
+
+dotnet_naming_symbols.constants.applicable_kinds = field, local
+dotnet_naming_symbols.constants.required_modifiers = const
+
+dotnet_naming_style.constant_style.capitalization = pascal_case
+
+# Static fields are camelCase and start with s_
+dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion
+dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields
+dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style
+
+dotnet_naming_symbols.static_fields.applicable_kinds = field
+dotnet_naming_symbols.static_fields.required_modifiers = static
+
+dotnet_naming_style.static_field_style.capitalization = camel_case
+dotnet_naming_style.static_field_style.required_prefix = _
+
+# Instance fields are camelCase and start with _
+dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion
+dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields
+dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style
+
+dotnet_naming_symbols.instance_fields.applicable_kinds = field
+
+dotnet_naming_style.instance_field_style.capitalization = camel_case
+dotnet_naming_style.instance_field_style.required_prefix = _
+
+# Locals and parameters are camelCase
+dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion
+dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters
+dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style
+
+dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local
+
+dotnet_naming_style.camel_case_style.capitalization = camel_case
+
+# Local functions are PascalCase
+dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions
+dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style
+
+dotnet_naming_symbols.local_functions.applicable_kinds = local_function
+
+dotnet_naming_style.local_function_style.capitalization = pascal_case
+
+# By default, name items with PascalCase
+dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members
+dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style
+
+dotnet_naming_symbols.all_members.applicable_kinds = *
+
+dotnet_naming_style.pascal_case_style.capitalization = pascal_case
+
+###############################
+# Code Quality #
+###############################
+[*.cs]
+dotnet_code_quality.CA1826.exclude_ordefault_methods = true
+
+###############################
+# C# Coding Conventions #
+###############################
+[*.cs]
+# var preferences
+csharp_style_var_for_built_in_types = true:silent
+csharp_style_var_when_type_is_apparent = true:silent
+csharp_style_var_elsewhere = true:silent
+# Expression-bodied members
+csharp_style_expression_bodied_methods = false:silent
+csharp_style_expression_bodied_constructors = false:silent
+csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_properties = true:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_accessors = true:silent
+# Pattern matching preferences
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+# Null-checking preferences
+csharp_style_throw_expression = true:suggestion
+csharp_style_conditional_delegate_call = true:suggestion
+# Modifier preferences
+csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
+# Expression-level preferences
+csharp_prefer_braces = true:silent
+csharp_style_deconstructed_variable_declaration = true:suggestion
+csharp_prefer_simple_default_expression = true:suggestion
+csharp_style_pattern_local_over_anonymous_function = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+
+###############################
+# C# Formatting Rules #
+###############################
+# New line preferences
+csharp_new_line_before_open_brace = all
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_between_query_expression_clauses = true
+# Indentation preferences
+csharp_indent_case_contents = true
+csharp_indent_switch_labels = true
+csharp_indent_labels = flush_left
+# Space preferences
+csharp_space_after_cast = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+# Wrapping preferences
+csharp_preserve_single_line_statements = true
+csharp_preserve_single_line_blocks = true
diff --git a/jellyfin.ruleset b/jellyfin.ruleset
new file mode 100644
index 0000000..8af791c
--- /dev/null
+++ b/jellyfin.ruleset
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Jellyfin.Plugin.Dlna.Model/ContentFeatureBuilder.cs b/src/Jellyfin.Plugin.Dlna.Model/ContentFeatureBuilder.cs
index d503219..b863011 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/ContentFeatureBuilder.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/ContentFeatureBuilder.cs
@@ -1,6 +1,3 @@
-#nullable disable
-#pragma warning disable CS1591
-
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -10,15 +7,27 @@
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the .
+///
public static class ContentFeatureBuilder
{
+ ///
+ /// Gets the image header.
+ ///
+ /// The .
+ /// The container.
+ /// The width.
+ /// The height.
+ /// Value indicating wether the stream is direct.
+ /// The orgPn.
public static string BuildImageHeader(
DlnaDeviceProfile profile,
string container,
int? width,
int? height,
bool isDirectStream,
- string orgPn = null)
+ string? orgPn = null)
{
string orgOp = ";DLNA.ORG_OP=" + DlnaMaps.GetImageOrgOpValue();
@@ -36,7 +45,7 @@ public static string BuildImageHeader(
if (string.IsNullOrEmpty(orgPn))
{
- ResponseProfile mediaProfile = profile.GetImageMediaProfile(
+ ResponseProfile? mediaProfile = profile.GetImageMediaProfile(
container,
width,
height);
@@ -57,10 +66,23 @@ public static string BuildImageHeader(
return "DLNA.ORG_PN=" + orgPn + orgOp + orgCi + dlnaflags;
}
+ ///
+ /// Gets the audio header.
+ ///
+ /// The .
+ /// The container.
+ /// The codec.
+ /// The bitrate.
+ /// The sample rate.
+ /// The channel count.
+ /// The bit depth.
+ /// Value indicating wether the stream is direct.
+ /// The runtime ticks.
+ /// The .
public static string BuildAudioHeader(
DlnaDeviceProfile profile,
- string container,
- string audioCodec,
+ string? container,
+ string? audioCodec,
int? audioBitrate,
int? audioSampleRate,
int? audioChannels,
@@ -94,7 +116,7 @@ public static string BuildAudioHeader(
";DLNA.ORG_FLAGS={0}",
DlnaMaps.FlagsToString(flagValue));
- ResponseProfile mediaProfile = profile.GetAudioMediaProfile(
+ ResponseProfile? mediaProfile = profile.GetAudioMediaProfile(
container,
audioCodec,
audioChannels,
@@ -102,7 +124,7 @@ public static string BuildAudioHeader(
audioSampleRate,
audioBitDepth);
- string orgPn = mediaProfile?.OrgPn;
+ string? orgPn = mediaProfile?.OrgPn;
if (string.IsNullOrEmpty(orgPn))
{
@@ -117,11 +139,38 @@ public static string BuildAudioHeader(
return "DLNA.ORG_PN=" + orgPn + orgOp + orgCi + dlnaflags;
}
+ ///
+ /// Gets the auvideodio header.
+ ///
+ /// The .
+ /// The container.
+ /// The video codec.
+ /// The audio codec.
+ /// The width.
+ /// The height.
+ /// The bit depth.
+ /// The video bitrate.
+ /// The .
+ /// Value indicating wether the stream is direct.
+ /// The runtime ticks.
+ /// The video profile.
+ /// The .
+ /// The video level.
+ /// The video framerate.
+ /// The packet length.
+ /// The .
+ /// Value indicating wether the stream is anamorphic.
+ /// Value indicating wether the stream is interlaced.
+ /// The reference frames.
+ /// The number of video streams.
+ /// The number of audio streams.
+ /// The video codec tag.
+ /// Value indicating wether the stream is AVC.
public static IEnumerable BuildVideoHeader(
DlnaDeviceProfile profile,
- string container,
- string videoCodec,
- string audioCodec,
+ string? container,
+ string? videoCodec,
+ string? audioCodec,
int? width,
int? height,
int? bitDepth,
@@ -129,7 +178,7 @@ public static IEnumerable BuildVideoHeader(
TransportStreamTimestamp timestamp,
bool isDirectStream,
long? runtimeTicks,
- string videoProfile,
+ string? videoProfile,
VideoRangeType videoRangeType,
double? videoLevel,
float? videoFramerate,
@@ -140,7 +189,7 @@ public static IEnumerable BuildVideoHeader(
int? refFrames,
int? numVideoStreams,
int? numAudioStreams,
- string videoCodecTag,
+ string? videoCodecTag,
bool? isAvc)
{
// first bit means Time based seek supported, second byte range seek supported (not sure about the order now), so 01 = only byte seek, 10 = time based, 11 = both, 00 = none
@@ -170,7 +219,7 @@ public static IEnumerable BuildVideoHeader(
";DLNA.ORG_FLAGS={0}",
DlnaMaps.FlagsToString(flagValue));
- ResponseProfile mediaProfile = profile.GetVideoMediaProfile(
+ ResponseProfile? mediaProfile = profile.GetVideoMediaProfile(
container,
audioCodec,
videoCodec,
@@ -234,14 +283,14 @@ public static IEnumerable BuildVideoHeader(
return contentFeatureList;
}
- private static string GetImageOrgPnValue(string container, int? width, int? height)
+ private static string? GetImageOrgPnValue(string container, int? width, int? height)
{
MediaFormatProfile? format = MediaFormatProfileResolver.ResolveImageFormat(container, width, height);
return format.HasValue ? format.Value.ToString() : null;
}
- private static string GetAudioOrgPnValue(string container, int? audioBitrate, int? audioSampleRate, int? audioChannels)
+ private static string? GetAudioOrgPnValue(string? container, int? audioBitrate, int? audioSampleRate, int? audioChannels)
{
MediaFormatProfile? format = MediaFormatProfileResolver.ResolveAudioFormat(
container,
@@ -252,8 +301,8 @@ private static string GetAudioOrgPnValue(string container, int? audioBitrate, in
return format.HasValue ? format.Value.ToString() : null;
}
- private static MediaFormatProfile[] GetVideoOrgPnValue(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestamp)
+ private static MediaFormatProfile[] GetVideoOrgPnValue(string? container, string? videoCodec, string? audioCodec, int? width, int? height, TransportStreamTimestamp timestamp)
{
return MediaFormatProfileResolver.ResolveVideoFormat(container, videoCodec, audioCodec, width, height, timestamp);
}
-}
\ No newline at end of file
+}
diff --git a/src/Jellyfin.Plugin.Dlna.Model/DeviceIdentification.cs b/src/Jellyfin.Plugin.Dlna.Model/DeviceIdentification.cs
index 2e193d5..8773109 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/DeviceIdentification.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/DeviceIdentification.cs
@@ -1,7 +1,10 @@
-using System;
+#pragma warning disable CA1819 // Properties should not return arrays
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the .
+///
public class DeviceIdentification
{
///
@@ -56,5 +59,5 @@ public class DeviceIdentification
/// Gets or sets the headers.
///
/// The headers.
- public HttpHeaderInfo[] Headers { get; set; } = Array.Empty();
+ public HttpHeaderInfo[] Headers { get; set; } = [];
}
diff --git a/src/Jellyfin.Plugin.Dlna.Model/DeviceProfileInfo.cs b/src/Jellyfin.Plugin.Dlna.Model/DeviceProfileInfo.cs
index 9fe13e1..de07df4 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/DeviceProfileInfo.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/DeviceProfileInfo.cs
@@ -2,6 +2,9 @@
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the .
+///
public class DeviceProfileInfo
{
///
diff --git a/src/Jellyfin.Plugin.Dlna.Model/DeviceProfileType.cs b/src/Jellyfin.Plugin.Dlna.Model/DeviceProfileType.cs
index e5f495d..b754467 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/DeviceProfileType.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/DeviceProfileType.cs
@@ -1,7 +1,17 @@
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the .
+///
public enum DeviceProfileType
{
+ ///
+ /// System profile.
+ ///
System = 0,
+
+ ///
+ /// User profile.
+ ///
User = 1
}
diff --git a/src/Jellyfin.Plugin.Dlna.Model/DlnaDeviceProfile.cs b/src/Jellyfin.Plugin.Dlna.Model/DlnaDeviceProfile.cs
index f096de1..6e9af05 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/DlnaDeviceProfile.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/DlnaDeviceProfile.cs
@@ -1,3 +1,5 @@
+#pragma warning disable CA1819 // Properties should not return arrays
+
using System;
using System.ComponentModel;
using System.Linq;
@@ -10,6 +12,9 @@
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the .
+///
[XmlRoot("Profile")]
public class DlnaDeviceProfile : DeviceProfile
{
@@ -154,18 +159,18 @@ public class DlnaDeviceProfile : DeviceProfile
///
/// Gets or sets the XmlRootAttributes.
///
- public XmlAttribute[] XmlRootAttributes { get; set; } = Array.Empty();
+ public XmlAttribute[] XmlRootAttributes { get; set; } = [];
///
/// Gets or sets the ResponseProfiles.
///
- public ResponseProfile[] ResponseProfiles { get; set; } = Array.Empty();
+ public ResponseProfile[] ResponseProfiles { get; set; } = [];
///
- /// The GetSupportedMediaTypes.
+ /// The supported media types.
///
/// The .
- public MediaType[] GetSupportedMediaTypes()
+ public MediaType[] FetchSupportedMediaTypes()
{
return ContainerHelper.Split(SupportedMediaTypes)
.Select(m => Enum.TryParse(m, out var parsed) ? parsed : MediaType.Unknown)
@@ -265,8 +270,13 @@ public MediaType[] GetSupportedMediaTypes()
/// The width.
/// The height.
/// The .
- public ResponseProfile? GetImageMediaProfile(string container, int? width, int? height)
+ public ResponseProfile? GetImageMediaProfile(string? container, int? width, int? height)
{
+ if (container is null)
+ {
+ return null;
+ }
+
foreach (var i in ResponseProfiles)
{
if (i.Type != DlnaProfileType.Photo)
diff --git a/src/Jellyfin.Plugin.Dlna.Model/DlnaFlags.cs b/src/Jellyfin.Plugin.Dlna.Model/DlnaFlags.cs
index 71c360f..68e97f8 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/DlnaFlags.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/DlnaFlags.cs
@@ -1,49 +1,90 @@
-#pragma warning disable CS1591
+#pragma warning disable CA1711, CA1028
using System;
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the .
+///
[Flags]
public enum DlnaFlags : ulong
{
- /*! Background transfer mode.
- For use with upload and download transfers to and from the server.
- The primary difference between \ref DH_TransferMode_Interactive and
- \ref DH_TransferMode_Bulk is that the latter assumes that the user
- is not relying on the transfer for immediately rendering the content
- and there are no issues with causing a buffer overflow if the
- receiver uses TCP flow control to reduce total throughput.
- */
+ ///
+ /// Defines the .
+ ///
+ ///
+ /// Background transfer mode.
+ /// For use with upload and download transfers to and from the server.
+ /// The primary difference between DH_TransferMode_Interactive and DH_TransferMode_Bulk is that the latter assumes that the user is not relying on the transfer
+ /// for immediately rendering the content and there are no issues with causing a buffer overflow if the receiver uses TCP flow control to reduce total throughput.
+ ///
BackgroundTransferMode = 1 << 22,
+ ///
+ /// Byte based seek.
+ ///
ByteBasedSeek = 1 << 29,
+
+ ///
+ /// Connection stall.
+ ///
ConnectionStall = 1 << 21,
+ ///
+ /// DLNA v1.5.
+ ///
DlnaV15 = 1 << 20,
- /*! Interactive transfer mode.
- For best effort transfer of images and non-real-time transfers.
- URIs with image content usually support \ref DH_TransferMode_Bulk too.
- The primary difference between \ref DH_TransferMode_Interactive and
- \ref DH_TransferMode_Bulk is that the former assumes that the
- transfer is intended for immediate rendering.
- */
+ ///
+ /// Interactive transfer mode.
+ ///
+ ///
+ /// Interactive transfer mode.
+ /// For best effort transfer of images and non-real-time transfers.
+ /// URIs with image content usually support \ref DH_TransferMode_Bulk too.
+ /// The primary difference between DH_TransferMode_Interactive and DH_TransferMode_Bulk is that the former assumes that the transfer is intended for immediate rendering.
+ ///
InteractiveTransferMode = 1 << 23,
+ ///
+ /// Play container.
+ ///
PlayContainer = 1 << 28,
+
+ ///
+ /// RTSP pause.
+ ///
RtspPause = 1 << 25,
+
+ ///
+ /// S0 increase.
+ ///
S0Increase = 1 << 27,
+
+ ///
+ /// Sender paced.
+ ///
SenderPaced = 1L << 31,
+
+ ///
+ /// Sn increase.
+ ///
SnIncrease = 1 << 26,
- /*! Streaming transfer mode.
- The server transmits at a throughput sufficient for real-time playback of
- audio or video. URIs with audio or video often support the
- \ref DH_TransferMode_Interactive and \ref DH_TransferMode_Bulk transfer modes.
- The most well-known exception to this general claim is for live streams.
- */
+ ///
+ /// Byte based seek.
+ ///
+ ///
+ /// Streaming transfer mode.
+ /// The server transmits at a throughput sufficient for real-time playback of audio or video.
+ /// URIs with audio or video often support the DH_TransferMode_Interactive and DH_TransferMode_Bulk transfer modes.
+ /// The most well-known exception to this general claim is for live streams.
+ ///
StreamingTransferMode = 1 << 24,
+ ///
+ /// Time based seek.
+ ///
TimeBasedSeek = 1 << 30
}
diff --git a/src/Jellyfin.Plugin.Dlna.Model/DlnaMaps.cs b/src/Jellyfin.Plugin.Dlna.Model/DlnaMaps.cs
index c907d4f..483af19 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/DlnaMaps.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/DlnaMaps.cs
@@ -1,17 +1,30 @@
-#pragma warning disable CS1591
-
using System.Globalization;
using MediaBrowser.Model.Dlna;
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the .
+///
public static class DlnaMaps
{
+ ///
+ /// Takes DLNA flags and stringifies them.
+ ///
+ /// The .
+ /// The flags string.
public static string FlagsToString(DlnaFlags flags)
{
return string.Format(CultureInfo.InvariantCulture, "{0:X8}{1:D24}", (ulong)flags, 0);
}
+ ///
+ /// Gets the org operation value.
+ ///
+ /// Value indicating whether the stream has a known runtime.
+ /// Value indicating whether the stream is a direct stream.
+ /// The .
+ /// System.String.
public static string GetOrgOpValue(bool hasKnownRuntime, bool isDirectStream, TranscodeSeekInfo profileTranscodeSeekInfo)
{
if (hasKnownRuntime)
@@ -31,6 +44,9 @@ public static string GetOrgOpValue(bool hasKnownRuntime, bool isDirectStream, Tr
return "00";
}
+ ///
+ /// Gets the image org operation value.
+ ///
public static string GetImageOrgOpValue()
{
string orgOp = string.Empty;
diff --git a/src/Jellyfin.Plugin.Dlna.Model/HeaderMatchType.cs b/src/Jellyfin.Plugin.Dlna.Model/HeaderMatchType.cs
index 158f3d5..335a9a3 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/HeaderMatchType.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/HeaderMatchType.cs
@@ -1,8 +1,22 @@
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the .
+///
public enum HeaderMatchType
{
+ ///
+ /// Equals.
+ ///
Equals = 0,
+
+ ///
+ /// Regex.
+ ///
Regex = 1,
+
+ ///
+ /// Substring.
+ ///
Substring = 2
}
diff --git a/src/Jellyfin.Plugin.Dlna.Model/HttpHeaderInfo.cs b/src/Jellyfin.Plugin.Dlna.Model/HttpHeaderInfo.cs
index 910ca03..46ecce1 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/HttpHeaderInfo.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/HttpHeaderInfo.cs
@@ -4,14 +4,26 @@
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the .
+///
public class HttpHeaderInfo
{
+ ///
+ /// The name.
+ ///
[XmlAttribute("name")]
public string Name { get; set; }
+ ///
+ /// The value.
+ ///
[XmlAttribute("value")]
public string Value { get; set; }
+ ///
+ /// The .
+ ///
[XmlAttribute("match")]
public HeaderMatchType Match { get; set; }
}
diff --git a/src/Jellyfin.Plugin.Dlna.Model/IDeviceDiscovery.cs b/src/Jellyfin.Plugin.Dlna.Model/IDeviceDiscovery.cs
index 37bb4ad..cbc59f4 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/IDeviceDiscovery.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/IDeviceDiscovery.cs
@@ -1,13 +1,21 @@
-#pragma warning disable CS1591
-
using System;
using Jellyfin.Data.Events;
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the interface.
+///
+
public interface IDeviceDiscovery
{
+ ///
+ /// Occurs when [device discovered].
+ ///
event EventHandler> DeviceDiscovered;
+ ///
+ /// Occurs when [device left].
+ ///
event EventHandler> DeviceLeft;
}
diff --git a/src/Jellyfin.Plugin.Dlna.Model/IDlnaManager.cs b/src/Jellyfin.Plugin.Dlna.Model/IDlnaManager.cs
index ff62401..8159f0e 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/IDlnaManager.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/IDlnaManager.cs
@@ -1,13 +1,12 @@
-#pragma warning disable CS1591
-
using System.Collections.Generic;
using System.IO;
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Model.Dlna;
using Microsoft.AspNetCore.Http;
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the interface.
+///
public interface IDlnaManager
{
///
diff --git a/src/Jellyfin.Plugin.Dlna.Model/Jellyfin.Plugin.Dlna.Model.csproj b/src/Jellyfin.Plugin.Dlna.Model/Jellyfin.Plugin.Dlna.Model.csproj
index 7e2be85..f9f4ce9 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/Jellyfin.Plugin.Dlna.Model.csproj
+++ b/src/Jellyfin.Plugin.Dlna.Model/Jellyfin.Plugin.Dlna.Model.csproj
@@ -1,7 +1,11 @@
net8.0
+ true
+ true
enable
+ AllEnabledByDefault
+ ../../jellyfin.ruleset
diff --git a/src/Jellyfin.Plugin.Dlna.Model/MediaFormatProfile.cs b/src/Jellyfin.Plugin.Dlna.Model/MediaFormatProfile.cs
index 15a12f7..7ab5a42 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/MediaFormatProfile.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/MediaFormatProfile.cs
@@ -1,113 +1,529 @@
-#pragma warning disable CS1591, CA1707
+#pragma warning disable CA1707
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the .
+///
public enum MediaFormatProfile
{
+ ///
+ /// MP3.
+ ///
MP3,
+
+ ///
+ /// WMA_BASE.
+ ///
WMA_BASE,
+
+ ///
+ /// WMA_FULL.
+ ///
WMA_FULL,
+
+ ///
+ /// LPCM16_44_MONO.
+ ///
LPCM16_44_MONO,
+
+ ///
+ /// LPCM16_44_STEREO.
+ ///
LPCM16_44_STEREO,
+
+ ///
+ /// LPCM16_48_MONO.
+ ///
LPCM16_48_MONO,
+
+ ///
+ /// LPCM16_48_STEREO.
+ ///
LPCM16_48_STEREO,
+
+ ///
+ /// AAC_ISO.
+ ///
AAC_ISO,
+
+ ///
+ /// AAC_ISO_320.
+ ///
AAC_ISO_320,
+
+ ///
+ /// AAC_ADTS.
+ ///
AAC_ADTS,
+
+ ///
+ /// AAC_ADTS_320.
+ ///
AAC_ADTS_320,
+
+ ///
+ /// FLAC.
+ ///
FLAC,
+
+ ///
+ /// OGG.
+ ///
OGG,
+ ///
+ /// JPEG_SM.
+ ///
JPEG_SM,
+
+ ///
+ /// JPEG_MED.
+ ///
JPEG_MED,
+
+ ///
+ /// JPEG_LRG.
+ ///
JPEG_LRG,
+
+ ///
+ /// JPEG_TN.
+ ///
JPEG_TN,
+
+ ///
+ /// PNG_LRG.
+ ///
PNG_LRG,
+
+ ///
+ /// PNG_TN.
+ ///
PNG_TN,
+
+ ///
+ /// GIF_LRG.
+ ///
GIF_LRG,
+
+ ///
+ /// RAW.
+ ///
RAW,
+ ///
+ /// MPEG1.
+ ///
MPEG1,
+
+ ///
+ /// MPEG_PS_PAL.
+ ///
MPEG_PS_PAL,
+
+ ///
+ /// MPEG_PS_NTSC.
+ ///
MPEG_PS_NTSC,
+
+ ///
+ /// MPEG_TS_SD_EU.
+ ///
MPEG_TS_SD_EU,
+
+ ///
+ /// MPEG_TS_SD_EU_ISO.
+ ///
MPEG_TS_SD_EU_ISO,
+
+ ///
+ /// MPEG_TS_SD_EU_T.
+ ///
MPEG_TS_SD_EU_T,
+
+ ///
+ /// MPEG_TS_SD_NA.
+ ///
MPEG_TS_SD_NA,
+
+ ///
+ /// MPEG_TS_SD_NA_ISO.
+ ///
MPEG_TS_SD_NA_ISO,
+
+ ///
+ /// MPEG_TS_SD_NA_T.
+ ///
MPEG_TS_SD_NA_T,
+
+ ///
+ /// MPEG_TS_SD_KO.
+ ///
MPEG_TS_SD_KO,
+
+ ///
+ /// MPEG_TS_SD_KO_ISO.
+ ///
MPEG_TS_SD_KO_ISO,
+
+ ///
+ /// MPEG_TS_SD_KO_T.
+ ///
MPEG_TS_SD_KO_T,
+
+ ///
+ /// MPEG_TS_JP_T.
+ ///
MPEG_TS_JP_T,
+
+ ///
+ /// AVI.
+ ///
AVI,
+
+ ///
+ /// MATROSKA.
+ ///
MATROSKA,
+
+ ///
+ /// FLV.
+ ///
FLV,
+
+ ///
+ /// DVR_MS.
+ ///
DVR_MS,
+
+ ///
+ /// WTV.
+ ///
WTV,
+
+ ///
+ /// OGV.
+ ///
OGV,
+
+ ///
+ /// AVC_MP4_MP_SD_AAC_MULT5.
+ ///
AVC_MP4_MP_SD_AAC_MULT5,
+
+ ///
+ /// AVC_MP4_MP_SD_MPEG1_L3.
+ ///
AVC_MP4_MP_SD_MPEG1_L3,
+
+ ///
+ /// AVC_MP4_MP_SD_AC3.
+ ///
AVC_MP4_MP_SD_AC3,
+
+ ///
+ /// AVC_MP4_MP_HD_720p_AAC.
+ ///
AVC_MP4_MP_HD_720p_AAC,
+
+ ///
+ /// AVC_MP4_MP_HD_1080i_AAC.
+ ///
AVC_MP4_MP_HD_1080i_AAC,
+
+ ///
+ /// AVC_MP4_HP_HD_AAC.
+ ///
AVC_MP4_HP_HD_AAC,
+
+ ///
+ /// AVC_TS_MP_HD_AAC_MULT5.
+ ///
AVC_TS_MP_HD_AAC_MULT5,
+
+ ///
+ /// AVC_TS_MP_HD_AAC_MULT5_T.
+ ///
AVC_TS_MP_HD_AAC_MULT5_T,
+
+ ///
+ /// AVC_TS_MP_HD_AAC_MULT5_ISO.
+ ///
AVC_TS_MP_HD_AAC_MULT5_ISO,
+
+ ///
+ /// AVC_TS_MP_HD_MPEG1_L3.
+ ///
AVC_TS_MP_HD_MPEG1_L3,
+
+ ///
+ /// AVC_TS_MP_HD_MPEG1_L3_T.
+ ///
AVC_TS_MP_HD_MPEG1_L3_T,
+
+ ///
+ /// AVC_TS_MP_HD_MPEG1_L3_ISO.
+ ///
AVC_TS_MP_HD_MPEG1_L3_ISO,
+
+ ///
+ /// AVC_TS_MP_HD_AC3.
+ ///
AVC_TS_MP_HD_AC3,
+
+ ///
+ /// AVC_TS_MP_HD_AC3_T.
+ ///
AVC_TS_MP_HD_AC3_T,
+
+ ///
+ /// AVC_TS_MP_HD_AC3_ISO.
+ ///
AVC_TS_MP_HD_AC3_ISO,
+
+ ///
+ /// AVC_TS_HP_HD_MPEG1_L2_T.
+ ///
AVC_TS_HP_HD_MPEG1_L2_T,
+
+ ///
+ /// AVC_TS_HP_HD_MPEG1_L2_ISO.
+ ///
AVC_TS_HP_HD_MPEG1_L2_ISO,
+
+ ///
+ /// AVC_TS_MP_SD_AAC_MULT5.
+ ///
AVC_TS_MP_SD_AAC_MULT5,
+
+ ///
+ /// AVC_TS_MP_SD_AAC_MULT5_T.
+ ///
AVC_TS_MP_SD_AAC_MULT5_T,
+
+ ///
+ /// AVC_TS_MP_SD_AAC_MULT5_ISO.
+ ///
AVC_TS_MP_SD_AAC_MULT5_ISO,
+
+ ///
+ /// AVC_TS_MP_SD_MPEG1_L3.
+ ///
AVC_TS_MP_SD_MPEG1_L3,
+
+ ///
+ /// AVC_TS_MP_SD_MPEG1_L3_T.
+ ///
AVC_TS_MP_SD_MPEG1_L3_T,
+
+ ///
+ /// AVC_TS_MP_SD_MPEG1_L3_ISO.
+ ///
AVC_TS_MP_SD_MPEG1_L3_ISO,
+
+ ///
+ /// AVC_TS_HP_SD_MPEG1_L2_T.
+ ///
AVC_TS_HP_SD_MPEG1_L2_T,
+
+ ///
+ /// AVC_TS_HP_SD_MPEG1_L2_ISO.
+ ///
AVC_TS_HP_SD_MPEG1_L2_ISO,
+
+ ///
+ /// AVC_TS_MP_SD_AC3.
+ ///
AVC_TS_MP_SD_AC3,
+
+ ///
+ /// AVC_TS_MP_SD_AC3_T.
+ ///
AVC_TS_MP_SD_AC3_T,
+
+ ///
+ /// AVC_TS_MP_SD_AC3_ISO.
+ ///
AVC_TS_MP_SD_AC3_ISO,
+
+ ///
+ /// AVC_TS_HD_DTS_T.
+ ///
AVC_TS_HD_DTS_T,
+
+ ///
+ /// AVC_TS_HD_DTS_ISO.
+ ///
AVC_TS_HD_DTS_ISO,
+
+ ///
+ /// WMVMED_BASE.
+ ///
WMVMED_BASE,
+
+ ///
+ /// WMVMED_FULL.
+ ///
WMVMED_FULL,
+
+ ///
+ /// WMVMED_PRO.
+ ///
WMVMED_PRO,
+
+ ///
+ /// WMVHIGH_FULL.
+ ///
WMVHIGH_FULL,
+
+ ///
+ /// WMVHIGH_PRO.
+ ///
WMVHIGH_PRO,
+
+ ///
+ /// VC1_ASF_AP_L1_WMA.
+ ///
VC1_ASF_AP_L1_WMA,
+
+ ///
+ /// VC1_ASF_AP_L2_WMA.
+ ///
VC1_ASF_AP_L2_WMA,
+
+ ///
+ /// VC1_ASF_AP_L3_WMA.
+ ///
VC1_ASF_AP_L3_WMA,
+
+ ///
+ /// VC1_TS_AP_L1_AC3_ISO.
+ ///
VC1_TS_AP_L1_AC3_ISO,
+
+ ///
+ /// VC1_TS_AP_L2_AC3_ISO.
+ ///
VC1_TS_AP_L2_AC3_ISO,
+
+ ///
+ /// VC1_TS_HD_DTS_ISO.
+ ///
VC1_TS_HD_DTS_ISO,
+
+ ///
+ /// VC1_TS_HD_DTS_T.
+ ///
VC1_TS_HD_DTS_T,
+
+ ///
+ /// MPEG4_P2_MP4_ASP_AAC.
+ ///
MPEG4_P2_MP4_ASP_AAC,
+
+ ///
+ /// MPEG4_P2_MP4_SP_L6_AAC.
+ ///
MPEG4_P2_MP4_SP_L6_AAC,
+
+ ///
+ /// MPEG4_P2_MP4_NDSD.
+ ///
MPEG4_P2_MP4_NDSD,
+
+ ///
+ /// MPEG4_P2_TS_ASP_AAC.
+ ///
MPEG4_P2_TS_ASP_AAC,
+
+ ///
+ /// MPEG4_P2_TS_ASP_AAC_T.
+ ///
MPEG4_P2_TS_ASP_AAC_T,
+
+ ///
+ /// MPEG4_P2_TS_ASP_AAC_ISO.
+ ///
MPEG4_P2_TS_ASP_AAC_ISO,
+
+ ///
+ /// MPEG4_P2_TS_ASP_MPEG1_L3.
+ ///
MPEG4_P2_TS_ASP_MPEG1_L3,
+
+ ///
+ /// MPEG4_P2_TS_ASP_MPEG1_L3_T.
+ ///
MPEG4_P2_TS_ASP_MPEG1_L3_T,
+
+ ///
+ /// MPEG4_P2_TS_ASP_MPEG1_L3_ISO.
+ ///
MPEG4_P2_TS_ASP_MPEG1_L3_ISO,
+
+ ///
+ /// MPEG4_P2_TS_ASP_MPEG2_L2.
+ ///
MPEG4_P2_TS_ASP_MPEG2_L2,
+
+ ///
+ /// MPEG4_P2_TS_ASP_MPEG2_L2_T.
+ ///
MPEG4_P2_TS_ASP_MPEG2_L2_T,
+
+ ///
+ /// MPEG4_P2_TS_ASP_MPEG2_L2_ISO.
+ ///
MPEG4_P2_TS_ASP_MPEG2_L2_ISO,
+
+ ///
+ /// MPEG4_P2_TS_ASP_AC3.
+ ///
MPEG4_P2_TS_ASP_AC3,
+
+ ///
+ /// MPEG4_P2_TS_ASP_AC3_T.
+ ///
MPEG4_P2_TS_ASP_AC3_T,
+
+ ///
+ /// MPEG4_P2_TS_ASP_AC3_ISO.
+ ///
MPEG4_P2_TS_ASP_AC3_ISO,
+
+ ///
+ /// AVC_TS_HD_50_LPCM_T.
+ ///
AVC_TS_HD_50_LPCM_T,
+
+ ///
+ /// AVC_MP4_LPCM.
+ ///
AVC_MP4_LPCM,
+
+ ///
+ /// MPEG4_P2_3GPP_SP_L0B_AAC.
+ ///
MPEG4_P2_3GPP_SP_L0B_AAC,
+
+ ///
+ /// MPEG4_P2_3GPP_SP_L0B_AMR.
+ ///
MPEG4_P2_3GPP_SP_L0B_AMR,
+
+ ///
+ /// AVC_3GPP_BL_QCIF15_AAC.
+ ///
AVC_3GPP_BL_QCIF15_AAC,
+
+ ///
+ /// MPEG4_H263_3GPP_P0_L10_AMR.
+ ///
MPEG4_H263_3GPP_P0_L10_AMR,
+
+ ///
+ /// MPEG4_H263_MP4_P0_L10_AAC.
+ ///
MPEG4_H263_MP4_P0_L10_AAC
}
diff --git a/src/Jellyfin.Plugin.Dlna.Model/MediaFormatProfileResolver.cs b/src/Jellyfin.Plugin.Dlna.Model/MediaFormatProfileResolver.cs
index 5bad5f2..8f7b3ba 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/MediaFormatProfileResolver.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/MediaFormatProfileResolver.cs
@@ -1,6 +1,3 @@
-#nullable disable
-#pragma warning disable CS1591
-
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -8,41 +5,54 @@
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the .
+///
public static class MediaFormatProfileResolver
{
- public static MediaFormatProfile[] ResolveVideoFormat(string container, string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType)
+ ///
+ /// Gets the video format profiles.
+ ///
+ /// The container.
+ /// The video codec.
+ /// The audio codec.
+ /// The width.
+ /// The height.
+ /// The .
+ /// DeviceProfile[].
+ public static MediaFormatProfile[] ResolveVideoFormat(string? container, string? videoCodec, string? audioCodec, int? width, int? height, TransportStreamTimestamp timestampType)
{
if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase))
{
MediaFormatProfile? val = ResolveVideoASFFormat(videoCodec, audioCodec, width, height);
- return val.HasValue ? new MediaFormatProfile[] { val.Value } : Array.Empty();
+ return val.HasValue ? [val.Value] : [];
}
if (string.Equals(container, "mp4", StringComparison.OrdinalIgnoreCase))
{
MediaFormatProfile? val = ResolveVideoMP4Format(videoCodec, audioCodec, width, height);
- return val.HasValue ? new MediaFormatProfile[] { val.Value } : Array.Empty();
+ return val.HasValue ? [val.Value] : [];
}
if (string.Equals(container, "avi", StringComparison.OrdinalIgnoreCase))
{
- return new MediaFormatProfile[] { MediaFormatProfile.AVI };
+ return [MediaFormatProfile.AVI];
}
if (string.Equals(container, "mkv", StringComparison.OrdinalIgnoreCase))
{
- return new MediaFormatProfile[] { MediaFormatProfile.MATROSKA };
+ return [MediaFormatProfile.MATROSKA];
}
if (string.Equals(container, "mpeg2ps", StringComparison.OrdinalIgnoreCase) ||
string.Equals(container, "ts", StringComparison.OrdinalIgnoreCase))
{
- return new MediaFormatProfile[] { MediaFormatProfile.MPEG_PS_NTSC, MediaFormatProfile.MPEG_PS_PAL };
+ return [MediaFormatProfile.MPEG_PS_NTSC, MediaFormatProfile.MPEG_PS_PAL];
}
if (string.Equals(container, "mpeg1video", StringComparison.OrdinalIgnoreCase))
{
- return new MediaFormatProfile[] { MediaFormatProfile.MPEG1 };
+ return [MediaFormatProfile.MPEG1];
}
if (string.Equals(container, "mpeg2ts", StringComparison.OrdinalIgnoreCase) ||
@@ -54,29 +64,29 @@ public static MediaFormatProfile[] ResolveVideoFormat(string container, string v
if (string.Equals(container, "flv", StringComparison.OrdinalIgnoreCase))
{
- return new MediaFormatProfile[] { MediaFormatProfile.FLV };
+ return [MediaFormatProfile.FLV];
}
if (string.Equals(container, "wtv", StringComparison.OrdinalIgnoreCase))
{
- return new MediaFormatProfile[] { MediaFormatProfile.WTV };
+ return [MediaFormatProfile.WTV];
}
if (string.Equals(container, "3gp", StringComparison.OrdinalIgnoreCase))
{
MediaFormatProfile? val = ResolveVideo3GPFormat(videoCodec, audioCodec);
- return val.HasValue ? new MediaFormatProfile[] { val.Value } : Array.Empty();
+ return val.HasValue ? [val.Value] : [];
}
if (string.Equals(container, "ogv", StringComparison.OrdinalIgnoreCase) || string.Equals(container, "ogg", StringComparison.OrdinalIgnoreCase))
{
- return new MediaFormatProfile[] { MediaFormatProfile.OGV };
+ return [MediaFormatProfile.OGV];
}
- return Array.Empty();
+ return [];
}
- private static MediaFormatProfile[] ResolveVideoMPEG2TSFormat(string videoCodec, string audioCodec, int? width, int? height, TransportStreamTimestamp timestampType)
+ private static MediaFormatProfile[] ResolveVideoMPEG2TSFormat(string? videoCodec, string? audioCodec, int? width, int? height, TransportStreamTimestamp timestampType)
{
string suffix = string.Empty;
@@ -117,43 +127,43 @@ private static MediaFormatProfile[] ResolveVideoMPEG2TSFormat(string videoCodec,
{
if (string.Equals(audioCodec, "lpcm", StringComparison.OrdinalIgnoreCase))
{
- return new MediaFormatProfile[] { MediaFormatProfile.AVC_TS_HD_50_LPCM_T };
+ return [MediaFormatProfile.AVC_TS_HD_50_LPCM_T];
}
if (string.Equals(audioCodec, "dts", StringComparison.OrdinalIgnoreCase))
{
if (timestampType == TransportStreamTimestamp.None)
{
- return new MediaFormatProfile[] { MediaFormatProfile.AVC_TS_HD_DTS_ISO };
+ return [MediaFormatProfile.AVC_TS_HD_DTS_ISO];
}
- return new MediaFormatProfile[] { MediaFormatProfile.AVC_TS_HD_DTS_T };
+ return [MediaFormatProfile.AVC_TS_HD_DTS_T];
}
if (string.Equals(audioCodec, "mp2", StringComparison.OrdinalIgnoreCase))
{
if (timestampType == TransportStreamTimestamp.None)
{
- return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "AVC_TS_HP_{0}D_MPEG1_L2_ISO", resolution)) };
+ return [ValueOf(string.Format(CultureInfo.InvariantCulture, "AVC_TS_HP_{0}D_MPEG1_L2_ISO", resolution))];
}
- return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "AVC_TS_HP_{0}D_MPEG1_L2_T", resolution)) };
+ return [ValueOf(string.Format(CultureInfo.InvariantCulture, "AVC_TS_HP_{0}D_MPEG1_L2_T", resolution))];
}
if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase))
{
- return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "AVC_TS_MP_{0}D_AAC_MULT5{1}", resolution, suffix)) };
+ return [ValueOf(string.Format(CultureInfo.InvariantCulture, "AVC_TS_MP_{0}D_AAC_MULT5{1}", resolution, suffix))];
}
if (string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase))
{
- return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "AVC_TS_MP_{0}D_MPEG1_L3{1}", resolution, suffix)) };
+ return [ValueOf(string.Format(CultureInfo.InvariantCulture, "AVC_TS_MP_{0}D_MPEG1_L3{1}", resolution, suffix))];
}
if (string.IsNullOrEmpty(audioCodec) ||
string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase))
{
- return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "AVC_TS_MP_{0}D_AC3{1}", resolution, suffix)) };
+ return [ValueOf(string.Format(CultureInfo.InvariantCulture, "AVC_TS_MP_{0}D_AC3{1}", resolution, suffix))];
}
}
else if (string.Equals(videoCodec, "vc1", StringComparison.OrdinalIgnoreCase))
@@ -162,43 +172,43 @@ private static MediaFormatProfile[] ResolveVideoMPEG2TSFormat(string videoCodec,
{
if ((width.HasValue && width.Value > 720) || (height.HasValue && height.Value > 576))
{
- return new MediaFormatProfile[] { MediaFormatProfile.VC1_TS_AP_L2_AC3_ISO };
+ return [MediaFormatProfile.VC1_TS_AP_L2_AC3_ISO];
}
- return new MediaFormatProfile[] { MediaFormatProfile.VC1_TS_AP_L1_AC3_ISO };
+ return [MediaFormatProfile.VC1_TS_AP_L1_AC3_ISO];
}
if (string.Equals(audioCodec, "dts", StringComparison.OrdinalIgnoreCase))
{
suffix = string.Equals(suffix, "_ISO", StringComparison.OrdinalIgnoreCase) ? suffix : "_T";
- return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "VC1_TS_HD_DTS{0}", suffix)) };
+ return [ValueOf(string.Format(CultureInfo.InvariantCulture, "VC1_TS_HD_DTS{0}", suffix))];
}
}
else if (string.Equals(videoCodec, "mpeg4", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "msmpeg4", StringComparison.OrdinalIgnoreCase))
{
if (string.Equals(audioCodec, "aac", StringComparison.OrdinalIgnoreCase))
{
- return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "MPEG4_P2_TS_ASP_AAC{0}", suffix)) };
+ return [ValueOf(string.Format(CultureInfo.InvariantCulture, "MPEG4_P2_TS_ASP_AAC{0}", suffix))];
}
if (string.Equals(audioCodec, "mp3", StringComparison.OrdinalIgnoreCase))
{
- return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "MPEG4_P2_TS_ASP_MPEG1_L3{0}", suffix)) };
+ return [ValueOf(string.Format(CultureInfo.InvariantCulture, "MPEG4_P2_TS_ASP_MPEG1_L3{0}", suffix))];
}
if (string.Equals(audioCodec, "mp2", StringComparison.OrdinalIgnoreCase))
{
- return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "MPEG4_P2_TS_ASP_MPEG2_L2{0}", suffix)) };
+ return [ValueOf(string.Format(CultureInfo.InvariantCulture, "MPEG4_P2_TS_ASP_MPEG2_L2{0}", suffix))];
}
if (string.Equals(audioCodec, "ac3", StringComparison.OrdinalIgnoreCase))
{
- return new MediaFormatProfile[] { ValueOf(string.Format(CultureInfo.InvariantCulture, "MPEG4_P2_TS_ASP_AC3{0}", suffix)) };
+ return [ValueOf(string.Format(CultureInfo.InvariantCulture, "MPEG4_P2_TS_ASP_AC3{0}", suffix))];
}
}
- return Array.Empty();
+ return [];
}
private static MediaFormatProfile ValueOf(string value)
@@ -206,7 +216,7 @@ private static MediaFormatProfile ValueOf(string value)
return (MediaFormatProfile)Enum.Parse(typeof(MediaFormatProfile), value, true);
}
- private static MediaFormatProfile? ResolveVideoMP4Format(string videoCodec, string audioCodec, int? width, int? height)
+ private static MediaFormatProfile? ResolveVideoMP4Format(string? videoCodec, string? audioCodec, int? width, int? height)
{
if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
{
@@ -279,7 +289,7 @@ private static MediaFormatProfile ValueOf(string value)
return null;
}
- private static MediaFormatProfile? ResolveVideo3GPFormat(string videoCodec, string audioCodec)
+ private static MediaFormatProfile? ResolveVideo3GPFormat(string? videoCodec, string? audioCodec)
{
if (string.Equals(videoCodec, "h264", StringComparison.OrdinalIgnoreCase))
{
@@ -309,7 +319,7 @@ private static MediaFormatProfile ValueOf(string value)
return null;
}
- private static MediaFormatProfile? ResolveVideoASFFormat(string videoCodec, string audioCodec, int? width, int? height)
+ private static MediaFormatProfile? ResolveVideoASFFormat(string? videoCodec, string? audioCodec, int? width, int? height)
{
if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase) &&
(string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "wma", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "wmapro", StringComparison.OrdinalIgnoreCase)))
@@ -363,7 +373,15 @@ private static MediaFormatProfile ValueOf(string value)
return null;
}
- public static MediaFormatProfile? ResolveAudioFormat(string container, int? bitrate, int? frequency, int? channels)
+ ///
+ /// Gets the audio format profile.
+ ///
+ /// The container.
+ /// The bitrate.
+ /// The frequency.
+ /// The channel count.
+ /// MediaFormatProfile.
+ public static MediaFormatProfile? ResolveAudioFormat(string? container, int? bitrate, int? frequency, int? channels)
{
if (string.Equals(container, "asf", StringComparison.OrdinalIgnoreCase))
{
@@ -465,6 +483,13 @@ private static MediaFormatProfile ResolveAudioADTSFormat(int? bitrate)
return MediaFormatProfile.AAC_ADTS;
}
+ ///
+ /// Gets the image format profile.
+ ///
+ /// The container.
+ /// The width.
+ /// The height.
+ /// MediaFormatProfile.
public static MediaFormatProfile? ResolveImageFormat(string container, int? width, int? height)
{
if (string.Equals(container, "jpeg", StringComparison.OrdinalIgnoreCase) ||
diff --git a/src/Jellyfin.Plugin.Dlna.Model/ResponseProfile.cs b/src/Jellyfin.Plugin.Dlna.Model/ResponseProfile.cs
index cbd7b6b..42f58d5 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/ResponseProfile.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/ResponseProfile.cs
@@ -1,45 +1,81 @@
+#pragma warning disable CA1819 // Properties should not return arrays
#nullable disable
-using System;
using System.Xml.Serialization;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Extensions;
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the .
+///
public class ResponseProfile
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
public ResponseProfile()
{
- Conditions = Array.Empty();
+ Conditions = [];
}
+ ///
+ /// Gets or sets the container.
+ ///
[XmlAttribute("container")]
public string Container { get; set; }
+ ///
+ /// Gets or sets the audio codec.
+ ///
[XmlAttribute("audioCodec")]
public string AudioCodec { get; set; }
+ ///
+ /// Gets or sets the video codec.
+ ///
[XmlAttribute("videoCodec")]
public string VideoCodec { get; set; }
+ ///
+ /// Gets or sets the type.
+ ///
[XmlAttribute("type")]
public DlnaProfileType Type { get; set; }
+ ///
+ /// Gets or sets the orgPn.
+ ///
[XmlAttribute("orgPn")]
public string OrgPn { get; set; }
+ ///
+ /// Gets or sets the MIME type.
+ ///
[XmlAttribute("mimeType")]
public string MimeType { get; set; }
+ ///
+ /// Gets or sets the conditions.
+ ///
public ProfileCondition[] Conditions { get; set; }
+ ///
+ /// Gets the containers.
+ ///
public string[] GetContainers()
=> ContainerHelper.Split(Container);
+ ///
+ /// Gets the audio codecs.
+ ///
public string[] GetAudioCodecs()
=> ContainerHelper.Split(AudioCodec);
+ ///
+ /// Gets the video codecs.
+ ///
public string[] GetVideoCodecs()
=> ContainerHelper.Split(VideoCodec);
}
diff --git a/src/Jellyfin.Plugin.Dlna.Model/SearchCriteria.cs b/src/Jellyfin.Plugin.Dlna.Model/SearchCriteria.cs
index 12da5b4..9d9344b 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/SearchCriteria.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/SearchCriteria.cs
@@ -1,12 +1,17 @@
-#pragma warning disable CS1591
-
using System;
using System.Text.RegularExpressions;
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the .
+///
public partial class SearchCriteria
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The search string.
public SearchCriteria(string search)
{
ArgumentException.ThrowIfNullOrEmpty(search);
@@ -44,6 +49,9 @@ public SearchCriteria(string search)
}
}
+ ///
+ /// Gets or sets the search type.
+ ///
public SearchType SearchType { get; set; }
[GeneratedRegex("\\s")]
diff --git a/src/Jellyfin.Plugin.Dlna.Model/SearchType.cs b/src/Jellyfin.Plugin.Dlna.Model/SearchType.cs
index 31f8d19..dc76ce4 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/SearchType.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/SearchType.cs
@@ -1,13 +1,37 @@
-#pragma warning disable CS1591
-
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the .
+///
public enum SearchType
{
+ ///
+ /// Unknown.
+ ///
Unknown = 0,
+
+ ///
+ /// Audio.
+ ///
Audio = 1,
+
+ ///
+ /// Image.
+ ///
Image = 2,
+
+ ///
+ /// Video.
+ ///
Video = 3,
+
+ ///
+ /// Playlist.
+ ///
Playlist = 4,
+
+ ///
+ /// Music Album.
+ ///
MusicAlbum = 5
}
diff --git a/src/Jellyfin.Plugin.Dlna.Model/SortCriteria.cs b/src/Jellyfin.Plugin.Dlna.Model/SortCriteria.cs
index 4a8a351..a4efec5 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/SortCriteria.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/SortCriteria.cs
@@ -1,12 +1,17 @@
-#pragma warning disable CS1591
-
using System;
using Jellyfin.Data.Enums;
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the .
+///
public class SortCriteria
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The sort order.
public SortCriteria(string sortOrder)
{
if (Enum.TryParse(sortOrder, true, out var sortOrderValue))
@@ -19,5 +24,8 @@ public SortCriteria(string sortOrder)
}
}
+ ///
+ /// Gets the sort order.
+ ///
public SortOrder SortOrder { get; }
}
diff --git a/src/Jellyfin.Plugin.Dlna.Model/UpnpDeviceInfo.cs b/src/Jellyfin.Plugin.Dlna.Model/UpnpDeviceInfo.cs
index 6a18e9e..fca0caf 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/UpnpDeviceInfo.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/UpnpDeviceInfo.cs
@@ -1,5 +1,6 @@
#nullable disable
-#pragma warning disable CS1591
+
+#pragma warning disable CA2227
using System;
using System.Collections.Generic;
@@ -7,15 +8,33 @@
namespace Jellyfin.Plugin.Dlna.Model;
+///
+/// Defines the .
+///
public class UpnpDeviceInfo
{
+ ///
+ /// Gets or sets the location.
+ ///
public Uri Location { get; set; }
+ ///
+ /// Gets the headers.
+ ///
public Dictionary Headers { get; set; }
+ ///
+ /// Gets or sets local IP address.
+ ///
public IPAddress LocalIPAddress { get; set; }
+ ///
+ /// Gets or sets the local port.
+ ///
public int LocalPort { get; set; }
+ ///
+ /// Gets or sets the remote IP address.
+ ///
public IPAddress RemoteIPAddress { get; set; }
}
diff --git a/src/Jellyfin.Plugin.Dlna.Model/XmlAttribute.cs b/src/Jellyfin.Plugin.Dlna.Model/XmlAttribute.cs
index c480fad..9c533d3 100644
--- a/src/Jellyfin.Plugin.Dlna.Model/XmlAttribute.cs
+++ b/src/Jellyfin.Plugin.Dlna.Model/XmlAttribute.cs
@@ -1,5 +1,7 @@
#nullable disable
+#pragma warning disable CA1711
+
using System.Xml.Serialization;
namespace Jellyfin.Plugin.Dlna.Model;
diff --git a/src/Jellyfin.Plugin.Dlna.Playback/DynamicHlsHelper.cs b/src/Jellyfin.Plugin.Dlna.Playback/DynamicHlsHelper.cs
index 2cbf6d8..537cfb5 100644
--- a/src/Jellyfin.Plugin.Dlna.Playback/DynamicHlsHelper.cs
+++ b/src/Jellyfin.Plugin.Dlna.Playback/DynamicHlsHelper.cs
@@ -12,7 +12,6 @@
using Jellyfin.Extensions;
using Jellyfin.Plugin.Dlna.Model;
using Jellyfin.Plugin.Dlna.Playback.Extensions;
-using Jellyfin.Plugin.Dlna.Playback.Model;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Net;
@@ -151,7 +150,7 @@ private async Task GetMasterPlaylistInternal(
_httpContextAccessor.HttpContext.Response.Headers.Append(HeaderNames.Expires, "0");
if (isHeadRequest)
{
- return new FileContentResult(Array.Empty(), MimeTypes.GetMimeType("playlist.m3u8"));
+ return new FileContentResult([], MimeTypes.GetMimeType("playlist.m3u8"));
}
var totalBitrate = (state.OutputAudioBitrate ?? 0) + (state.OutputVideoBitrate ?? 0);
@@ -569,7 +568,7 @@ private void AddTrickplay(StreamState state, Dictionary tric
&& state.VideoStream is not null
&& state.VideoStream.Level.HasValue)
{
- levelString = state.VideoStream.Level.ToString() ?? string.Empty;
+ levelString = state.VideoStream.Level?.ToString(CultureInfo.InvariantCulture) ?? string.Empty;
}
else
{
diff --git a/src/Jellyfin.Plugin.Dlna.Playback/FileStreamResponseHelpers.cs b/src/Jellyfin.Plugin.Dlna.Playback/FileStreamResponseHelpers.cs
index e533006..e05eb0c 100644
--- a/src/Jellyfin.Plugin.Dlna.Playback/FileStreamResponseHelpers.cs
+++ b/src/Jellyfin.Plugin.Dlna.Playback/FileStreamResponseHelpers.cs
@@ -93,7 +93,7 @@ public static async Task GetTranscodedFile(
return new OkResult();
}
- using var transcodingLock = await transcodeManager.LockAsync(outputPath, cancellationTokenSource.Token);
+ using var transcodingLock = await transcodeManager.LockAsync(outputPath, cancellationTokenSource.Token).ConfigureAwait(false);
TranscodingJob? job;
if (!File.Exists(outputPath))
diff --git a/src/Jellyfin.Plugin.Dlna.Playback/Jellyfin.Plugin.Dlna.Playback.csproj b/src/Jellyfin.Plugin.Dlna.Playback/Jellyfin.Plugin.Dlna.Playback.csproj
index c70babd..0621bc1 100644
--- a/src/Jellyfin.Plugin.Dlna.Playback/Jellyfin.Plugin.Dlna.Playback.csproj
+++ b/src/Jellyfin.Plugin.Dlna.Playback/Jellyfin.Plugin.Dlna.Playback.csproj
@@ -1,7 +1,11 @@
net8.0
+ true
+ true
enable
+ AllEnabledByDefault
+ ../../jellyfin.ruleset
diff --git a/src/Jellyfin.Plugin.Dlna.Playback/Model/DlnaStreamState.cs b/src/Jellyfin.Plugin.Dlna.Playback/Model/DlnaStreamState.cs
index 56cd183..959fb49 100644
--- a/src/Jellyfin.Plugin.Dlna.Playback/Model/DlnaStreamState.cs
+++ b/src/Jellyfin.Plugin.Dlna.Playback/Model/DlnaStreamState.cs
@@ -5,8 +5,17 @@
namespace Jellyfin.Plugin.Dlna.Playback.Model;
+///
+/// Defines the .
+///
public class DlnaStreamState : StreamState
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Instance of the interface.
+ /// The .
+ /// Instance of the interface.
public DlnaStreamState(
IMediaSourceManager mediaSourceManager,
TranscodingJobType transcodingType,
diff --git a/src/Jellyfin.Plugin.Dlna.Playback/StreamingHelpers.cs b/src/Jellyfin.Plugin.Dlna.Playback/StreamingHelpers.cs
index d00ccd2..78b54e6 100644
--- a/src/Jellyfin.Plugin.Dlna.Playback/StreamingHelpers.cs
+++ b/src/Jellyfin.Plugin.Dlna.Playback/StreamingHelpers.cs
@@ -130,7 +130,7 @@ public static async Task GetStreamingState(
var item = libraryManager.GetItemById(streamingRequest.Id);
- state.IsInputVideo = item.MediaType == MediaType.Video;
+ state.IsInputVideo = item?.MediaType == MediaType.Video;
MediaSourceInfo? mediaSource = null;
if (string.IsNullOrWhiteSpace(streamingRequest.LiveStreamId))
@@ -251,8 +251,8 @@ public static async Task GetStreamingState(
}
var deviceProfileId = state.IsVideoRequest
- ? (streamingRequest as DlnaVideoRequestDto).DeviceProfileId
- : (streamingRequest as DlnaStreamingRequestDto).DeviceProfileId;
+ ? (streamingRequest as DlnaVideoRequestDto)?.DeviceProfileId
+ : (streamingRequest as DlnaStreamingRequestDto)?.DeviceProfileId;
ApplyDeviceProfileSettings(state, dlnaManager, deviceManager, httpRequest, deviceProfileId, streamingRequest.Static);
var ext = string.IsNullOrWhiteSpace(state.OutputContainer)
diff --git a/src/Jellyfin.Plugin.Dlna/Api/DlnaServerController.cs b/src/Jellyfin.Plugin.Dlna/Api/DlnaServerController.cs
index 99630c3..ea09310 100644
--- a/src/Jellyfin.Plugin.Dlna/Api/DlnaServerController.cs
+++ b/src/Jellyfin.Plugin.Dlna/Api/DlnaServerController.cs
@@ -1,6 +1,5 @@
using System;
using System.ComponentModel.DataAnnotations;
-using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Net.Mime;
using System.Threading.Tasks;
@@ -22,7 +21,7 @@ namespace Jellyfin.Plugin.Dlna.Api;
[Authorize(Policy = Policies.AnonymousLanAccessPolicy)]
public class DlnaServerController : ControllerBase
{
- private static readonly string[] _relativePathUserAgents = { "Bigscreen" };
+ private static readonly string[] _relativePathUserAgents = ["Bigscreen"];
private readonly IDlnaManager _dlnaManager;
private readonly IContentDirectory _contentDirectory;
@@ -66,7 +65,7 @@ public ActionResult GetDescriptionXml([FromRoute, Required] string serve
string? userAgent = Request.Headers.UserAgent;
if (userAgent is not null)
{
- var firstIndexOfSlash = userAgent.IndexOf('/');
+ var firstIndexOfSlash = userAgent.IndexOf('/', StringComparison.OrdinalIgnoreCase);
if (firstIndexOfSlash > 0)
{
userAgent = userAgent.Substring(0, firstIndexOfSlash);
@@ -94,7 +93,6 @@ public ActionResult GetDescriptionXml([FromRoute, Required] string serve
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
[Produces(MediaTypeNames.Text.Xml)]
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
public ActionResult GetContentDirectory([FromRoute, Required] string serverId)
{
return Ok(_contentDirectory.GetServiceXml());
@@ -113,7 +111,6 @@ public ActionResult GetContentDirectory([FromRoute, Required] string ser
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
[Produces(MediaTypeNames.Text.Xml)]
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
public ActionResult GetMediaReceiverRegistrar([FromRoute, Required] string serverId)
{
return Ok(_mediaReceiverRegistrar.GetServiceXml());
@@ -132,7 +129,6 @@ public ActionResult GetMediaReceiverRegistrar([FromRoute, Required] stri
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
[Produces(MediaTypeNames.Text.Xml)]
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
public ActionResult GetConnectionManager([FromRoute, Required] string serverId)
{
return Ok(_connectionManager.GetServiceXml());
@@ -195,8 +191,7 @@ public async Task> ProcessMediaReceiverRegistrarCo
/// Event subscription response.
[HttpSubscribe("{serverId}/MediaReceiverRegistrar/Events")]
[HttpUnsubscribe("{serverId}/MediaReceiverRegistrar/Events")]
- [ApiExplorerSettings(IgnoreApi = true)] // Ignore in openapi docs
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
+ [ApiExplorerSettings(IgnoreApi = true)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
[Produces(MediaTypeNames.Text.Xml)]
@@ -214,8 +209,7 @@ public ActionResult ProcessMediaReceiverRegistrarEven
/// Event subscription response.
[HttpSubscribe("{serverId}/ContentDirectory/Events")]
[HttpUnsubscribe("{serverId}/ContentDirectory/Events")]
- [ApiExplorerSettings(IgnoreApi = true)] // Ignore in openapi docs
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
+ [ApiExplorerSettings(IgnoreApi = true)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
[Produces(MediaTypeNames.Text.Xml)]
@@ -233,8 +227,7 @@ public ActionResult ProcessContentDirectoryEventReque
/// Event subscription response.
[HttpSubscribe("{serverId}/ConnectionManager/Events")]
[HttpUnsubscribe("{serverId}/ConnectionManager/Events")]
- [ApiExplorerSettings(IgnoreApi = true)] // Ignore in openapi docs
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
+ [ApiExplorerSettings(IgnoreApi = true)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
[Produces(MediaTypeNames.Text.Xml)]
@@ -253,7 +246,6 @@ public ActionResult ProcessConnectionManagerEventRequ
/// DLNA is disabled.
/// Icon stream.
[HttpGet("{serverId}/icons/{fileName}")]
- [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "serverId", Justification = "Required for DLNA")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status503ServiceUnavailable)]
diff --git a/src/Jellyfin.Plugin.Dlna/Api/HttpSubscribeAttribute.cs b/src/Jellyfin.Plugin.Dlna/Api/HttpSubscribeAttribute.cs
index c95b3c4..0bdf189 100644
--- a/src/Jellyfin.Plugin.Dlna/Api/HttpSubscribeAttribute.cs
+++ b/src/Jellyfin.Plugin.Dlna/Api/HttpSubscribeAttribute.cs
@@ -9,7 +9,7 @@ namespace Jellyfin.Plugin.Dlna.Api;
///
public sealed class HttpSubscribeAttribute : HttpMethodAttribute
{
- private static readonly IEnumerable _supportedMethods = new[] { "SUBSCRIBE" };
+ private static readonly IEnumerable _supportedMethods = ["SUBSCRIBE"];
///
/// Initializes a new instance of the class.
diff --git a/src/Jellyfin.Plugin.Dlna/Api/HttpUnsubscribeAttribute.cs b/src/Jellyfin.Plugin.Dlna/Api/HttpUnsubscribeAttribute.cs
index 0505ab1..0f31943 100644
--- a/src/Jellyfin.Plugin.Dlna/Api/HttpUnsubscribeAttribute.cs
+++ b/src/Jellyfin.Plugin.Dlna/Api/HttpUnsubscribeAttribute.cs
@@ -9,7 +9,7 @@ namespace Jellyfin.Plugin.Dlna.Api;
///
public sealed class HttpUnsubscribeAttribute : HttpMethodAttribute
{
- private static readonly IEnumerable _supportedMethods = new[] { "UNSUBSCRIBE" };
+ private static readonly IEnumerable _supportedMethods = ["UNSUBSCRIBE"];
///
/// Initializes a new instance of the class.
diff --git a/src/Jellyfin.Plugin.Dlna/Common/ServiceAction.cs b/src/Jellyfin.Plugin.Dlna/Common/ServiceAction.cs
index a103b87..83968ae 100644
--- a/src/Jellyfin.Plugin.Dlna/Common/ServiceAction.cs
+++ b/src/Jellyfin.Plugin.Dlna/Common/ServiceAction.cs
@@ -12,7 +12,7 @@ public class ServiceAction
///
public ServiceAction()
{
- ArgumentList = new List();
+ ArgumentList = [];
}
///
@@ -23,7 +23,7 @@ public ServiceAction()
///
/// Gets the ArgumentList.
///
- public List ArgumentList { get; }
+ public IReadOnlyList ArgumentList { get; set;}
///
public override string ToString() => Name;
diff --git a/src/Jellyfin.Plugin.Dlna/Configuration/DlnaPluginConfiguration.cs b/src/Jellyfin.Plugin.Dlna/Configuration/DlnaPluginConfiguration.cs
index 1a04a15..e007340 100644
--- a/src/Jellyfin.Plugin.Dlna/Configuration/DlnaPluginConfiguration.cs
+++ b/src/Jellyfin.Plugin.Dlna/Configuration/DlnaPluginConfiguration.cs
@@ -3,6 +3,9 @@
namespace Jellyfin.Plugin.Dlna.Configuration;
+///
+/// Defines the .
+///
public class DlnaPluginConfiguration : BasePluginConfiguration
{
///
diff --git a/src/Jellyfin.Plugin.Dlna/ConnectionManager/ConnectionManagerService.cs b/src/Jellyfin.Plugin.Dlna/ConnectionManager/ConnectionManagerService.cs
index 15999c6..89dcc66 100644
--- a/src/Jellyfin.Plugin.Dlna/ConnectionManager/ConnectionManagerService.cs
+++ b/src/Jellyfin.Plugin.Dlna/ConnectionManager/ConnectionManagerService.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System.Net.Http;
using System.Threading.Tasks;
using Jellyfin.Plugin.Dlna.Service;
diff --git a/src/Jellyfin.Plugin.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs b/src/Jellyfin.Plugin.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs
index d63179c..1502e0c 100644
--- a/src/Jellyfin.Plugin.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs
+++ b/src/Jellyfin.Plugin.Dlna/ConnectionManager/ConnectionManagerXmlBuilder.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System.Collections.Generic;
using Jellyfin.Plugin.Dlna.Common;
using Jellyfin.Plugin.Dlna.Service;
@@ -18,7 +16,7 @@ public static class ConnectionManagerXmlBuilder
/// An XML description of this service.
public static string GetXml()
{
- return new ServiceXmlBuilder().GetXml(ServiceActionListBuilder.GetActions(), GetStateVariables());
+ return ServiceXmlBuilder.GetXml(ServiceActionListBuilder.GetActions(), GetStateVariables());
}
///
@@ -27,8 +25,8 @@ public static string GetXml()
/// The .
private static IEnumerable GetStateVariables()
{
- return new StateVariable[]
- {
+ return
+ [
new StateVariable
{
Name = "SourceProtocolInfo",
@@ -56,14 +54,14 @@ private static IEnumerable GetStateVariables()
DataType = "string",
SendsEvents = false,
- AllowedValues = new[]
- {
+ AllowedValues =
+ [
"OK",
"ContentFormatMismatch",
"InsufficientBandwidth",
"UnreliableChannel",
"Unknown"
- }
+ ]
},
new StateVariable
@@ -79,11 +77,11 @@ private static IEnumerable GetStateVariables()
DataType = "string",
SendsEvents = false,
- AllowedValues = new[]
- {
+ AllowedValues =
+ [
"Output",
"Input"
- }
+ ]
},
new StateVariable
@@ -113,6 +111,6 @@ private static IEnumerable GetStateVariables()
DataType = "ui4",
SendsEvents = false
}
- };
+ ];
}
}
diff --git a/src/Jellyfin.Plugin.Dlna/ConnectionManager/ControlHandler.cs b/src/Jellyfin.Plugin.Dlna/ConnectionManager/ControlHandler.cs
index 3a3a101..60a7f2d 100644
--- a/src/Jellyfin.Plugin.Dlna/ConnectionManager/ControlHandler.cs
+++ b/src/Jellyfin.Plugin.Dlna/ConnectionManager/ControlHandler.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System;
using System.Collections.Generic;
using System.Xml;
@@ -20,8 +18,8 @@ public class ControlHandler : BaseControlHandler
///
/// Initializes a new instance of the class.
///
- /// The for use with the instance.
- /// The for use with the instance.
+ /// The .
+ /// The .
public ControlHandler(ILogger logger, DlnaDeviceProfile profile)
: base(logger)
{
diff --git a/src/Jellyfin.Plugin.Dlna/ConnectionManager/ServiceActionListBuilder.cs b/src/Jellyfin.Plugin.Dlna/ConnectionManager/ServiceActionListBuilder.cs
index 8dc2e15..5954407 100644
--- a/src/Jellyfin.Plugin.Dlna/ConnectionManager/ServiceActionListBuilder.cs
+++ b/src/Jellyfin.Plugin.Dlna/ConnectionManager/ServiceActionListBuilder.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System.Collections.Generic;
using Jellyfin.Plugin.Dlna.Common;
@@ -11,7 +9,7 @@ namespace Jellyfin.Plugin.Dlna.ConnectionManager;
public static class ServiceActionListBuilder
{
///
- /// Returns an enumerable of the ConnectionManagar:1 DLNA actions.
+ /// Returns an enumerable of the ConnectionManager:1 DLNA actions.
///
/// An .
public static IEnumerable GetActions()
@@ -36,58 +34,53 @@ private static ServiceAction PrepareForConnection()
{
var action = new ServiceAction
{
- Name = "PrepareForConnection"
+ Name = "PrepareForConnection",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "RemoteProtocolInfo",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_ProtocolInfo"
+ },
+ new Argument
+ {
+ Name = "PeerConnectionManager",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_ConnectionManager"
+ },
+ new Argument
+ {
+ Name = "PeerConnectionID",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_ConnectionID"
+ },
+ new Argument
+ {
+ Name = "Direction",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_Direction"
+ },
+ new Argument
+ {
+ Name = "ConnectionID",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_ConnectionID"
+ },
+ new Argument
+ {
+ Name = "AVTransportID",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_AVTransportID"
+ },
+ new Argument
+ {
+ Name = "RcsID",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_RcsID"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "RemoteProtocolInfo",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_ProtocolInfo"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "PeerConnectionManager",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_ConnectionManager"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "PeerConnectionID",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_ConnectionID"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "Direction",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_Direction"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "ConnectionID",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_ConnectionID"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "AVTransportID",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_AVTransportID"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "RcsID",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_RcsID"
- });
-
return action;
}
@@ -99,65 +92,59 @@ private static ServiceAction GetCurrentConnectionInfo()
{
var action = new ServiceAction
{
- Name = "GetCurrentConnectionInfo"
+ Name = "GetCurrentConnectionInfo",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "ConnectionID",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_ConnectionID"
+ },
+ new Argument
+ {
+ Name = "RcsID",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_RcsID"
+ },
+ new Argument
+ {
+ Name = "AVTransportID",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_AVTransportID"
+ },
+ new Argument
+ {
+ Name = "ProtocolInfo",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_ProtocolInfo"
+ },
+ new Argument
+ {
+ Name = "PeerConnectionManager",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_ConnectionManager"
+ },
+ new Argument
+ {
+ Name = "PeerConnectionID",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_ConnectionID"
+ },
+ new Argument
+ {
+ Name = "Direction",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_Direction"
+ },
+ new Argument
+ {
+ Name = "Status",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_ConnectionStatus"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "ConnectionID",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_ConnectionID"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "RcsID",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_RcsID"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "AVTransportID",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_AVTransportID"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "ProtocolInfo",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_ProtocolInfo"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "PeerConnectionManager",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_ConnectionManager"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "PeerConnectionID",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_ConnectionID"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "Direction",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_Direction"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "Status",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_ConnectionStatus"
- });
-
return action;
}
@@ -169,23 +156,23 @@ private static ServiceAction GetProtocolInfo()
{
var action = new ServiceAction
{
- Name = "GetProtocolInfo"
+ Name = "GetProtocolInfo",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "Source",
+ Direction = "out",
+ RelatedStateVariable = "SourceProtocolInfo"
+ },
+ new Argument
+ {
+ Name = "Sink",
+ Direction = "out",
+ RelatedStateVariable = "SinkProtocolInfo"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "Source",
- Direction = "out",
- RelatedStateVariable = "SourceProtocolInfo"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "Sink",
- Direction = "out",
- RelatedStateVariable = "SinkProtocolInfo"
- });
-
return action;
}
@@ -197,16 +184,17 @@ private static ServiceAction GetCurrentConnectionIDs()
{
var action = new ServiceAction
{
- Name = "GetCurrentConnectionIDs"
+ Name = "GetCurrentConnectionIDs",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "ConnectionIDs",
+ Direction = "out",
+ RelatedStateVariable = "CurrentConnectionIDs"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "ConnectionIDs",
- Direction = "out",
- RelatedStateVariable = "CurrentConnectionIDs"
- });
-
return action;
}
@@ -218,16 +206,17 @@ private static ServiceAction ConnectionComplete()
{
var action = new ServiceAction
{
- Name = "ConnectionComplete"
+ Name = "ConnectionComplete",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "ConnectionID",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_ConnectionID"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "ConnectionID",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_ConnectionID"
- });
-
return action;
}
}
diff --git a/src/Jellyfin.Plugin.Dlna/ContentDirectory/ContentDirectoryService.cs b/src/Jellyfin.Plugin.Dlna/ContentDirectory/ContentDirectoryService.cs
index 0ee0b95..ef7d7bb 100644
--- a/src/Jellyfin.Plugin.Dlna/ContentDirectory/ContentDirectoryService.cs
+++ b/src/Jellyfin.Plugin.Dlna/ContentDirectory/ContentDirectoryService.cs
@@ -1,11 +1,10 @@
-#pragma warning disable CS1591
-
using System;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Enums;
+using Jellyfin.Extensions;
using Jellyfin.Plugin.Dlna.Model;
using Jellyfin.Plugin.Dlna.Service;
using MediaBrowser.Controller.Drawing;
diff --git a/src/Jellyfin.Plugin.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs b/src/Jellyfin.Plugin.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs
index e82711d..17e1c23 100644
--- a/src/Jellyfin.Plugin.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs
+++ b/src/Jellyfin.Plugin.Dlna/ContentDirectory/ContentDirectoryXmlBuilder.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System.Collections.Generic;
using Jellyfin.Plugin.Dlna.Common;
using Jellyfin.Plugin.Dlna.Service;
@@ -18,7 +16,7 @@ public static class ContentDirectoryXmlBuilder
/// An XML description of this service.
public static string GetXml()
{
- return new ServiceXmlBuilder().GetXml(ServiceActionListBuilder.GetActions(), GetStateVariables());
+ return ServiceXmlBuilder.GetXml(ServiceActionListBuilder.GetActions(), GetStateVariables());
}
///
@@ -27,8 +25,8 @@ public static string GetXml()
/// The .
private static IEnumerable GetStateVariables()
{
- return new StateVariable[]
- {
+ return
+ [
new StateVariable
{
Name = "A_ARG_TYPE_Filter",
@@ -112,11 +110,11 @@ private static IEnumerable GetStateVariables()
DataType = "string",
SendsEvents = false,
- AllowedValues = new[]
- {
+ AllowedValues =
+ [
"BrowseMetadata",
"BrowseDirectChildren"
- }
+ ]
},
new StateVariable
@@ -153,6 +151,6 @@ private static IEnumerable GetStateVariables()
DataType = "string",
SendsEvents = false
}
- };
+ ];
}
}
diff --git a/src/Jellyfin.Plugin.Dlna/ContentDirectory/ControlHandler.cs b/src/Jellyfin.Plugin.Dlna/ContentDirectory/ControlHandler.cs
index 53eddfa..5b2cb1e 100644
--- a/src/Jellyfin.Plugin.Dlna/ContentDirectory/ControlHandler.cs
+++ b/src/Jellyfin.Plugin.Dlna/ContentDirectory/ControlHandler.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -43,7 +41,7 @@ public class ControlHandler : BaseControlHandler
private readonly ILibraryManager _libraryManager;
private readonly IUserDataManager _userDataManager;
- private readonly User _user;
+ private readonly User? _user;
private readonly IUserViewManager _userViewManager;
private readonly ITVSeriesManager _tvSeriesManager;
@@ -56,29 +54,29 @@ public class ControlHandler : BaseControlHandler
///
/// Initializes a new instance of the class.
///
- /// The for use with the instance.
- /// The for use with the instance.
- /// The for use with the instance.
- /// The server address to use in this instance> for use with the instance.
- /// The for use with the instance.
- /// The for use with the instance.
- /// The for use with the instance.
- /// The for use with the instance.
- /// The system id for use with the instance.
- /// The for use with the instance.
- /// The for use with the instance.
- /// The for use with the instance.
- /// The for use with the instance.
- /// The for use with the instance.
+ /// The .
+ /// Instance of the interface.
+ /// The .
+ /// The server address.
+ /// The access token.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// The .
+ /// The system id.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
public ControlHandler(
ILogger logger,
ILibraryManager libraryManager,
DlnaDeviceProfile profile,
string serverAddress,
- string accessToken,
+ string? accessToken,
IImageProcessor imageProcessor,
IUserDataManager userDataManager,
- User user,
+ User? user,
int systemUpdateId,
ILocalizationManager localization,
IMediaSourceManager mediaSourceManager,
@@ -186,6 +184,11 @@ protected override void WriteResult(string methodName, IReadOnlyDictionaryThe method parameters.
private void HandleXSetBookmark(IReadOnlyDictionary sparams)
{
+ if (_user is null)
+ {
+ return;
+ }
+
var id = sparams["ObjectID"];
var serverItem = GetItemFromObjectId(id);
@@ -487,25 +490,25 @@ private void HandleSearch(XmlWriter xmlWriter, IReadOnlyDictionaryThe start index.
/// The maximum number to return.
/// The .
- private static QueryResult GetChildrenSorted(BaseItem item, User user, SearchCriteria search, SortCriteria sort, int? startIndex, int? limit)
+ private static QueryResult GetChildrenSorted(BaseItem item, User? user, SearchCriteria search, SortCriteria sort, int? startIndex, int? limit)
{
var folder = (Folder)item;
- MediaType[] mediaTypes = Array.Empty();
+ MediaType[] mediaTypes = [];
bool? isFolder = null;
switch (search.SearchType)
{
case SearchType.Audio:
- mediaTypes = new[] { MediaType.Audio };
+ mediaTypes = [MediaType.Audio];
isFolder = false;
break;
case SearchType.Video:
- mediaTypes = new[] { MediaType.Video };
+ mediaTypes = [MediaType.Video];
isFolder = false;
break;
case SearchType.Image:
- mediaTypes = new[] { MediaType.Photo };
+ mediaTypes = [MediaType.Photo];
isFolder = false;
break;
case SearchType.Playlist:
@@ -522,7 +525,7 @@ private static QueryResult GetChildrenSorted(BaseItem item, User user,
User = user,
Recursive = true,
IsMissing = false,
- ExcludeItemTypes = new[] { BaseItemKind.Book },
+ ExcludeItemTypes = [BaseItemKind.Book],
IsFolder = isFolder,
MediaTypes = mediaTypes,
DtoOptions = GetDtoOptions()
@@ -548,32 +551,35 @@ private static DtoOptions GetDtoOptions()
/// The start index.
/// The maximum number to return.
/// The .
- private QueryResult GetUserItems(BaseItem item, StubType? stubType, User user, SortCriteria sort, int? startIndex, int? limit)
+ private QueryResult GetUserItems(BaseItem item, StubType? stubType, User? user, SortCriteria sort, int? startIndex, int? limit)
{
- switch (item)
+ if (user is not null)
{
- case MusicGenre:
- return GetMusicGenreItems(item, user, sort, startIndex, limit);
- case MusicArtist:
- return GetMusicArtistItems(item, user, sort, startIndex, limit);
- case Genre:
- return GetGenreItems(item, user, sort, startIndex, limit);
- }
+ switch (item)
+ {
+ case MusicGenre:
+ return GetMusicGenreItems(item, user, sort, startIndex, limit);
+ case MusicArtist:
+ return GetMusicArtistItems(item, user, sort, startIndex, limit);
+ case Genre:
+ return GetGenreItems(item, user, sort, startIndex, limit);
+ }
- if (stubType != StubType.Folder && item is IHasCollectionType collectionFolder)
- {
- switch (collectionFolder.CollectionType)
+ if (stubType != StubType.Folder && item is IHasCollectionType collectionFolder)
{
- case CollectionType.music:
- return GetMusicFolders(item, user, stubType, sort, startIndex, limit);
- case CollectionType.movies:
- return GetMovieFolders(item, user, stubType, sort, startIndex, limit);
- case CollectionType.tvshows:
- return GetTvFolders(item, user, stubType, sort, startIndex, limit);
- case CollectionType.folders:
- return GetFolders(user, startIndex, limit);
- case CollectionType.livetv:
- return GetLiveTvChannels(user, sort, startIndex, limit);
+ switch (collectionFolder.CollectionType)
+ {
+ case CollectionType.music:
+ return GetMusicFolders(item, user, stubType, sort, startIndex, limit);
+ case CollectionType.movies:
+ return GetMovieFolders(item, user, stubType, sort, startIndex, limit);
+ case CollectionType.tvshows:
+ return GetTvFolders(item, user, stubType, sort, startIndex, limit);
+ case CollectionType.folders:
+ return GetFolders(user, startIndex, limit);
+ case CollectionType.livetv:
+ return GetLiveTvChannels(user, sort, startIndex, limit);
+ }
}
}
@@ -590,7 +596,7 @@ private QueryResult GetUserItems(BaseItem item, StubType? stubType,
Limit = limit,
StartIndex = startIndex,
IsVirtualItem = false,
- ExcludeItemTypes = new[] { BaseItemKind.Book },
+ ExcludeItemTypes = [BaseItemKind.Book],
IsPlaceHolder = false,
DtoOptions = GetDtoOptions(),
OrderBy = GetOrderBy(sort, folder.IsPreSorted)
@@ -615,7 +621,7 @@ private QueryResult GetLiveTvChannels(User user, SortCriteria sort,
{
StartIndex = startIndex,
Limit = limit,
- IncludeItemTypes = new[] { BaseItemKind.LiveTvChannel },
+ IncludeItemTypes = [BaseItemKind.LiveTvChannel],
OrderBy = GetOrderBy(sort, false)
};
@@ -831,11 +837,11 @@ private QueryResult GetMovieContinueWatching(BaseItem parent, Intern
query.Recursive = true;
query.Parent = parent;
- query.OrderBy = new[]
- {
+ query.OrderBy =
+ [
(ItemSortBy.DatePlayed, SortOrder.Descending),
(ItemSortBy.SortName, SortOrder.Ascending)
- };
+ ];
query.IsResumable = true;
query.Limit ??= 10;
@@ -853,7 +859,7 @@ private QueryResult GetMovieContinueWatching(BaseItem parent, Intern
private QueryResult GetMovieCollections(InternalItemsQuery query)
{
query.Recursive = true;
- query.IncludeItemTypes = new[] { BaseItemKind.BoxSet };
+ query.IncludeItemTypes = [BaseItemKind.BoxSet];
var result = _libraryManager.GetItemsResult(query);
@@ -873,7 +879,7 @@ private QueryResult GetChildrenOfItem(BaseItem parent, InternalItems
query.Recursive = true;
query.Parent = parent;
query.IsFavorite = isFavorite;
- query.IncludeItemTypes = new[] { itemType };
+ query.IncludeItemTypes = [itemType];
var result = _libraryManager.GetItemsResult(query);
@@ -891,7 +897,7 @@ private QueryResult GetGenres(BaseItem parent, InternalItemsQuery qu
{
// Don't sort
query.OrderBy = Array.Empty<(ItemSortBy, SortOrder)>();
- query.AncestorIds = new[] { parent.Id };
+ query.AncestorIds = [parent.Id];
var genresResult = _libraryManager.GetGenres(query);
return ToResult(query.StartIndex, genresResult);
@@ -907,7 +913,7 @@ private QueryResult GetMusicGenres(BaseItem parent, InternalItemsQue
{
// Don't sort
query.OrderBy = Array.Empty<(ItemSortBy, SortOrder)>();
- query.AncestorIds = new[] { parent.Id };
+ query.AncestorIds = [parent.Id];
var genresResult = _libraryManager.GetMusicGenres(query);
return ToResult(query.StartIndex, genresResult);
@@ -923,7 +929,7 @@ private QueryResult GetMusicAlbumArtists(BaseItem parent, InternalIt
{
// Don't sort
query.OrderBy = Array.Empty<(ItemSortBy, SortOrder)>();
- query.AncestorIds = new[] { parent.Id };
+ query.AncestorIds = [parent.Id];
var artists = _libraryManager.GetAlbumArtists(query);
return ToResult(query.StartIndex, artists);
@@ -939,7 +945,7 @@ private QueryResult GetMusicArtists(BaseItem parent, InternalItemsQu
{
// Don't sort
query.OrderBy = Array.Empty<(ItemSortBy, SortOrder)>();
- query.AncestorIds = new[] { parent.Id };
+ query.AncestorIds = [parent.Id];
var artists = _libraryManager.GetArtists(query);
return ToResult(query.StartIndex, artists);
}
@@ -954,7 +960,7 @@ private QueryResult GetFavoriteArtists(BaseItem parent, InternalItem
{
// Don't sort
query.OrderBy = Array.Empty<(ItemSortBy, SortOrder)>();
- query.AncestorIds = new[] { parent.Id };
+ query.AncestorIds = [parent.Id];
query.IsFavorite = true;
var artists = _libraryManager.GetArtists(query);
return ToResult(query.StartIndex, artists);
@@ -968,7 +974,7 @@ private QueryResult GetFavoriteArtists(BaseItem parent, InternalItem
private QueryResult GetMusicPlaylists(InternalItemsQuery query)
{
query.Parent = null;
- query.IncludeItemTypes = new[] { BaseItemKind.Playlist };
+ query.IncludeItemTypes = [BaseItemKind.Playlist];
query.Recursive = true;
var result = _libraryManager.GetItemsResult(query);
@@ -994,7 +1000,7 @@ private QueryResult GetNextUp(BaseItem parent, InternalItemsQuery qu
// User cannot be null here as the caller has set it
User = query.User!
},
- new[] { parent },
+ [parent],
query.DtoOptions);
return ToResult(query.StartIndex, result);
@@ -1028,15 +1034,15 @@ private QueryResult GetLatest(BaseItem parent, InternalItemsQuery qu
// User cannot be null here as the caller has set it
User = query.User!,
Limit = limit,
- IncludeItemTypes = new[] { itemType },
+ IncludeItemTypes = [itemType],
ParentId = parent?.Id ?? Guid.Empty,
GroupItems = true
},
- query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).Where(i => i is not null).ToArray();
+ query.DtoOptions).Select(i => i.Item1 ?? i.Item2.FirstOrDefault()).OfType().ToArray();
if (query.StartIndex > 0)
{
- items = (items.Length <= query.StartIndex) ? Array.Empty() : items[query.StartIndex.Value..];
+ items = (items.Length <= query.StartIndex) ? [] : items[query.StartIndex.Value..];
}
return ToResult(query.StartIndex, items);
@@ -1056,8 +1062,8 @@ private QueryResult GetMusicArtistItems(BaseItem item, User user, So
var query = new InternalItemsQuery(user)
{
Recursive = true,
- ArtistIds = new[] { item.Id },
- IncludeItemTypes = new[] { BaseItemKind.MusicAlbum },
+ ArtistIds = [item.Id],
+ IncludeItemTypes = [BaseItemKind.MusicAlbum],
Limit = limit,
StartIndex = startIndex,
DtoOptions = GetDtoOptions(),
@@ -1083,12 +1089,12 @@ private QueryResult GetGenreItems(BaseItem item, User user, SortCrit
var query = new InternalItemsQuery(user)
{
Recursive = true,
- GenreIds = new[] { item.Id },
- IncludeItemTypes = new[]
- {
+ GenreIds = [item.Id],
+ IncludeItemTypes =
+ [
BaseItemKind.Movie,
BaseItemKind.Series
- },
+ ],
Limit = limit,
StartIndex = startIndex,
DtoOptions = GetDtoOptions(),
@@ -1114,8 +1120,8 @@ private QueryResult GetMusicGenreItems(BaseItem item, User user, Sor
var query = new InternalItemsQuery(user)
{
Recursive = true,
- GenreIds = new[] { item.Id },
- IncludeItemTypes = new[] { BaseItemKind.MusicAlbum },
+ GenreIds = [item.Id],
+ IncludeItemTypes = [BaseItemKind.MusicAlbum],
Limit = limit,
StartIndex = startIndex,
DtoOptions = GetDtoOptions(),
@@ -1133,16 +1139,16 @@ private QueryResult GetMusicGenreItems(BaseItem item, User user, Sor
/// The start index.
/// An array of .
/// A .
- private static QueryResult ToResult(int? startIndex, IReadOnlyCollection result)
+ private static QueryResult ToResult(int? startIndex, IReadOnlyCollection? result)
{
- var serverItems = result
+ var serverItems = result?
.Select(i => new ServerItem(i, null))
.ToArray();
return new QueryResult(
startIndex,
- result.Count,
- serverItems);
+ result?.Count ?? 0,
+ serverItems ?? []);
}
///
@@ -1194,7 +1200,7 @@ private static QueryResult ToResult(int? startIndex, QueryResult<(Ba
/// True if pre-sorted.
private static (ItemSortBy SortName, SortOrder SortOrder)[] GetOrderBy(SortCriteria sort, bool isPreSorted)
{
- return isPreSorted ? Array.Empty<(ItemSortBy, SortOrder)>() : new[] { (ItemSortBy.SortName, sort.SortOrder) };
+ return isPreSorted ? Array.Empty<(ItemSortBy, SortOrder)>() : [(ItemSortBy.SortName, sort.SortOrder)];
}
///
@@ -1239,8 +1245,10 @@ private ServerItem ParseItemId(string id)
if (Guid.TryParse(id, out var itemId))
{
var item = _libraryManager.GetItemById(itemId);
-
- return new ServerItem(item, stubType);
+ if (item is not null)
+ {
+ return new ServerItem(item, stubType);
+ }
}
Logger.LogError("Error parsing item Id: {Id}. Returning user root folder.", id);
@@ -1259,7 +1267,7 @@ private static ServerItem[] GetTrimmedServerItemsArray(ServerItem[] serverItems,
{
if (startIndex >= serverItems.Length)
{
- return Array.Empty();
+ return [];
}
if (startIndex > 0)
diff --git a/src/Jellyfin.Plugin.Dlna/ContentDirectory/ServerItem.cs b/src/Jellyfin.Plugin.Dlna/ContentDirectory/ServerItem.cs
index 10253d6..5eefe57 100644
--- a/src/Jellyfin.Plugin.Dlna/ContentDirectory/ServerItem.cs
+++ b/src/Jellyfin.Plugin.Dlna/ContentDirectory/ServerItem.cs
@@ -5,7 +5,7 @@ namespace Jellyfin.Plugin.Dlna.ContentDirectory;
///
/// Defines the .
///
-internal class ServerItem
+internal sealed class ServerItem
{
///
/// Initializes a new instance of the class.
diff --git a/src/Jellyfin.Plugin.Dlna/ContentDirectory/ServiceActionListBuilder.cs b/src/Jellyfin.Plugin.Dlna/ContentDirectory/ServiceActionListBuilder.cs
index f5fe977..9551454 100644
--- a/src/Jellyfin.Plugin.Dlna/ContentDirectory/ServiceActionListBuilder.cs
+++ b/src/Jellyfin.Plugin.Dlna/ContentDirectory/ServiceActionListBuilder.cs
@@ -14,8 +14,8 @@ public static class ServiceActionListBuilder
/// An .
public static IEnumerable GetActions()
{
- return new[]
- {
+ return
+ [
GetSearchCapabilitiesAction(),
GetSortCapabilitiesAction(),
GetGetSystemUpdateIDAction(),
@@ -24,7 +24,7 @@ public static IEnumerable GetActions()
GetX_GetFeatureListAction(),
GetXSetBookmarkAction(),
GetBrowseByLetterAction()
- };
+ ];
}
///
@@ -35,16 +35,17 @@ private static ServiceAction GetGetSystemUpdateIDAction()
{
var action = new ServiceAction
{
- Name = "GetSystemUpdateID"
+ Name = "GetSystemUpdateID",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "Id",
+ Direction = "out",
+ RelatedStateVariable = "SystemUpdateID"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "Id",
- Direction = "out",
- RelatedStateVariable = "SystemUpdateID"
- });
-
return action;
}
@@ -56,16 +57,17 @@ private static ServiceAction GetSearchCapabilitiesAction()
{
var action = new ServiceAction
{
- Name = "GetSearchCapabilities"
+ Name = "GetSearchCapabilities",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "SearchCaps",
+ Direction = "out",
+ RelatedStateVariable = "SearchCapabilities"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "SearchCaps",
- Direction = "out",
- RelatedStateVariable = "SearchCapabilities"
- });
-
return action;
}
@@ -77,16 +79,17 @@ private static ServiceAction GetSortCapabilitiesAction()
{
var action = new ServiceAction
{
- Name = "GetSortCapabilities"
+ Name = "GetSortCapabilities",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "SortCaps",
+ Direction = "out",
+ RelatedStateVariable = "SortCapabilities"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "SortCaps",
- Direction = "out",
- RelatedStateVariable = "SortCapabilities"
- });
-
return action;
}
@@ -98,16 +101,17 @@ private static ServiceAction GetX_GetFeatureListAction()
{
var action = new ServiceAction
{
- Name = "X_GetFeatureList"
+ Name = "X_GetFeatureList",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "FeatureList",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_Featurelist"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "FeatureList",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_Featurelist"
- });
-
return action;
}
@@ -119,79 +123,71 @@ private static ServiceAction GetSearchAction()
{
var action = new ServiceAction
{
- Name = "Search"
+ Name = "Search",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "ContainerID",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_ObjectID"
+ },
+ new Argument
+ {
+ Name = "SearchCriteria",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_SearchCriteria"
+ },
+ new Argument
+ {
+ Name = "Filter",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_Filter"
+ },
+ new Argument
+ {
+ Name = "StartingIndex",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_Index"
+ },
+ new Argument
+ {
+ Name = "RequestedCount",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_Count"
+ },
+ new Argument
+ {
+ Name = "SortCriteria",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_SortCriteria"
+ },
+ new Argument
+ {
+ Name = "Result",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_Result"
+ },
+ new Argument
+ {
+ Name = "NumberReturned",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_Count"
+ },
+ new Argument
+ {
+ Name = "TotalMatches",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_Count"
+ },
+ new Argument
+ {
+ Name = "UpdateID",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_UpdateID"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "ContainerID",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_ObjectID"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "SearchCriteria",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_SearchCriteria"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "Filter",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_Filter"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "StartingIndex",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_Index"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "RequestedCount",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_Count"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "SortCriteria",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_SortCriteria"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "Result",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_Result"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "NumberReturned",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_Count"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "TotalMatches",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_Count"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "UpdateID",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_UpdateID"
- });
-
return action;
}
@@ -203,79 +199,71 @@ private static ServiceAction GetBrowseAction()
{
var action = new ServiceAction
{
- Name = "Browse"
+ Name = "Browse",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "ObjectID",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_ObjectID"
+ },
+ new Argument
+ {
+ Name = "BrowseFlag",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_BrowseFlag"
+ },
+ new Argument
+ {
+ Name = "Filter",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_Filter"
+ },
+ new Argument
+ {
+ Name = "StartingIndex",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_Index"
+ },
+ new Argument
+ {
+ Name = "RequestedCount",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_Count"
+ },
+ new Argument
+ {
+ Name = "SortCriteria",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_SortCriteria"
+ },
+ new Argument
+ {
+ Name = "Result",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_Result"
+ },
+ new Argument
+ {
+ Name = "NumberReturned",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_Count"
+ },
+ new Argument
+ {
+ Name = "TotalMatches",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_Count"
+ },
+ new Argument
+ {
+ Name = "UpdateID",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_UpdateID"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "ObjectID",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_ObjectID"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "BrowseFlag",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_BrowseFlag"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "Filter",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_Filter"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "StartingIndex",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_Index"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "RequestedCount",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_Count"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "SortCriteria",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_SortCriteria"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "Result",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_Result"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "NumberReturned",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_Count"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "TotalMatches",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_Count"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "UpdateID",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_UpdateID"
- });
-
return action;
}
@@ -287,86 +275,77 @@ private static ServiceAction GetBrowseByLetterAction()
{
var action = new ServiceAction
{
- Name = "X_BrowseByLetter"
+ Name = "X_BrowseByLetter",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "ObjectID",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_ObjectID"
+ },
+ new Argument
+ {
+ Name = "BrowseFlag",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_BrowseFlag"
+ },
+ new Argument
+ {
+ Name = "Filter",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_Filter"
+ },
+ new Argument
+ {
+ Name = "StartingLetter",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_BrowseLetter"
+ },
+ new Argument
+ {
+ Name = "RequestedCount",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_Count"
+ },
+ new Argument
+ {
+ Name = "SortCriteria",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_SortCriteria"
+ },
+ new Argument
+ {
+ Name = "Result",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_Result"
+ },
+ new Argument
+ {
+ Name = "NumberReturned",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_Count"
+ },
+ new Argument
+ {
+ Name = "TotalMatches",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_Count"
+ },
+ new Argument
+ {
+ Name = "UpdateID",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_UpdateID"
+ },
+ new Argument
+ {
+ Name = "StartingIndex",
+ Direction = "out",
+ RelatedStateVariable = "A_ARG_TYPE_Index"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "ObjectID",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_ObjectID"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "BrowseFlag",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_BrowseFlag"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "Filter",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_Filter"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "StartingLetter",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_BrowseLetter"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "RequestedCount",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_Count"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "SortCriteria",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_SortCriteria"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "Result",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_Result"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "NumberReturned",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_Count"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "TotalMatches",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_Count"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "UpdateID",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_UpdateID"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "StartingIndex",
- Direction = "out",
- RelatedStateVariable = "A_ARG_TYPE_Index"
- });
-
return action;
}
@@ -378,37 +357,35 @@ private static ServiceAction GetXSetBookmarkAction()
{
var action = new ServiceAction
{
- Name = "X_SetBookmark"
+ Name = "X_SetBookmark",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "CategoryType",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_CategoryType"
+ },
+ new Argument
+ {
+ Name = "RID",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_RID"
+ },
+ new Argument
+ {
+ Name = "ObjectID",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_ObjectID"
+ },
+ new Argument
+ {
+ Name = "PosSecond",
+ Direction = "in",
+ RelatedStateVariable = "A_ARG_TYPE_PosSec"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "CategoryType",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_CategoryType"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "RID",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_RID"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "ObjectID",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_ObjectID"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "PosSecond",
- Direction = "in",
- RelatedStateVariable = "A_ARG_TYPE_PosSec"
- });
-
return action;
}
}
diff --git a/src/Jellyfin.Plugin.Dlna/ContentDirectory/StubType.cs b/src/Jellyfin.Plugin.Dlna/ContentDirectory/StubType.cs
index b1964d8..edc20d6 100644
--- a/src/Jellyfin.Plugin.Dlna/ContentDirectory/StubType.cs
+++ b/src/Jellyfin.Plugin.Dlna/ContentDirectory/StubType.cs
@@ -1,29 +1,102 @@
-#pragma warning disable CS1591
-
namespace Jellyfin.Plugin.Dlna.ContentDirectory;
///
-/// Defines the DLNA item types.
+/// DLNA item types.
///
public enum StubType
{
+ ///
+ /// Folder stub.
+ ///
Folder = 0,
+
+ ///
+ /// Latest stub.
+ ///
Latest = 2,
+
+ ///
+ /// Playlists stub.
+ ///
Playlists = 3,
+
+ ///
+ /// Albums stub.
+ ///
Albums = 4,
+
+ ///
+ /// AlbumArtists stub.
+ ///
AlbumArtists = 5,
+
+ ///
+ /// Artists stub.
+ ///
Artists = 6,
+
+ ///
+ /// Songs stub.
+ ///
Songs = 7,
+
+ ///
+ /// Genres stub.
+ ///
Genres = 8,
+
+ ///
+ /// FavoriteSongs stub.
+ ///
FavoriteSongs = 9,
+
+ ///
+ /// FavoriteArtists stub.
+ ///
FavoriteArtists = 10,
+
+ ///
+ /// FavoriteAlbums stub.
+ ///
FavoriteAlbums = 11,
+
+ ///
+ /// ContinueWatching stub.
+ ///
ContinueWatching = 12,
+
+ ///
+ /// Movies stub.
+ ///
Movies = 13,
+
+ ///
+ /// Collections stub.
+ ///
Collections = 14,
+
+ ///
+ /// Favorites stub.
+ ///
Favorites = 15,
+
+ ///
+ /// NextUp stub.
+ ///
NextUp = 16,
+
+ ///
+ /// Series stub.
+ ///
Series = 17,
+
+ ///
+ /// FavoriteSeries stub.
+ ///
FavoriteSeries = 18,
+
+ ///
+ /// FavoriteEpisodes stub.
+ ///
FavoriteEpisodes = 19
}
diff --git a/src/Jellyfin.Plugin.Dlna/ControlRequest.cs b/src/Jellyfin.Plugin.Dlna/ControlRequest.cs
index 5739c26..847a247 100644
--- a/src/Jellyfin.Plugin.Dlna/ControlRequest.cs
+++ b/src/Jellyfin.Plugin.Dlna/ControlRequest.cs
@@ -1,24 +1,41 @@
#nullable disable
-#pragma warning disable CS1591
-
using System.IO;
using Microsoft.AspNetCore.Http;
namespace Jellyfin.Plugin.Dlna;
+///
+/// Defines the .
+///
public class ControlRequest
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Instance of the interface.
public ControlRequest(IHeaderDictionary headers)
{
Headers = headers;
}
+ ///
+ /// Gets the instance.
+ ///
public IHeaderDictionary Headers { get; }
+ ///
+ /// Gets or sets the .
+ ///
public Stream InputXml { get; set; }
+ ///
+ /// Gets or sets the target server UUID.
+ ///
public string TargetServerUuId { get; set; }
+ ///
+ /// Gets or sets the request URL.
+ ///
public string RequestedUrl { get; set; }
}
diff --git a/src/Jellyfin.Plugin.Dlna/ControlResponse.cs b/src/Jellyfin.Plugin.Dlna/ControlResponse.cs
index 41d8d14..4650425 100644
--- a/src/Jellyfin.Plugin.Dlna/ControlResponse.cs
+++ b/src/Jellyfin.Plugin.Dlna/ControlResponse.cs
@@ -1,11 +1,17 @@
-#pragma warning disable CS1591
-
using System.Collections.Generic;
namespace Jellyfin.Plugin.Dlna;
+///
+/// Defines the .
+///
public class ControlResponse
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The XML.
+ /// A value indicating wether the triggering action is successful or not.
public ControlResponse(string xml, bool isSuccessful)
{
Headers = new Dictionary();
@@ -13,10 +19,19 @@ public ControlResponse(string xml, bool isSuccessful)
IsSuccessful = isSuccessful;
}
+ ///
+ /// Gets the headers dictionary.
+ ///
public IDictionary Headers { get; }
+ ///
+ /// Gets or sets the XML.
+ ///
public string Xml { get; set; }
+ ///
+ /// Gets or sets a value indicating whether the triggering action is successful.
+ ///
public bool IsSuccessful { get; set; }
///
diff --git a/src/Jellyfin.Plugin.Dlna/Didl/DidlBuilder.cs b/src/Jellyfin.Plugin.Dlna/Didl/DidlBuilder.cs
index 0d33267..1ef685d 100644
--- a/src/Jellyfin.Plugin.Dlna/Didl/DidlBuilder.cs
+++ b/src/Jellyfin.Plugin.Dlna/Didl/DidlBuilder.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System;
using System.Globalization;
using System.IO;
@@ -24,7 +22,6 @@
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Net;
using Microsoft.Extensions.Logging;
-using DeviceProfile = MediaBrowser.Model.Dlna.DeviceProfile;
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
using Genre = MediaBrowser.Controller.Entities.Genre;
using MediaOptions = MediaBrowser.Model.Dlna.MediaOptions;
@@ -40,6 +37,9 @@
namespace Jellyfin.Plugin.Dlna.Didl;
+///
+/// Defines the .
+///
public class DidlBuilder
{
private const string NsDidl = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
@@ -59,6 +59,20 @@ public class DidlBuilder
private readonly IMediaEncoder _mediaEncoder;
private readonly ILibraryManager _libraryManager;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The .
+ /// The .
+ /// Instance of the interface.
+ /// The server address.
+ /// The access token.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
public DidlBuilder(
DlnaDeviceProfile profile,
User? user,
@@ -85,11 +99,24 @@ public DidlBuilder(
_libraryManager = libraryManager;
}
+ ///
+ /// Gets the normalized DLNA media URL.
+ /// The URL to normalize.
+ ///
public static string NormalizeDlnaMediaUrl(string url)
{
return url + "&dlnaheaders=true";
}
+ ///
+ /// Gets the item DIDL.
+ /// The .
+ /// The .
+ /// The context.
+ /// The device id.
+ /// The .
+ /// The .
+ ///
public string GetItemDidl(BaseItem item, User? user, BaseItem? context, string deviceId, Filter filter, StreamInfo streamInfo)
{
var settings = new XmlWriterSettings
@@ -126,6 +153,11 @@ public string GetItemDidl(BaseItem item, User? user, BaseItem? context, string d
}
}
+ ///
+ /// Writes XML attributes of a profile the item DIDL.
+ /// The .
+ /// The .
+ ///
public static void WriteXmlRootAttributes(DlnaDeviceProfile profile, XmlWriter writer)
{
foreach (var att in profile.XmlRootAttributes)
@@ -142,6 +174,17 @@ public static void WriteXmlRootAttributes(DlnaDeviceProfile profile, XmlWriter w
}
}
+ ///
+ /// Writes an XML item element.
+ /// The .
+ /// The .
+ /// The .
+ /// The context.
+ /// The of the context.
+ /// The device id.
+ /// The .
+ /// The .
+ ///
public void WriteItemElement(
XmlWriter writer,
BaseItem item,
@@ -218,8 +261,8 @@ private void AddVideoResource(XmlWriter writer, BaseItem video, string deviceId,
var contentFeatureList = ContentFeatureBuilder.BuildVideoHeader(
_profile,
streamInfo.Container,
- streamInfo.TargetVideoCodec.FirstOrDefault(),
- streamInfo.TargetAudioCodec.FirstOrDefault(),
+ streamInfo.TargetVideoCodec[0],
+ streamInfo.TargetAudioCodec[0],
targetWidth,
targetHeight,
streamInfo.TargetVideoBitDepth,
@@ -476,13 +519,13 @@ private string GetEpisodeDisplayName(Episode episode, BaseItem? context)
// inside a season use simple format (ex. '12 - Episode Name')
var epNumberName = GetEpisodeIndexFullName(episode);
- components = new[] { epNumberName, episode.Name };
+ components = [epNumberName, episode.Name];
}
else
{
// outside a season include series and season details (ex. 'TV Show - S05E11 - Episode Name')
var epNumberName = GetEpisodeNumberDisplayName(episode);
- components = new[] { episode.SeriesName, epNumberName, episode.Name };
+ components = [episode.SeriesName, epNumberName, episode.Name];
}
return string.Join(" - ", components.Where(NotNullOrWhiteSpace));
@@ -493,7 +536,7 @@ private string GetEpisodeDisplayName(Episode episode, BaseItem? context)
///
/// The episode.
/// For single episodes returns just the number. For double episodes - current and ending numbers.
- private string GetEpisodeIndexFullName(Episode episode)
+ private static string GetEpisodeIndexFullName(Episode episode)
{
var name = string.Empty;
if (episode.IndexNumber.HasValue)
@@ -509,11 +552,6 @@ private string GetEpisodeIndexFullName(Episode episode)
return name;
}
- ///
- /// Gets episode number formatted as 'S##E##'.
- ///
- /// The episode.
- /// Formatted episode number.
private string GetEpisodeNumberDisplayName(Episode episode)
{
var name = string.Empty;
@@ -611,7 +649,7 @@ private void AddAudioResource(XmlWriter writer, BaseItem audio, string deviceId,
var contentFeatures = ContentFeatureBuilder.BuildAudioHeader(
_profile,
- streamInfo.Container,
+ streamInfo.Container?.FirstOrDefault().ToString(),
streamInfo.TargetAudioCodec.FirstOrDefault(),
targetAudioBitrate,
targetSampleRate,
@@ -634,13 +672,28 @@ private void AddAudioResource(XmlWriter writer, BaseItem audio, string deviceId,
writer.WriteFullEndElement();
}
+ ///
+ /// Gets a value indicating whether the id is a root id.
+ ///
+ /// The id.
+ /// true if the id is a root id; otherwise, false.
public static bool IsIdRoot(string id)
=> string.IsNullOrWhiteSpace(id)
|| string.Equals(id, "0", StringComparison.OrdinalIgnoreCase)
// Samsung sometimes uses 1 as root
|| string.Equals(id, "1", StringComparison.OrdinalIgnoreCase);
- public void WriteFolderElement(XmlWriter writer, BaseItem folder, StubType? stubType, BaseItem context, int childCount, Filter filter, string? requestedId = null)
+ ///
+ /// Writes an XML folder element.
+ /// The .
+ /// The .
+ /// The .
+ /// The context.
+ /// The child count.
+ /// The .
+ /// The request id.
+ ///
+ public void WriteFolderElement(XmlWriter writer, BaseItem folder, StubType? stubType, BaseItem? context, int childCount, Filter filter, string? requestedId = null)
{
writer.WriteStartElement(string.Empty, "container", NsDidl);
@@ -720,9 +773,6 @@ private void AddSamsungBookmarkInfo(BaseItem item, User? user, XmlWriter writer,
}
}
- ///
- /// Adds fields used by both items and folders.
- ///
private void AddCommonFields(BaseItem item, StubType? itemStubType, BaseItem? context, XmlWriter writer, Filter filter)
{
// Don't filter on dc:title because not all devices will include it in the filter
@@ -1123,7 +1173,7 @@ private void AddImageResElement(
return null;
}
- private BaseItem? GetFirstParentWithImageBelowUserRoot(BaseItem item)
+ private static BaseItem? GetFirstParentWithImageBelowUserRoot(BaseItem item)
{
if (item is null)
{
@@ -1194,11 +1244,23 @@ private ImageDownloadInfo GetImageInfo(BaseItem item, ImageType type)
};
}
+ ///
+ /// Gets the client id of an based on the .
+ ///
+ /// The .
+ /// Current .
+ /// The client id
public static string GetClientId(BaseItem item, StubType? stubType)
{
return GetClientId(item.Id, stubType);
}
+ ///
+ /// Gets the client id of an based on the .
+ ///
+ /// The .
+ /// Current .
+ /// The client id
public static string GetClientId(Guid idValue, StubType? stubType)
{
var id = idValue.ToString("N", CultureInfo.InvariantCulture);
@@ -1245,13 +1307,13 @@ public static string GetClientId(Guid idValue, StubType? stubType)
}
}
- // just lie
+ // Just lie
info.IsDirectStream = true;
return (url, width, height);
}
- private class ImageDownloadInfo
+ private sealed class ImageDownloadInfo
{
internal Guid ItemId { get; set; }
diff --git a/src/Jellyfin.Plugin.Dlna/Didl/Filter.cs b/src/Jellyfin.Plugin.Dlna/Didl/Filter.cs
index 4f20451..9173dbd 100644
--- a/src/Jellyfin.Plugin.Dlna/Didl/Filter.cs
+++ b/src/Jellyfin.Plugin.Dlna/Didl/Filter.cs
@@ -1,25 +1,37 @@
-#pragma warning disable CS1591
-
using System;
namespace Jellyfin.Plugin.Dlna.Didl;
+///
+/// Defines the .
+///
public class Filter
{
private readonly string[] _fields;
private readonly bool _all;
+ ///
+ /// Initializes a new instance of the class.
+ ///
public Filter()
: this("*")
{
}
-
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Filter.
public Filter(string filter)
{
_all = string.Equals(filter, "*", StringComparison.OrdinalIgnoreCase);
_fields = filter.Split(',', StringSplitOptions.RemoveEmptyEntries);
}
+ ///
+ /// Gets a value indicating whether the filter contains a field.
+ ///
+ /// The field to check.
+ /// true if this filter contains the field; otherwise, false.
public bool Contains(string field)
{
return _all || Array.Exists(_fields, x => x.Equals(field, StringComparison.OrdinalIgnoreCase));
diff --git a/src/Jellyfin.Plugin.Dlna/Didl/StringWriterWithEncoding.cs b/src/Jellyfin.Plugin.Dlna/Didl/StringWriterWithEncoding.cs
index b63b590..abeca40 100644
--- a/src/Jellyfin.Plugin.Dlna/Didl/StringWriterWithEncoding.cs
+++ b/src/Jellyfin.Plugin.Dlna/Didl/StringWriterWithEncoding.cs
@@ -1,57 +1,24 @@
-#pragma warning disable CS1591
-#pragma warning disable CA1305
-
-using System;
using System.IO;
using System.Text;
namespace Jellyfin.Plugin.Dlna.Didl;
+///
+/// Defines the .
+///
public class StringWriterWithEncoding : StringWriter
{
private readonly Encoding? _encoding;
- public StringWriterWithEncoding()
- {
- }
-
- public StringWriterWithEncoding(IFormatProvider formatProvider)
- : base(formatProvider)
- {
- }
-
- public StringWriterWithEncoding(StringBuilder sb)
- : base(sb)
- {
- }
-
- public StringWriterWithEncoding(StringBuilder sb, IFormatProvider formatProvider)
- : base(sb, formatProvider)
- {
- }
-
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The .
public StringWriterWithEncoding(Encoding encoding)
{
_encoding = encoding;
}
- public StringWriterWithEncoding(IFormatProvider formatProvider, Encoding encoding)
- : base(formatProvider)
- {
- _encoding = encoding;
- }
-
- public StringWriterWithEncoding(StringBuilder sb, Encoding encoding)
- : base(sb)
- {
- _encoding = encoding;
- }
-
- public StringWriterWithEncoding(StringBuilder sb, IFormatProvider formatProvider, Encoding encoding)
- : base(sb, formatProvider)
- {
- _encoding = encoding;
- }
-
+ ///
public override Encoding Encoding => _encoding ?? base.Encoding;
}
diff --git a/src/Jellyfin.Plugin.Dlna/DlnaManager.cs b/src/Jellyfin.Plugin.Dlna/DlnaManager.cs
index 82ba152..47d2115 100644
--- a/src/Jellyfin.Plugin.Dlna/DlnaManager.cs
+++ b/src/Jellyfin.Plugin.Dlna/DlnaManager.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -17,9 +15,7 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller;
-using MediaBrowser.Controller.Drawing;
using MediaBrowser.Model.Dlna;
-using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
using Microsoft.AspNetCore.Http;
@@ -29,6 +25,9 @@
namespace Jellyfin.Plugin.Dlna;
+///
+/// Defines the .
+///
public class DlnaManager : IDlnaManager
{
private readonly IApplicationPaths _appPaths;
@@ -42,6 +41,14 @@ public class DlnaManager : IDlnaManager
private readonly Dictionary> _profiles
= new(StringComparer.Ordinal);
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
public DlnaManager(
IXmlSerializer xmlSerializer,
IFileSystem fileSystem,
@@ -58,8 +65,11 @@ public DlnaManager(
private string UserProfilesPath => Path.Combine(_appPaths.PluginConfigurationsPath, "dlna", "user");
- private string SystemProfilesPath => Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "profiles");
+ private static string SystemProfilesPath => Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, "profiles");
+ ///
+ /// Initializes the profiles asynchronously.
+ ///
public async Task InitProfilesAsync()
{
try
@@ -87,6 +97,9 @@ private void LoadProfiles()
.OrderBy(i => i.Name));
}
+ ///
+ /// Gets the profiles.
+ ///
public IEnumerable GetProfiles()
{
lock (_profiles)
@@ -196,7 +209,7 @@ private bool IsMatch(IHeaderDictionary headers, DeviceIdentification profileInfo
return profileInfo.Headers.Any(i => IsMatch(headers, i));
}
- private bool IsMatch(IHeaderDictionary headers, HttpHeaderInfo header)
+ private static bool IsMatch(IHeaderDictionary headers, HttpHeaderInfo header)
{
// Handle invalid user setup
if (string.IsNullOrEmpty(header.Name))
@@ -216,7 +229,7 @@ private bool IsMatch(IHeaderDictionary headers, HttpHeaderInfo header)
case HeaderMatchType.Equals:
return string.Equals(value, header.Value, StringComparison.OrdinalIgnoreCase);
case HeaderMatchType.Substring:
- var isMatch = value.ToString().IndexOf(header.Value, StringComparison.OrdinalIgnoreCase) != -1;
+ var isMatch = value.ToString().Contains(header.Value, StringComparison.OrdinalIgnoreCase);
// _logger.LogDebug("IsMatch-Substring value: {0} testValue: {1} isMatch: {2}", value, header.Value, isMatch);
return isMatch;
case HeaderMatchType.Regex:
@@ -396,7 +409,7 @@ public void UpdateProfile(string profileId, DlnaDeviceProfile profile)
if (profile.Id.IsNullOrEmpty())
{
- throw new ArgumentException("Profile id cannot be empty.", nameof(profile.Id));
+ throw new ArgumentException("Profile id cannot be empty. ProfileId: {Id}", nameof(profile));
}
ArgumentException.ThrowIfNullOrEmpty(profile.Name);
@@ -472,7 +485,7 @@ public string GetServerDescriptionXml(IHeaderDictionary headers, string serverUu
return _assembly.GetManifestResourceStream(resource);
}
- private class InternalProfileInfo
+ private sealed class InternalProfileInfo
{
internal InternalProfileInfo(DeviceProfileInfo info, string path)
{
diff --git a/src/Jellyfin.Plugin.Dlna/DlnaPlugin.cs b/src/Jellyfin.Plugin.Dlna/DlnaPlugin.cs
index 697debd..25622d2 100644
--- a/src/Jellyfin.Plugin.Dlna/DlnaPlugin.cs
+++ b/src/Jellyfin.Plugin.Dlna/DlnaPlugin.cs
@@ -13,8 +13,16 @@ namespace Jellyfin.Plugin.Dlna;
///
public class DlnaPlugin : BasePlugin, IHasWebPages
{
+ ///
+ /// The instance.
+ ///
public static DlnaPlugin Instance { get; private set; } = null!;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Instance of the interface.
+ /// Instance of the interface.
public DlnaPlugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
: base(applicationPaths, xmlSerializer)
{
@@ -29,12 +37,12 @@ public DlnaPlugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializ
///
public override string Description => "Use Jellyfin as a DLNA server.";
-
+
///
public IEnumerable GetPages()
{
- return new[]
- {
+ return
+ [
new PluginPageInfo
{
Name = "dlna",
@@ -46,6 +54,6 @@ public IEnumerable GetPages()
Name = "dlnajs",
EmbeddedResourcePath = GetType().Namespace + ".Configuration.config.js"
},
- };
+ ];
}
-}
\ No newline at end of file
+}
diff --git a/src/Jellyfin.Plugin.Dlna/DlnaServiceRegistrator.cs b/src/Jellyfin.Plugin.Dlna/DlnaServiceRegistrator.cs
index e4fa2d8..05a8cb8 100644
--- a/src/Jellyfin.Plugin.Dlna/DlnaServiceRegistrator.cs
+++ b/src/Jellyfin.Plugin.Dlna/DlnaServiceRegistrator.cs
@@ -19,11 +19,15 @@
namespace Jellyfin.Plugin.Dlna;
+///
+/// Defines the .
+///
public class DlnaServiceRegistrator : IPluginServiceRegistrator
{
- public void RegisterServices(IServiceCollection services, IServerApplicationHost applicationHost)
+ ///
+ public void RegisterServices(IServiceCollection serviceCollection, IServerApplicationHost applicationHost)
{
- services.AddHttpClient(NamedClient.Dlna, c =>
+ serviceCollection.AddHttpClient(NamedClient.Dlna, c =>
{
c.DefaultRequestHeaders.UserAgent.ParseAdd(
string.Format(
@@ -43,22 +47,22 @@ public void RegisterServices(IServiceCollection services, IServerApplicationHost
RequestHeaderEncodingSelector = (_, _) => Encoding.UTF8
});
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
+ serviceCollection.AddSingleton();
+ serviceCollection.AddSingleton();
+ serviceCollection.AddSingleton();
+ serviceCollection.AddSingleton();
+ serviceCollection.AddSingleton();
- services.AddScoped();
- services.AddScoped();
+ serviceCollection.AddScoped();
+ serviceCollection.AddScoped();
- services.AddSingleton(provider => new SsdpCommunicationsServer(
+ serviceCollection.AddSingleton(provider => new SsdpCommunicationsServer(
provider.GetRequiredService(),
provider.GetRequiredService>())
{
IsShared = true
});
- services.AddHostedService();
+ serviceCollection.AddHostedService();
}
-}
\ No newline at end of file
+}
diff --git a/src/Jellyfin.Plugin.Dlna/EventSubscriptionResponse.cs b/src/Jellyfin.Plugin.Dlna/EventSubscriptionResponse.cs
index 601efef..440e67c 100644
--- a/src/Jellyfin.Plugin.Dlna/EventSubscriptionResponse.cs
+++ b/src/Jellyfin.Plugin.Dlna/EventSubscriptionResponse.cs
@@ -1,21 +1,36 @@
-#pragma warning disable CS1591
-
using System.Collections.Generic;
namespace Jellyfin.Plugin.Dlna;
+///
+/// Defines the .
+///
public class EventSubscriptionResponse
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The content.
+ /// The content type.
public EventSubscriptionResponse(string content, string contentType)
{
Content = content;
ContentType = contentType;
- Headers = new Dictionary();
+ Headers = [];
}
+ ///
+ /// Gets or sets the content.
+ ///
public string Content { get; set; }
+ ///
+ /// Gets or sets the content type.
+ ///
public string ContentType { get; set; }
+ ///
+ /// Gets the headers dictionary.
+ ///
public Dictionary Headers { get; }
}
diff --git a/src/Jellyfin.Plugin.Dlna/Eventing/DlnaEventManager.cs b/src/Jellyfin.Plugin.Dlna/Eventing/DlnaEventManager.cs
index f69249f..346ccc0 100644
--- a/src/Jellyfin.Plugin.Dlna/Eventing/DlnaEventManager.cs
+++ b/src/Jellyfin.Plugin.Dlna/Eventing/DlnaEventManager.cs
@@ -1,7 +1,3 @@
-#nullable disable
-
-#pragma warning disable CS1591
-
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -18,24 +14,40 @@
namespace Jellyfin.Plugin.Dlna.Eventing;
+///
+/// Defines the .
+///
public class DlnaEventManager : IDlnaEventManager
{
private readonly ConcurrentDictionary _subscriptions =
- new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
+ new(StringComparer.OrdinalIgnoreCase);
private readonly ILogger _logger;
private readonly IHttpClientFactory _httpClientFactory;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Instance of the interface.
+ /// Instance of the interface.
public DlnaEventManager(ILogger logger, IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
_logger = logger;
}
- public EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string requestedTimeoutString, string callbackUrl)
+ ///
+ /// Renews an event subscription.
+ ///
+ /// The subscription id.
+ /// The notification type.
+ /// The requested timeout string.
+ /// The callback URL.
+ /// EventSubscriptionResponse.
+ public EventSubscriptionResponse RenewEventSubscription(string? subscriptionId, string? notificationType, string? requestedTimeoutString, string? callbackUrl)
{
var subscription = GetSubscription(subscriptionId, false);
- if (subscription is not null)
+ if (subscription is not null && subscriptionId is not null)
{
subscription.TimeoutSeconds = ParseTimeout(requestedTimeoutString) ?? 300;
int timeoutSeconds = subscription.TimeoutSeconds;
@@ -53,7 +65,14 @@ public EventSubscriptionResponse RenewEventSubscription(string subscriptionId, s
return new EventSubscriptionResponse(string.Empty, "text/plain");
}
- public EventSubscriptionResponse CreateEventSubscription(string notificationType, string requestedTimeoutString, string callbackUrl)
+ ///
+ /// Creates an event subscription.
+ ///
+ /// The notification type.
+ /// The requested timeout string.
+ /// The callback URL.
+ /// EventSubscriptionResponse.
+ public EventSubscriptionResponse CreateEventSubscription(string? notificationType, string? requestedTimeoutString, string? callbackUrl)
{
var timeout = ParseTimeout(requestedTimeoutString) ?? 300;
var id = "uuid:" + Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture);
@@ -76,7 +95,7 @@ public EventSubscriptionResponse CreateEventSubscription(string notificationType
return GetEventSubscriptionResponse(id, requestedTimeoutString, timeout);
}
- private int? ParseTimeout(string header)
+ private static int? ParseTimeout(string? header)
{
if (!string.IsNullOrEmpty(header))
{
@@ -90,16 +109,24 @@ public EventSubscriptionResponse CreateEventSubscription(string notificationType
return null;
}
- public EventSubscriptionResponse CancelEventSubscription(string subscriptionId)
+ ///
+ /// Cancels the event subscription of an subscriptionId.
+ ///
+ /// The subscription id.
+ /// EventSubscriptionResponse.
+ public EventSubscriptionResponse CancelEventSubscription(string? subscriptionId)
{
_logger.LogDebug("Cancelling event subscription {0}", subscriptionId);
- _subscriptions.TryRemove(subscriptionId, out _);
+ if (subscriptionId is not null)
+ {
+ _subscriptions.TryRemove(subscriptionId, out _);
+ }
return new EventSubscriptionResponse(string.Empty, "text/plain");
}
- private EventSubscriptionResponse GetEventSubscriptionResponse(string subscriptionId, string requestedTimeoutString, int timeoutSeconds)
+ private static EventSubscriptionResponse GetEventSubscriptionResponse(string subscriptionId, string? requestedTimeoutString, int timeoutSeconds)
{
var response = new EventSubscriptionResponse(string.Empty, "text/plain");
@@ -109,14 +136,19 @@ private EventSubscriptionResponse GetEventSubscriptionResponse(string subscripti
return response;
}
- public EventSubscription GetSubscription(string id)
+ ///
+ /// Gets the subscription of an id.
+ ///
+ /// The id.
+ /// EventSubscription.
+ public EventSubscription? GetSubscription(string id)
{
return GetSubscription(id, false);
}
- private EventSubscription GetSubscription(string id, bool throwOnMissing)
+ private EventSubscription? GetSubscription(string? id, bool throwOnMissing)
{
- if (!_subscriptions.TryGetValue(id, out EventSubscription e) && throwOnMissing)
+ if (id is null || !_subscriptions.TryGetValue(id, out var e) && throwOnMissing)
{
throw new ResourceNotFoundException("Event with Id " + id + " not found.");
}
@@ -124,6 +156,12 @@ private EventSubscription GetSubscription(string id, bool throwOnMissing)
return e;
}
+ ///
+ /// Triggers an event.
+ ///
+ /// The notification type.
+ /// The state variables.
+ /// Task.
public Task TriggerEvent(string notificationType, IDictionary stateVariables)
{
var subs = _subscriptions.Values
diff --git a/src/Jellyfin.Plugin.Dlna/Eventing/EventSubscription.cs b/src/Jellyfin.Plugin.Dlna/Eventing/EventSubscription.cs
index 3c080d1..a71d9f1 100644
--- a/src/Jellyfin.Plugin.Dlna/Eventing/EventSubscription.cs
+++ b/src/Jellyfin.Plugin.Dlna/Eventing/EventSubscription.cs
@@ -1,27 +1,51 @@
-#nullable disable
-
-#pragma warning disable CS1591
-
using System;
namespace Jellyfin.Plugin.Dlna.Eventing;
+///
+/// Defines the .
+///
public class EventSubscription
{
- public string Id { get; set; }
-
- public string CallbackUrl { get; set; }
-
- public string NotificationType { get; set; }
-
+ ///
+ /// Gets the id.
+ ///
+ public string? Id { get; set; }
+
+ ///
+ /// Gets the callback URL.
+ ///
+ public string? CallbackUrl { get; set; }
+
+ ///
+ /// Gets the notification type.
+ ///
+ public string? NotificationType { get; set; }
+
+ ///
+ /// Gets the subscription time.
+ ///
public DateTime SubscriptionTime { get; set; }
+ ///
+ /// Gets the timeout seconds.
+ ///
public int TimeoutSeconds { get; set; }
+ ///
+ /// Gets the trigger count.
+ ///
public long TriggerCount { get; set; }
+ ///
+ /// Gets or sets a value indicating whether this instance is expired.
+ ///
+ /// true if this instance is expired; otherwise, false.
public bool IsExpired => SubscriptionTime.AddSeconds(TimeoutSeconds) >= DateTime.UtcNow;
+ ///
+ /// Increments the trigger count.
+ ///
public void IncrementTriggerCount()
{
if (TriggerCount == long.MaxValue)
diff --git a/src/Jellyfin.Plugin.Dlna/Extensions/StreamInfoExtensions.cs b/src/Jellyfin.Plugin.Dlna/Extensions/StreamInfoExtensions.cs
index 101998d..0ab20d3 100644
--- a/src/Jellyfin.Plugin.Dlna/Extensions/StreamInfoExtensions.cs
+++ b/src/Jellyfin.Plugin.Dlna/Extensions/StreamInfoExtensions.cs
@@ -7,8 +7,18 @@
namespace Jellyfin.Plugin.Dlna.Extensions;
+///
+/// Extensions for .
+///
public static class StreamInfoExtensions
{
+ ///
+ /// Get the DLNA URL.
+ ///
+ /// The .
+ /// The base URL.
+ /// The access token.
+ /// User id.
public static string ToDlnaUrl(this StreamInfo streamInfo, string baseUrl, string? accessToken)
{
ArgumentException.ThrowIfNullOrEmpty(baseUrl);
@@ -77,7 +87,7 @@ private static string GetUrl(StreamInfo streamInfo, string baseUrl, string query
return string.Format(CultureInfo.InvariantCulture, "{0}/dlna/videos/{1}/stream{2}?{3}", baseUrl, itemId, extension, queryString);
}
- private static IEnumerable BuildParams(StreamInfo item, string? accessToken)
+ private static List BuildParams(StreamInfo item, string? accessToken)
{
var list = new List();
diff --git a/src/Jellyfin.Plugin.Dlna/IConnectionManager.cs b/src/Jellyfin.Plugin.Dlna/IConnectionManager.cs
index 8618c2c..042d2bc 100644
--- a/src/Jellyfin.Plugin.Dlna/IConnectionManager.cs
+++ b/src/Jellyfin.Plugin.Dlna/IConnectionManager.cs
@@ -1,7 +1,8 @@
-#pragma warning disable CS1591
-
namespace Jellyfin.Plugin.Dlna;
+///
+/// Defines the interface.
+///
public interface IConnectionManager : IDlnaEventManager, IUpnpService
{
}
diff --git a/src/Jellyfin.Plugin.Dlna/IContentDirectory.cs b/src/Jellyfin.Plugin.Dlna/IContentDirectory.cs
index 9f0e478..370195c 100644
--- a/src/Jellyfin.Plugin.Dlna/IContentDirectory.cs
+++ b/src/Jellyfin.Plugin.Dlna/IContentDirectory.cs
@@ -1,7 +1,8 @@
-#pragma warning disable CS1591
-
namespace Jellyfin.Plugin.Dlna;
+///
+/// Defines the interface.
+///
public interface IContentDirectory : IDlnaEventManager, IUpnpService
{
}
diff --git a/src/Jellyfin.Plugin.Dlna/IDlnaEventManager.cs b/src/Jellyfin.Plugin.Dlna/IDlnaEventManager.cs
index a4d4017..128f88d 100644
--- a/src/Jellyfin.Plugin.Dlna/IDlnaEventManager.cs
+++ b/src/Jellyfin.Plugin.Dlna/IDlnaEventManager.cs
@@ -1,8 +1,8 @@
-#nullable disable
-#pragma warning disable CS1591
-
namespace Jellyfin.Plugin.Dlna;
+///
+/// Defines the interface.
+///
public interface IDlnaEventManager
{
///
@@ -10,7 +10,7 @@ public interface IDlnaEventManager
///
/// The subscription identifier.
/// The response.
- EventSubscriptionResponse CancelEventSubscription(string subscriptionId);
+ EventSubscriptionResponse CancelEventSubscription(string? subscriptionId);
///
/// Renews the event subscription.
@@ -20,7 +20,7 @@ public interface IDlnaEventManager
/// The requested timeout as a string.
/// The callback url.
/// The response.
- EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string requestedTimeoutString, string callbackUrl);
+ EventSubscriptionResponse RenewEventSubscription(string? subscriptionId, string? notificationType, string? requestedTimeoutString, string? callbackUrl);
///
/// Creates the event subscription.
@@ -29,5 +29,5 @@ public interface IDlnaEventManager
/// The requested timeout as a string.
/// The callback url.
/// The response.
- EventSubscriptionResponse CreateEventSubscription(string notificationType, string requestedTimeoutString, string callbackUrl);
+ EventSubscriptionResponse CreateEventSubscription(string? notificationType, string? requestedTimeoutString, string? callbackUrl);
}
diff --git a/src/Jellyfin.Plugin.Dlna/IMediaReceiverRegistrar.cs b/src/Jellyfin.Plugin.Dlna/IMediaReceiverRegistrar.cs
index 86f002d..aeb646c 100644
--- a/src/Jellyfin.Plugin.Dlna/IMediaReceiverRegistrar.cs
+++ b/src/Jellyfin.Plugin.Dlna/IMediaReceiverRegistrar.cs
@@ -1,7 +1,8 @@
-#pragma warning disable CS1591
-
namespace Jellyfin.Plugin.Dlna;
+///
+/// Defines the interface.
+///
public interface IMediaReceiverRegistrar : IDlnaEventManager, IUpnpService
{
}
diff --git a/src/Jellyfin.Plugin.Dlna/IUpnpService.cs b/src/Jellyfin.Plugin.Dlna/IUpnpService.cs
index da8589e..25f7da2 100644
--- a/src/Jellyfin.Plugin.Dlna/IUpnpService.cs
+++ b/src/Jellyfin.Plugin.Dlna/IUpnpService.cs
@@ -1,9 +1,10 @@
-#pragma warning disable CS1591
-
using System.Threading.Tasks;
namespace Jellyfin.Plugin.Dlna;
+///
+/// Defines the interface.
+///
public interface IUpnpService
{
///
diff --git a/src/Jellyfin.Plugin.Dlna/Jellyfin.Plugin.Dlna.csproj b/src/Jellyfin.Plugin.Dlna/Jellyfin.Plugin.Dlna.csproj
index 6f6ca2d..dc00765 100644
--- a/src/Jellyfin.Plugin.Dlna/Jellyfin.Plugin.Dlna.csproj
+++ b/src/Jellyfin.Plugin.Dlna/Jellyfin.Plugin.Dlna.csproj
@@ -1,7 +1,11 @@
net8.0
+ true
+ true
enable
+ AllEnabledByDefault
+ ../../jellyfin.ruleset
diff --git a/src/Jellyfin.Plugin.Dlna/Main/DlnaHost.cs b/src/Jellyfin.Plugin.Dlna/Main/DlnaHost.cs
index 0374bb9..9f63e29 100644
--- a/src/Jellyfin.Plugin.Dlna/Main/DlnaHost.cs
+++ b/src/Jellyfin.Plugin.Dlna/Main/DlnaHost.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CA1031 // Do not catch general exception types.
-
using System;
using System.Globalization;
using System.Linq;
@@ -270,7 +268,7 @@ private void RegisterServerEndpoints()
uri.Scheme = "http://";
uri.Port = httpBindPort;
- _logger.LogInformation("Registering publisher for {ResourceName} on {DeviceAddress} with uri {fulluri}", fullService, intf.Address, uri);
+ _logger.LogInformation("Registering publisher for {ResourceName} on {DeviceAddress} with uri {FullUri}", fullService, intf.Address, uri);
var device = new SsdpRootDevice
{
diff --git a/src/Jellyfin.Plugin.Dlna/MediaReceiverRegistrar/ControlHandler.cs b/src/Jellyfin.Plugin.Dlna/MediaReceiverRegistrar/ControlHandler.cs
index d14ca9c..63736b9 100644
--- a/src/Jellyfin.Plugin.Dlna/MediaReceiverRegistrar/ControlHandler.cs
+++ b/src/Jellyfin.Plugin.Dlna/MediaReceiverRegistrar/ControlHandler.cs
@@ -15,7 +15,7 @@ public class ControlHandler : BaseControlHandler
///
/// Initializes a new instance of the class.
///
- /// The for use with the instance.
+ /// The .
public ControlHandler(ILogger logger)
: base(logger)
{
diff --git a/src/Jellyfin.Plugin.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs b/src/Jellyfin.Plugin.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs
index 9422c54..aaaba64 100644
--- a/src/Jellyfin.Plugin.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs
+++ b/src/Jellyfin.Plugin.Dlna/MediaReceiverRegistrar/MediaReceiverRegistrarXmlBuilder.cs
@@ -16,74 +16,64 @@ public static class MediaReceiverRegistrarXmlBuilder
/// An XML representation of this service.
public static string GetXml()
{
- return new ServiceXmlBuilder().GetXml(ServiceActionListBuilder.GetActions(), GetStateVariables());
+ return ServiceXmlBuilder.GetXml(ServiceActionListBuilder.GetActions(), GetStateVariables());
}
///
/// The a list of all the state variables for this invocation.
///
/// The .
- private static IEnumerable GetStateVariables()
+ private static IReadOnlyList GetStateVariables()
{
- var list = new List
- {
- new StateVariable
- {
+ return
+ [
+ new() {
Name = "AuthorizationGrantedUpdateID",
DataType = "ui4",
SendsEvents = true
},
- new StateVariable
- {
+ new() {
Name = "A_ARG_TYPE_DeviceID",
DataType = "string",
SendsEvents = false
},
- new StateVariable
- {
+ new() {
Name = "AuthorizationDeniedUpdateID",
DataType = "ui4",
SendsEvents = true
},
- new StateVariable
- {
+ new() {
Name = "ValidationSucceededUpdateID",
DataType = "ui4",
SendsEvents = true
},
- new StateVariable
- {
+ new() {
Name = "A_ARG_TYPE_RegistrationRespMsg",
DataType = "bin.base64",
SendsEvents = false
},
- new StateVariable
- {
+ new() {
Name = "A_ARG_TYPE_RegistrationReqMsg",
DataType = "bin.base64",
SendsEvents = false
},
- new StateVariable
- {
+ new() {
Name = "ValidationRevokedUpdateID",
DataType = "ui4",
SendsEvents = true
},
- new StateVariable
- {
+ new() {
Name = "A_ARG_TYPE_Result",
DataType = "int",
SendsEvents = false
}
- };
-
- return list;
+ ];
}
}
diff --git a/src/Jellyfin.Plugin.Dlna/MediaReceiverRegistrar/ServiceActionListBuilder.cs b/src/Jellyfin.Plugin.Dlna/MediaReceiverRegistrar/ServiceActionListBuilder.cs
index bd050c8..73f3985 100644
--- a/src/Jellyfin.Plugin.Dlna/MediaReceiverRegistrar/ServiceActionListBuilder.cs
+++ b/src/Jellyfin.Plugin.Dlna/MediaReceiverRegistrar/ServiceActionListBuilder.cs
@@ -14,8 +14,8 @@ public static class ServiceActionListBuilder
/// An .
public static IEnumerable GetActions()
{
- return new[]
- {
+ return
+ [
GetIsValidated(),
GetIsAuthorized(),
GetRegisterDevice(),
@@ -23,7 +23,7 @@ public static IEnumerable GetActions()
GetGetAuthorizationGrantedUpdateID(),
GetGetValidationRevokedUpdateID(),
GetGetValidationSucceededUpdateID()
- };
+ ];
}
///
@@ -34,21 +34,21 @@ private static ServiceAction GetIsValidated()
{
var action = new ServiceAction
{
- Name = "IsValidated"
+ Name = "IsValidated",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "DeviceID",
+ Direction = "in"
+ },
+ new Argument
+ {
+ Name = "Result",
+ Direction = "out"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "DeviceID",
- Direction = "in"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "Result",
- Direction = "out"
- });
-
return action;
}
@@ -60,21 +60,21 @@ private static ServiceAction GetIsAuthorized()
{
var action = new ServiceAction
{
- Name = "IsAuthorized"
+ Name = "IsAuthorized",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "DeviceID",
+ Direction = "in"
+ },
+ new Argument
+ {
+ Name = "Result",
+ Direction = "out"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "DeviceID",
- Direction = "in"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "Result",
- Direction = "out"
- });
-
return action;
}
@@ -86,21 +86,21 @@ private static ServiceAction GetRegisterDevice()
{
var action = new ServiceAction
{
- Name = "RegisterDevice"
+ Name = "RegisterDevice",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "RegistrationReqMsg",
+ Direction = "in"
+ },
+ new Argument
+ {
+ Name = "RegistrationRespMsg",
+ Direction = "out"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "RegistrationReqMsg",
- Direction = "in"
- });
-
- action.ArgumentList.Add(new Argument
- {
- Name = "RegistrationRespMsg",
- Direction = "out"
- });
-
return action;
}
@@ -112,15 +112,16 @@ private static ServiceAction GetGetValidationSucceededUpdateID()
{
var action = new ServiceAction
{
- Name = "GetValidationSucceededUpdateID"
+ Name = "GetValidationSucceededUpdateID",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "ValidationSucceededUpdateID",
+ Direction = "out"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "ValidationSucceededUpdateID",
- Direction = "out"
- });
-
return action;
}
@@ -132,15 +133,16 @@ private static ServiceAction GetGetAuthorizationDeniedUpdateID()
{
var action = new ServiceAction
{
- Name = "GetAuthorizationDeniedUpdateID"
+ Name = "GetAuthorizationDeniedUpdateID",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "AuthorizationDeniedUpdateID",
+ Direction = "out"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "AuthorizationDeniedUpdateID",
- Direction = "out"
- });
-
return action;
}
@@ -152,15 +154,16 @@ private static ServiceAction GetGetValidationRevokedUpdateID()
{
var action = new ServiceAction
{
- Name = "GetValidationRevokedUpdateID"
+ Name = "GetValidationRevokedUpdateID",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "ValidationRevokedUpdateID",
+ Direction = "out"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "ValidationRevokedUpdateID",
- Direction = "out"
- });
-
return action;
}
@@ -172,15 +175,16 @@ private static ServiceAction GetGetAuthorizationGrantedUpdateID()
{
var action = new ServiceAction
{
- Name = "GetAuthorizationGrantedUpdateID"
+ Name = "GetAuthorizationGrantedUpdateID",
+ ArgumentList = [
+ new Argument
+ {
+ Name = "AuthorizationGrantedUpdateID",
+ Direction = "out"
+ }
+ ]
};
- action.ArgumentList.Add(new Argument
- {
- Name = "AuthorizationGrantedUpdateID",
- Direction = "out"
- });
-
return action;
}
}
diff --git a/src/Jellyfin.Plugin.Dlna/PlayTo/Device.cs b/src/Jellyfin.Plugin.Dlna/PlayTo/Device.cs
index da744c6..0def51f 100644
--- a/src/Jellyfin.Plugin.Dlna/PlayTo/Device.cs
+++ b/src/Jellyfin.Plugin.Dlna/PlayTo/Device.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -16,13 +14,14 @@
namespace Jellyfin.Plugin.Dlna.PlayTo;
+///
+/// Defines the .
+///
public class Device : IDisposable
{
private readonly IHttpClientFactory _httpClientFactory;
-
private readonly ILogger _logger;
-
- private readonly object _timerLock = new object();
+ private readonly object _timerLock = new();
private Timer? _timer;
private int _muteVol;
private int _volume;
@@ -31,6 +30,12 @@ public class Device : IDisposable
private int _connectFailureCount;
private bool _disposed;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The .
+ /// Instance of the interface.
+ /// Instance of the interface.
public Device(DeviceInfo deviceProperties, IHttpClientFactory httpClientFactory, ILogger logger)
{
Properties = deviceProperties;
@@ -38,18 +43,39 @@ public Device(DeviceInfo deviceProperties, IHttpClientFactory httpClientFactory,
_logger = logger;
}
+ ///
+ /// Raised when playback starts.
+ ///
public event EventHandler? PlaybackStart;
+ ///
+ /// Raised when playback progresses.
+ ///
public event EventHandler? PlaybackProgress;
+ ///
+ /// Raised when playback stopped.
+ ///
public event EventHandler? PlaybackStopped;
+ ///
+ /// Raised when media changed.
+ ///
public event EventHandler? MediaChanged;
+ ///
+ /// Gets or sets the properties.
+ ///
public DeviceInfo Properties { get; set; }
+ ///
+ /// Gets or sets a value indicating whether the device is muted.
+ ///
public bool IsMuted { get; set; }
+ ///
+ /// Gets or sets the volume.
+ ///
public int Volume
{
get
@@ -61,26 +87,59 @@ public int Volume
set => _volume = value;
}
+ ///
+ /// Gets or sets the playback duration.
+ ///
public TimeSpan? Duration { get; set; }
+ ///
+ /// Gets or sets the playback position.
+ ///
public TimeSpan Position { get; set; } = TimeSpan.FromSeconds(0);
+ ///
+ /// Gets or sets the transport state.
+ ///
public TransportState TransportState { get; private set; }
+ ///
+ /// Gets or sets a value indicating whether the device is playing.
+ ///
public bool IsPlaying => TransportState == TransportState.PLAYING;
+ ///
+ /// Gets or sets a value indicating whether the device is paused.
+ ///
public bool IsPaused => TransportState == TransportState.PAUSED_PLAYBACK;
+ ///
+ /// Gets or sets a value indicating whether the device is stopped.
+ ///
public bool IsStopped => TransportState == TransportState.STOPPED;
+ ///
+ /// Gets or sets the action to be executed when the device becomes unavailable.
+ ///
public Action? OnDeviceUnavailable { get; set; }
+ ///
+ /// Gets or sets the AV commands.
+ ///
private TransportCommands? AvCommands { get; set; }
+ ///
+ /// Gets or sets the render commands.
+ ///
private TransportCommands? RendererCommands { get; set; }
+ ///
+ /// Gets or sets the current media info.
+ ///
public UBaseObject? CurrentMediaInfo { get; private set; }
+ ///
+ /// Starts the device.
+ ///
public void Start()
{
_logger.LogDebug("Dlna Device.Start");
@@ -151,6 +210,9 @@ private void RestartTimerInactive()
}
}
+ ///
+ /// Lowers the volume.
+ ///
public Task VolumeDown(CancellationToken cancellationToken)
{
var sendVolume = Math.Max(Volume - 5, 0);
@@ -158,6 +220,9 @@ public Task VolumeDown(CancellationToken cancellationToken)
return SetVolume(sendVolume, cancellationToken);
}
+ ///
+ /// Rises the volume.
+ ///
public Task VolumeUp(CancellationToken cancellationToken)
{
var sendVolume = Math.Min(Volume + 5, 100);
@@ -165,6 +230,9 @@ public Task VolumeUp(CancellationToken cancellationToken)
return SetVolume(sendVolume, cancellationToken);
}
+ ///
+ /// Toggles mute.
+ ///
public Task ToggleMute(CancellationToken cancellationToken)
{
if (IsMuted)
@@ -175,6 +243,9 @@ public Task ToggleMute(CancellationToken cancellationToken)
return Mute(cancellationToken);
}
+ ///
+ /// Mutes the device.
+ ///
public async Task Mute(CancellationToken cancellationToken)
{
var success = await SetMute(true, cancellationToken).ConfigureAwait(true);
@@ -185,6 +256,9 @@ public async Task Mute(CancellationToken cancellationToken)
}
}
+ ///
+ /// Un-mutes the device.
+ ///
public async Task Unmute(CancellationToken cancellationToken)
{
var success = await SetMute(false, cancellationToken).ConfigureAwait(true);
@@ -279,6 +353,11 @@ public async Task SetVolume(int value, CancellationToken cancellationToken)
.ConfigureAwait(false);
}
+ ///
+ /// Seeks playback.
+ ///
+ /// The value to seek to.
+ /// The .
public async Task Seek(TimeSpan value, CancellationToken cancellationToken)
{
var avCommands = await GetAVProtocolAsync(cancellationToken).ConfigureAwait(false);
@@ -302,6 +381,13 @@ public async Task Seek(TimeSpan value, CancellationToken cancellationToken)
RestartTimer(true);
}
+ ///
+ /// Sets AV transport.
+ ///
+ /// The URL.
+ /// The header.
+ /// The meta data.
+ /// The .
public async Task SetAvTransport(string url, string? header, string metaData, CancellationToken cancellationToken)
{
var avCommands = await GetAVProtocolAsync(cancellationToken).ConfigureAwait(false);
@@ -349,10 +435,17 @@ public async Task SetAvTransport(string url, string? header, string metaData, Ca
RestartTimer(true);
}
- /*
- * SetNextAvTransport is used to specify to the DLNA device what is the next track to play.
- * Without that information, the next track command on the device does not work.
- */
+ ///
+ /// Sets next AV transport.
+ ///
+ /// The URL.
+ /// The header.
+ /// The meta data.
+ /// The .
+ ///
+ /// SetNextAvTransport is used to specify to the DLNA device what is the next track to play.
+ /// Without that information, the next track command on the device does not work.
+ ///
public async Task SetNextAvTransport(string url, string? header, string metaData, CancellationToken cancellationToken = default)
{
var avCommands = await GetAVProtocolAsync(cancellationToken).ConfigureAwait(false);
@@ -407,6 +500,10 @@ private Task SetPlay(TransportCommands avCommands, CancellationToken cancellatio
cancellationToken: cancellationToken);
}
+ ///
+ /// Sends play command.
+ ///
+ /// The .
public async Task SetPlay(CancellationToken cancellationToken)
{
var avCommands = await GetAVProtocolAsync(cancellationToken).ConfigureAwait(false);
@@ -420,6 +517,10 @@ public async Task SetPlay(CancellationToken cancellationToken)
RestartTimer(true);
}
+ ///
+ /// Sends stop command.
+ ///
+ /// The .
public async Task SetStop(CancellationToken cancellationToken)
{
var avCommands = await GetAVProtocolAsync(cancellationToken).ConfigureAwait(false);
@@ -443,6 +544,10 @@ public async Task SetStop(CancellationToken cancellationToken)
RestartTimer(true);
}
+ ///
+ /// Sends pause command.
+ ///
+ /// The .
public async Task SetPause(CancellationToken cancellationToken)
{
var avCommands = await GetAVProtocolAsync(cancellationToken).ConfigureAwait(false);
@@ -863,7 +968,7 @@ private async Task GetMute(CancellationToken cancellationToken)
return (true, uTrack);
}
- private XElement? ParseResponse(string xml)
+ private static XElement? ParseResponse(string xml)
{
// Handle different variations sent back by devices.
try
@@ -944,10 +1049,7 @@ private static string[] GetProtocolInfo(XElement container)
return AvCommands;
}
- if (_disposed)
- {
- throw new ObjectDisposedException(GetType().Name);
- }
+ ObjectDisposedException.ThrowIf(_disposed, GetType().Name);
var avService = GetAvTransportService();
if (avService is null)
@@ -976,10 +1078,7 @@ private static string[] GetProtocolInfo(XElement container)
return RendererCommands;
}
- if (_disposed)
- {
- throw new ObjectDisposedException(GetType().Name);
- }
+ ObjectDisposedException.ThrowIf(_disposed, GetType().Name);
var avService = GetServiceRenderingControl();
ArgumentNullException.ThrowIfNull(avService);
@@ -998,7 +1097,7 @@ private static string[] GetProtocolInfo(XElement container)
return RendererCommands;
}
- private string NormalizeUrl(string baseUrl, string url)
+ private static string NormalizeUrl(string baseUrl, string url)
{
// If it's already a complete url, don't stick anything onto the front of it
if (url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
@@ -1019,6 +1118,13 @@ private string NormalizeUrl(string baseUrl, string url)
return baseUrl + url;
}
+ ///
+ /// Creates uPNP device.
+ ///
+ /// The .
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// The .
public static async Task CreateuPnpDeviceAsync(Uri url, IHttpClientFactory httpClientFactory, ILogger logger, CancellationToken cancellationToken)
{
var ssdpHttpClient = new DlnaHttpClient(logger, httpClientFactory);
@@ -1046,7 +1152,8 @@ private string NormalizeUrl(string baseUrl, string url)
var deviceProperties = new DeviceInfo()
{
Name = string.Join(' ', friendlyNames),
- BaseUrl = string.Format(CultureInfo.InvariantCulture, "http://{0}:{1}", url.Host, url.Port)
+ BaseUrl = string.Format(CultureInfo.InvariantCulture, "http://{0}:{1}", url.Host, url.Port),
+ Services = GetServices(document)
};
var model = document.Descendants(UPnpNamespaces.Ud.GetName("modelName")).FirstOrDefault();
@@ -1109,30 +1216,6 @@ private string NormalizeUrl(string baseUrl, string url)
deviceProperties.Icon = CreateIcon(icon);
}
- foreach (var services in document.Descendants(UPnpNamespaces.Ud.GetName("serviceList")))
- {
- if (services is null)
- {
- continue;
- }
-
- var servicesList = services.Descendants(UPnpNamespaces.Ud.GetName("service"));
- if (servicesList is null)
- {
- continue;
- }
-
- foreach (var element in servicesList)
- {
- var service = Create(element);
-
- if (service is not null)
- {
- deviceProperties.Services.Add(service);
- }
- }
- }
-
return new Device(deviceProperties, httpClientFactory, logger);
}
@@ -1157,7 +1240,7 @@ private static DeviceIcon CreateIcon(XElement element)
}
private static DeviceService Create(XElement element)
- => new DeviceService()
+ => new()
{
ControlUrl = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("controlURL")) ?? string.Empty,
EventSubUrl = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("eventSubURL")) ?? string.Empty,
@@ -1166,6 +1249,36 @@ private static DeviceService Create(XElement element)
ServiceType = element.GetDescendantValue(UPnpNamespaces.Ud.GetName("serviceType")) ?? string.Empty
};
+ private static List GetServices(XDocument document)
+ {
+ List deviceServices = [];
+ foreach (var services in document.Descendants(UPnpNamespaces.Ud.GetName("serviceList")))
+ {
+ if (services is null)
+ {
+ continue;
+ }
+
+ var servicesList = services.Descendants(UPnpNamespaces.Ud.GetName("service"));
+ if (servicesList is null)
+ {
+ continue;
+ }
+
+ foreach (var element in servicesList)
+ {
+ var service = Create(element);
+
+ if (service is not null)
+ {
+ deviceServices.Add(service);
+ }
+ }
+ }
+
+ return deviceServices;
+ }
+
private void UpdateMediaInfo(UBaseObject? mediaInfo, TransportState state)
{
TransportState = state;
diff --git a/src/Jellyfin.Plugin.Dlna/PlayTo/DeviceInfo.cs b/src/Jellyfin.Plugin.Dlna/PlayTo/DeviceInfo.cs
index ec6ec51..93cf59f 100644
--- a/src/Jellyfin.Plugin.Dlna/PlayTo/DeviceInfo.cs
+++ b/src/Jellyfin.Plugin.Dlna/PlayTo/DeviceInfo.cs
@@ -1,53 +1,106 @@
-#nullable disable
-
-#pragma warning disable CS1591
-
using System.Collections.Generic;
using Jellyfin.Plugin.Dlna.Common;
using Jellyfin.Plugin.Dlna.Model;
namespace Jellyfin.Plugin.Dlna.PlayTo;
+///
+/// Defines the .
+///
public class DeviceInfo
{
- private readonly List _services = new List();
private string _baseUrl = string.Empty;
+ ///
+ /// Initializes a new instance of the class.
+ ///
public DeviceInfo()
{
+ UUID = string.Empty;
Name = "Generic Device";
+ ModelName = string.Empty;
+ ModelNumber = string.Empty;
+ ModelDescription = string.Empty;
+ ModelUrl = string.Empty;
+ Manufacturer = string.Empty;
+ ManufacturerUrl = string.Empty;
+ SerialNumber = string.Empty;
+ PresentationUrl = string.Empty;
+ Services = [];
}
+ ///
+ /// Gets or sets the UUID.
+ ///
public string UUID { get; set; }
+ ///
+ /// Gets or sets the name.
+ ///
public string Name { get; set; }
+ ///
+ /// Gets or sets the model name.
+ ///
public string ModelName { get; set; }
+ ///
+ /// Gets or sets the model number.
+ ///
public string ModelNumber { get; set; }
+ ///
+ /// Gets or sets the model description.
+ ///
public string ModelDescription { get; set; }
+ ///
+ /// Gets or sets the model URL.
+ ///
public string ModelUrl { get; set; }
+ ///
+ /// Gets or sets the manufacturer.
+ ///
public string Manufacturer { get; set; }
- public string SerialNumber { get; set; }
-
+ ///
+ /// Gets or sets the manufacturer URL.
+ ///
public string ManufacturerUrl { get; set; }
+ ///
+ /// Gets or sets the serial number.
+ ///
+ public string SerialNumber { get; set; }
+
+ ///
+ /// Gets or sets the presentation URL.
+ ///
public string PresentationUrl { get; set; }
+ ///
+ /// Gets or sets the base URL.
+ ///
public string BaseUrl
{
get => _baseUrl;
set => _baseUrl = value;
}
- public DeviceIcon Icon { get; set; }
+ ///
+ /// Gets or sets the icon.
+ ///
+ public DeviceIcon? Icon { get; set; }
- public List Services => _services;
+ ///
+ /// Gets or sets the device services.
+ ///
+ public IReadOnlyList Services { get; set; }
+ ///
+ /// Gets the .
+ ///
public DeviceIdentification ToDeviceIdentification()
{
return new DeviceIdentification
diff --git a/src/Jellyfin.Plugin.Dlna/PlayTo/DlnaHttpClient.cs b/src/Jellyfin.Plugin.Dlna/PlayTo/DlnaHttpClient.cs
index 0ee426a..f2b3762 100644
--- a/src/Jellyfin.Plugin.Dlna/PlayTo/DlnaHttpClient.cs
+++ b/src/Jellyfin.Plugin.Dlna/PlayTo/DlnaHttpClient.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System;
using System.Globalization;
using System.IO;
@@ -25,6 +23,11 @@ public partial class DlnaHttpClient
private readonly ILogger _logger;
private readonly IHttpClientFactory _httpClientFactory;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Instance of the interface.
+ /// Instance of the interface.
public DlnaHttpClient(ILogger logger, IHttpClientFactory httpClientFactory)
{
_logger = logger;
@@ -69,7 +72,7 @@ private static string NormalizeServiceUrl(string baseUrl, string serviceUrl)
{
// try correcting the Xml response with common errors
stream.Position = 0;
- using StreamReader sr = new StreamReader(stream);
+ using StreamReader sr = new(stream);
var xmlString = await sr.ReadToEndAsync(cancellationToken).ConfigureAwait(false);
// find and replace unescaped ampersands (&)
@@ -95,6 +98,12 @@ private static string NormalizeServiceUrl(string baseUrl, string serviceUrl)
}
}
+ ///
+ /// Gets data of a URL.
+ ///
+ /// The URL.
+ /// The .
+ /// Task.
public async Task GetDataAsync(string url, CancellationToken cancellationToken)
{
using var request = new HttpRequestMessage(HttpMethod.Get, url);
@@ -103,6 +112,16 @@ private static string NormalizeServiceUrl(string baseUrl, string serviceUrl)
return await SendRequestAsync(request, cancellationToken).ConfigureAwait(false);
}
+ ///
+ /// Sends command async.
+ ///
+ /// The base URL.
+ /// The .
+ /// The command.
+ /// The POST data.
+ /// The header.
+ /// The .
+ /// Task.
public async Task SendCommandAsync(
string baseUrl,
DeviceService service,
diff --git a/src/Jellyfin.Plugin.Dlna/PlayTo/MediaChangedEventArgs.cs b/src/Jellyfin.Plugin.Dlna/PlayTo/MediaChangedEventArgs.cs
index 2861f59..542132e 100644
--- a/src/Jellyfin.Plugin.Dlna/PlayTo/MediaChangedEventArgs.cs
+++ b/src/Jellyfin.Plugin.Dlna/PlayTo/MediaChangedEventArgs.cs
@@ -1,18 +1,30 @@
-#pragma warning disable CS1591
-
using System;
namespace Jellyfin.Plugin.Dlna.PlayTo;
+///
+/// Defines the .
+///
public class MediaChangedEventArgs : EventArgs
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The old media info .
+ /// The new media info .
public MediaChangedEventArgs(UBaseObject oldMediaInfo, UBaseObject newMediaInfo)
{
OldMediaInfo = oldMediaInfo;
NewMediaInfo = newMediaInfo;
}
+ ///
+ /// Gets or sets the old media info.
+ ///
public UBaseObject OldMediaInfo { get; set; }
+ ///
+ /// Gets or sets the new media info.
+ ///
public UBaseObject NewMediaInfo { get; set; }
}
diff --git a/src/Jellyfin.Plugin.Dlna/PlayTo/PlayToController.cs b/src/Jellyfin.Plugin.Dlna/PlayTo/PlayToController.cs
index 93b53fe..6d923ad 100644
--- a/src/Jellyfin.Plugin.Dlna/PlayTo/PlayToController.cs
+++ b/src/Jellyfin.Plugin.Dlna/PlayTo/PlayToController.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -31,7 +29,10 @@
namespace Jellyfin.Plugin.Dlna.PlayTo;
-public class PlayToController2 : ISessionController, IDisposable
+///
+/// Defines the .
+///
+public class PlayToController : ISessionController, IDisposable
{
private readonly SessionInfo _session;
private readonly ISessionManager _sessionManager;
@@ -44,18 +45,33 @@ public class PlayToController2 : ISessionController, IDisposable
private readonly ILocalizationManager _localization;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly IMediaEncoder _mediaEncoder;
-
private readonly IDeviceDiscovery _deviceDiscovery;
private readonly string _serverAddress;
private readonly string? _accessToken;
-
- private readonly List _playlist = new List();
+ private readonly List _playlist = [];
private Device _device;
private int _currentPlaylistIndex;
-
private bool _disposed;
- public PlayToController2(
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The .
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// The server address.
+ /// The access token.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// The .
+ public PlayToController(
SessionInfo session,
ISessionManager sessionManager,
ILibraryManager libraryManager,
@@ -99,8 +115,14 @@ public PlayToController2(
_deviceDiscovery.DeviceLeft += OnDeviceDiscoveryDeviceLeft;
}
+ ///
+ /// Gets or sets a value indicating the session is active.
+ ///
public bool IsSessionActive => !_disposed;
+ ///
+ /// Gets or sets a value indicating whether media control is supported.
+ ///
public bool SupportsMediaControl => IsSessionActive;
/*
@@ -114,16 +136,21 @@ private async Task SendNextTrackMessage(int currentPlayListItemIndex, Cancellati
var nextItemIndex = currentPlayListItemIndex + 1;
var nextItem = _playlist[nextItemIndex];
+ if (nextItem is null)
+ {
+ return;
+ }
+
// Send the SetNextAvTransport message.
await _device.SetNextAvTransport(nextItem.StreamUrl, GetDlnaHeaders(nextItem), nextItem.Didl, cancellationToken).ConfigureAwait(false);
}
}
- private void OnDeviceUnavailable()
+ private async void OnDeviceUnavailable()
{
try
{
- _sessionManager.ReportSessionEnded(_session.Id);
+ await _sessionManager.ReportSessionEnded(_session.Id).ConfigureAwait(false);
}
catch (Exception ex)
{
@@ -138,10 +165,10 @@ private void OnDeviceDiscoveryDeviceLeft(object? sender, GenericEventArgs
+ /// Sends a play command.
+ ///
+ /// The .
+ /// The .
+ /// Task.
public Task SendPlayCommand(PlayRequest command, CancellationToken cancellationToken)
{
_logger.LogDebug("{0} - Received PlayRequest: {1}", _session.DeviceName, command.PlayCommand);
@@ -466,12 +499,12 @@ private async Task Seek(long newPosition)
}
}
- private bool EnableClientSideSeek(StreamParams info)
+ private static bool EnableClientSideSeek(StreamParams info)
{
return info.IsDirectStream;
}
- private bool EnableClientSideSeek(StreamInfo info)
+ private static bool EnableClientSideSeek(StreamInfo info)
{
return info.IsDirectStream;
}
@@ -479,7 +512,7 @@ private bool EnableClientSideSeek(StreamInfo info)
private void AddItemFromId(Guid id, List list)
{
var item = _libraryManager.GetItemById(id);
- if (item.MediaType == MediaType.Audio || item.MediaType == MediaType.Video)
+ if (item?.MediaType == MediaType.Audio || item?.MediaType == MediaType.Video)
{
list.Add(item);
}
@@ -500,7 +533,7 @@ private PlaylistItem CreatePlaylistItem(
var mediaSources = item is IHasMediaSources
? _mediaSourceManager.GetStaticMediaSources(item, true, user).ToArray()
- : Array.Empty();
+ : [];
var playlistItem = GetPlaylistItem(item, mediaSources, profile, _session.DeviceId, mediaSourceId, audioStreamIndex, subtitleStreamIndex);
playlistItem.StreamInfo.StartPositionTicks = startPostionTicks;
@@ -526,7 +559,7 @@ private PlaylistItem CreatePlaylistItem(
return playlistItem;
}
- private string? GetDlnaHeaders(PlaylistItem item)
+ private static string? GetDlnaHeaders(PlaylistItem item)
{
var profile = item.Profile;
var streamInfo = item.StreamInfo;
@@ -846,12 +879,9 @@ private static long GetLongValue(IReadOnlyDictionary values, str
///
public Task SendMessage(SessionMessageType name, Guid messageId, T data, CancellationToken cancellationToken)
{
- if (_disposed)
- {
- throw new ObjectDisposedException(GetType().Name);
- }
-
- return name switch
+ return _disposed
+ ? throw new ObjectDisposedException(GetType().Name)
+ : name switch
{
SessionMessageType.Play => SendPlayCommand((data as PlayRequest)!, cancellationToken),
SessionMessageType.Playstate => SendPlaystateCommand((data as PlaystateRequest)!, cancellationToken),
@@ -860,7 +890,7 @@ public Task SendMessage(SessionMessageType name, Guid messageId, T data, Canc
};
}
- private class StreamParams
+ private sealed class StreamParams
{
private MediaSourceInfo? _mediaSource;
private IMediaSourceManager? _mediaSourceManager;
diff --git a/src/Jellyfin.Plugin.Dlna/PlayTo/PlayToManager.cs b/src/Jellyfin.Plugin.Dlna/PlayTo/PlayToManager.cs
index 5c61e6d..24f7246 100644
--- a/src/Jellyfin.Plugin.Dlna/PlayTo/PlayToManager.cs
+++ b/src/Jellyfin.Plugin.Dlna/PlayTo/PlayToManager.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System;
using System.Globalization;
using System.Linq;
@@ -21,11 +19,13 @@
namespace Jellyfin.Plugin.Dlna.PlayTo;
+///
+/// Defines the .
+///
public sealed class PlayToManager : IDisposable
{
private readonly ILogger _logger;
private readonly ISessionManager _sessionManager;
-
private readonly ILibraryManager _libraryManager;
private readonly IUserManager _userManager;
private readonly IDlnaManager _dlnaManager;
@@ -34,16 +34,43 @@ public sealed class PlayToManager : IDisposable
private readonly IHttpClientFactory _httpClientFactory;
private readonly IUserDataManager _userDataManager;
private readonly ILocalizationManager _localization;
-
private readonly IDeviceDiscovery _deviceDiscovery;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly IMediaEncoder _mediaEncoder;
-
- private readonly SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1);
- private readonly CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
+ private readonly SemaphoreSlim _sessionLock = new(1, 1);
+ private readonly CancellationTokenSource _disposeCancellationTokenSource = new();
private bool _disposed;
- public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClientFactory httpClientFactory, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder)
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The .
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ public PlayToManager(
+ ILogger logger,
+ ISessionManager sessionManager,
+ ILibraryManager libraryManager,
+ IUserManager userManager,
+ IDlnaManager dlnaManager,
+ IServerApplicationHost appHost,
+ IImageProcessor imageProcessor,
+ IDeviceDiscovery deviceDiscovery,
+ IHttpClientFactory httpClientFactory,
+ IUserDataManager userDataManager,
+ ILocalizationManager localization,
+ IMediaSourceManager mediaSourceManager,
+ IMediaEncoder mediaEncoder)
{
_logger = logger;
_sessionManager = sessionManager;
@@ -60,6 +87,9 @@ public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryMan
_mediaEncoder = mediaEncoder;
}
+ ///
+ /// Starts device discovery.
+ ///
public void Start()
{
_deviceDiscovery.DeviceDiscovered += OnDeviceDiscoveryDeviceDiscovered;
@@ -102,7 +132,7 @@ private async void OnDeviceDiscoveryDeviceDiscovered(object? sender, GenericEven
return;
}
- if (_sessionManager.Sessions.Any(i => usn.IndexOf(i.DeviceId, StringComparison.OrdinalIgnoreCase) != -1))
+ if (_sessionManager.Sessions.Any(i => usn.Contains(i.DeviceId, StringComparison.OrdinalIgnoreCase)))
{
return;
}
@@ -172,7 +202,7 @@ private async Task AddDevice(UpnpDeviceInfo info, CancellationToken cancellation
.LogSessionActivity("DLNA", _appHost.ApplicationVersionString, uuid, null, uri.OriginalString, null)
.ConfigureAwait(false);
- var controller = sessionInfo.SessionControllers.OfType().FirstOrDefault();
+ var controller = sessionInfo.SessionControllers.OfType().FirstOrDefault();
if (controller is null)
{
@@ -189,7 +219,7 @@ private async Task AddDevice(UpnpDeviceInfo info, CancellationToken cancellation
string serverAddress = _appHost.GetSmartApiUrl(info.RemoteIPAddress);
- controller = new PlayToController2(
+ controller = new PlayToController(
sessionInfo,
_sessionManager,
_libraryManager,
@@ -213,10 +243,10 @@ private async Task AddDevice(UpnpDeviceInfo info, CancellationToken cancellation
_sessionManager.ReportCapabilities(sessionInfo.Id, new ClientCapabilities
{
- PlayableMediaTypes = profile.GetSupportedMediaTypes(),
+ PlayableMediaTypes = profile.FetchSupportedMediaTypes(),
- SupportedCommands = new[]
- {
+ SupportedCommands =
+ [
GeneralCommandType.VolumeDown,
GeneralCommandType.VolumeUp,
GeneralCommandType.Mute,
@@ -226,7 +256,7 @@ private async Task AddDevice(UpnpDeviceInfo info, CancellationToken cancellation
GeneralCommandType.SetAudioStreamIndex,
GeneralCommandType.SetSubtitleStreamIndex,
GeneralCommandType.PlayMediaSource
- },
+ ],
SupportsMediaControl = true
});
diff --git a/src/Jellyfin.Plugin.Dlna/PlayTo/PlaybackProgressEventArgs.cs b/src/Jellyfin.Plugin.Dlna/PlayTo/PlaybackProgressEventArgs.cs
index 6bea3b5..193cd96 100644
--- a/src/Jellyfin.Plugin.Dlna/PlayTo/PlaybackProgressEventArgs.cs
+++ b/src/Jellyfin.Plugin.Dlna/PlayTo/PlaybackProgressEventArgs.cs
@@ -1,15 +1,23 @@
-#pragma warning disable CS1591
-
using System;
namespace Jellyfin.Plugin.Dlna.PlayTo;
+///
+/// Defines the .
+///
public class PlaybackProgressEventArgs : EventArgs
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The media info .
public PlaybackProgressEventArgs(UBaseObject mediaInfo)
{
MediaInfo = mediaInfo;
}
+ ///
+ /// Gets or sets the media info.
+ ///
public UBaseObject MediaInfo { get; set; }
}
diff --git a/src/Jellyfin.Plugin.Dlna/PlayTo/PlaybackStartEventArgs.cs b/src/Jellyfin.Plugin.Dlna/PlayTo/PlaybackStartEventArgs.cs
index c8580d3..930a3fb 100644
--- a/src/Jellyfin.Plugin.Dlna/PlayTo/PlaybackStartEventArgs.cs
+++ b/src/Jellyfin.Plugin.Dlna/PlayTo/PlaybackStartEventArgs.cs
@@ -1,15 +1,23 @@
-#pragma warning disable CS1591
-
using System;
namespace Jellyfin.Plugin.Dlna.PlayTo;
+///
+/// Defines the .
+///
public class PlaybackStartEventArgs : EventArgs
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The media info .
public PlaybackStartEventArgs(UBaseObject mediaInfo)
{
MediaInfo = mediaInfo;
}
+ ///
+ /// Gets or sets the media info.
+ ///
public UBaseObject MediaInfo { get; set; }
}
diff --git a/src/Jellyfin.Plugin.Dlna/PlayTo/PlaybackStoppedEventArgs.cs b/src/Jellyfin.Plugin.Dlna/PlayTo/PlaybackStoppedEventArgs.cs
index b4aef04..fde3183 100644
--- a/src/Jellyfin.Plugin.Dlna/PlayTo/PlaybackStoppedEventArgs.cs
+++ b/src/Jellyfin.Plugin.Dlna/PlayTo/PlaybackStoppedEventArgs.cs
@@ -1,15 +1,23 @@
-#pragma warning disable CS1591
-
using System;
namespace Jellyfin.Plugin.Dlna.PlayTo;
+///
+/// Defines the .
+///
public class PlaybackStoppedEventArgs : EventArgs
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The media info .
public PlaybackStoppedEventArgs(UBaseObject mediaInfo)
{
MediaInfo = mediaInfo;
}
+ ///
+ /// Gets or sets the media info.
+ ///
public UBaseObject MediaInfo { get; set; }
}
diff --git a/src/Jellyfin.Plugin.Dlna/PlayTo/PlaylistItem.cs b/src/Jellyfin.Plugin.Dlna/PlayTo/PlaylistItem.cs
index 3baa014..4ddc2e4 100644
--- a/src/Jellyfin.Plugin.Dlna/PlayTo/PlaylistItem.cs
+++ b/src/Jellyfin.Plugin.Dlna/PlayTo/PlaylistItem.cs
@@ -1,19 +1,32 @@
-#nullable disable
-
-#pragma warning disable CS1591
+# nullable disable
using Jellyfin.Plugin.Dlna.Model;
using MediaBrowser.Model.Dlna;
namespace Jellyfin.Plugin.Dlna.PlayTo;
+///
+/// Defines the .
+///
public class PlaylistItem
{
+ ///
+ /// Gets or sets the stream URL.
+ ///
public string StreamUrl { get; set; }
+ ///
+ /// Gets or sets the DIDL.
+ ///
public string Didl { get; set; }
+ ///
+ /// Gets or sets the stream info.
+ ///
public StreamInfo StreamInfo { get; set; }
+ ///
+ /// Gets or sets the profile.
+ ///
public DlnaDeviceProfile Profile { get; set; }
}
diff --git a/src/Jellyfin.Plugin.Dlna/PlayTo/PlaylistItemFactory.cs b/src/Jellyfin.Plugin.Dlna/PlayTo/PlaylistItemFactory.cs
index 436ef34..3570766 100644
--- a/src/Jellyfin.Plugin.Dlna/PlayTo/PlaylistItemFactory.cs
+++ b/src/Jellyfin.Plugin.Dlna/PlayTo/PlaylistItemFactory.cs
@@ -1,7 +1,3 @@
-#nullable disable
-
-#pragma warning disable CS1591
-
using System.IO;
using System.Linq;
using Jellyfin.Plugin.Dlna.Model;
@@ -11,8 +7,16 @@
namespace Jellyfin.Plugin.Dlna.PlayTo;
+///
+/// Defines the .
+///
public static class PlaylistItemFactory
{
+ ///
+ /// Creates a new playlist item.
+ ///
+ /// The .
+ /// The .
public static PlaylistItem Create(Photo item, DlnaDeviceProfile profile)
{
var playlistItem = new PlaylistItem
diff --git a/src/Jellyfin.Plugin.Dlna/PlayTo/TransportCommands.cs b/src/Jellyfin.Plugin.Dlna/PlayTo/TransportCommands.cs
index bed5732..9ff7d02 100644
--- a/src/Jellyfin.Plugin.Dlna/PlayTo/TransportCommands.cs
+++ b/src/Jellyfin.Plugin.Dlna/PlayTo/TransportCommands.cs
@@ -1,62 +1,69 @@
-#pragma warning disable CS1591
-
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using System.Text;
using System.Xml.Linq;
using Jellyfin.Plugin.Dlna.Common;
using Jellyfin.Plugin.Dlna.Ssdp;
namespace Jellyfin.Plugin.Dlna.PlayTo;
+///
+/// Defines the .
+///
public class TransportCommands
{
- private const string CommandBase = "\r\n" + "" + "" + "" + "{2}" + "" + "";
-
- public List StateVariables { get; } = new List();
-
- public List ServiceActions { get; } = new List();
-
+ private static readonly CompositeFormat _commandBase = CompositeFormat.Parse("\r\n" + "" + "" + "" + "{2}" + "" + "");
+
+ ///
+ /// Gets or sets the state variables.
+ ///
+ public IReadOnlyList StateVariables { get; set; } = [];
+
+ ///
+ /// Gets or sets the service actions.
+ ///
+ public IReadOnlyList ServiceActions { get; set; } = [];
+
+ ///
+ /// Creates based on the input .
+ ///
+ /// The .
public static TransportCommands Create(XDocument document)
{
- var command = new TransportCommands();
-
var actionList = document.Descendants(UPnpNamespaces.Svc + "actionList");
-
- foreach (var container in actionList.Descendants(UPnpNamespaces.Svc + "action"))
- {
- command.ServiceActions.Add(ServiceActionFromXml(container));
- }
-
var stateValues = document.Descendants(UPnpNamespaces.ServiceStateTable).FirstOrDefault();
- if (stateValues is not null)
+ return new()
{
- foreach (var container in stateValues.Elements(UPnpNamespaces.Svc + "stateVariable"))
- {
- command.StateVariables.Add(FromXml(container));
- }
- }
+ ServiceActions = GetServiceActions(actionList),
+ StateVariables = GetStateVariables(stateValues)
+ };
+ }
+
+ private static List GetStateVariables(XElement? stateValues)
+ {
+ return stateValues?.Descendants(UPnpNamespaces.Svc + "stateVariable").Select(FromXml).ToList() ?? [];
+ }
- return command;
+ private static List GetServiceActions(IEnumerable actionList)
+ {
+ return actionList.Descendants(UPnpNamespaces.Svc + "action").Select(ServiceActionFromXml).ToList();
}
private static ServiceAction ServiceActionFromXml(XElement container)
{
- var serviceAction = new ServiceAction
+ return new()
{
Name = container.GetValue(UPnpNamespaces.Svc + "name") ?? string.Empty,
+ ArgumentList = GetArguments(container)
};
+ }
- var argumentList = serviceAction.ArgumentList;
-
- foreach (var arg in container.Descendants(UPnpNamespaces.Svc + "argument"))
- {
- argumentList.Add(ArgumentFromXml(arg));
- }
-
- return serviceAction;
+ private static List GetArguments(XElement container)
+ {
+ return container.Descendants(UPnpNamespaces.Svc + "argument").Select(ArgumentFromXml).ToList();
}
private static Argument ArgumentFromXml(XElement container)
@@ -92,6 +99,11 @@ private static StateVariable FromXml(XElement container)
};
}
+ ///
+ /// Builds the POST payload for a .
+ ///
+ /// The .
+ /// The XML namespace.
public string BuildPost(ServiceAction action, string xmlNamespace)
{
var stateString = string.Empty;
@@ -113,9 +125,16 @@ public string BuildPost(ServiceAction action, string xmlNamespace)
}
}
- return string.Format(CultureInfo.InvariantCulture, CommandBase, action.Name, xmlNamespace, stateString);
+ return string.Format(CultureInfo.InvariantCulture, _commandBase, action.Name, xmlNamespace, stateString);
}
+ ///
+ /// Builds the POST payload for a .
+ ///
+ /// The .
+ /// The XML namespace.
+ /// The value.
+ /// The command parameter.
public string BuildPost(ServiceAction action, string xmlNamespace, object value, string commandParameter = "")
{
var stateString = string.Empty;
@@ -137,10 +156,17 @@ public string BuildPost(ServiceAction action, string xmlNamespace, object value,
}
}
- return string.Format(CultureInfo.InvariantCulture, CommandBase, action.Name, xmlNamespace, stateString);
+ return string.Format(CultureInfo.InvariantCulture, _commandBase, action.Name, xmlNamespace, stateString);
}
- public string BuildPost(ServiceAction action, string xmlNamespace, object value, Dictionary dictionary)
+ ///
+ /// Builds the POST payload for a .
+ ///
+ /// The .
+ /// The XML namespace.
+ /// The value.
+ /// The argument values.
+ public string BuildPost(ServiceAction action, string xmlNamespace, object value, Dictionary argumentValueDictionary)
{
var stateString = string.Empty;
@@ -150,7 +176,7 @@ public string BuildPost(ServiceAction action, string xmlNamespace, object value,
{
stateString += BuildArgumentXml(arg, "0");
}
- else if (dictionary.TryGetValue(arg.Name, out var argValue))
+ else if (argumentValueDictionary.TryGetValue(arg.Name, out var argValue))
{
stateString += BuildArgumentXml(arg, argValue);
}
@@ -160,7 +186,7 @@ public string BuildPost(ServiceAction action, string xmlNamespace, object value,
}
}
- return string.Format(CultureInfo.InvariantCulture, CommandBase, action.Name, xmlNamespace, stateString);
+ return string.Format(CultureInfo.InvariantCulture, _commandBase, action.Name, xmlNamespace, stateString);
}
private string BuildArgumentXml(Argument argument, string? value, string commandParameter = "")
diff --git a/src/Jellyfin.Plugin.Dlna/PlayTo/TransportState.cs b/src/Jellyfin.Plugin.Dlna/PlayTo/TransportState.cs
index daf3e23..5e3f3a6 100644
--- a/src/Jellyfin.Plugin.Dlna/PlayTo/TransportState.cs
+++ b/src/Jellyfin.Plugin.Dlna/PlayTo/TransportState.cs
@@ -1,4 +1,4 @@
-#pragma warning disable CS1591
+#pragma warning disable CA1707
namespace Jellyfin.Plugin.Dlna.PlayTo;
@@ -8,8 +8,23 @@ namespace Jellyfin.Plugin.Dlna.PlayTo;
///
public enum TransportState
{
+ ///
+ /// Stopped state.
+ ///
STOPPED,
+
+ ///
+ /// Playing state.
+ ///
PLAYING,
+
+ ///
+ /// Transitioning state.
+ ///
TRANSITIONING,
+
+ ///
+ /// Paused state.
+ ///
PAUSED_PLAYBACK
}
diff --git a/src/Jellyfin.Plugin.Dlna/PlayTo/UpnpContainer.cs b/src/Jellyfin.Plugin.Dlna/PlayTo/UpnpContainer.cs
index cdb2cf1..17ac5ee 100644
--- a/src/Jellyfin.Plugin.Dlna/PlayTo/UpnpContainer.cs
+++ b/src/Jellyfin.Plugin.Dlna/PlayTo/UpnpContainer.cs
@@ -1,13 +1,18 @@
-#pragma warning disable CS1591
-
using System;
using System.Xml.Linq;
using Jellyfin.Plugin.Dlna.Ssdp;
namespace Jellyfin.Plugin.Dlna.PlayTo;
+///
+/// Defines the .
+///
public class UpnpContainer : UBaseObject
{
+ ///
+ /// Create a .
+ ///
+ /// The .
public static UBaseObject Create(XElement container)
{
ArgumentNullException.ThrowIfNull(container);
diff --git a/src/Jellyfin.Plugin.Dlna/PlayTo/uBaseObject.cs b/src/Jellyfin.Plugin.Dlna/PlayTo/uBaseObject.cs
index edf7167..326412d 100644
--- a/src/Jellyfin.Plugin.Dlna/PlayTo/uBaseObject.cs
+++ b/src/Jellyfin.Plugin.Dlna/PlayTo/uBaseObject.cs
@@ -1,32 +1,63 @@
#nullable disable
-#pragma warning disable CS1591
-
using System;
using System.Collections.Generic;
namespace Jellyfin.Plugin.Dlna.PlayTo;
+///
+/// Defines the .
+///
public class UBaseObject
{
+ ///
+ /// Gets or sets the id.
+ ///
public string Id { get; set; }
+ ///
+ /// Gets or sets the parent id.
+ ///
public string ParentId { get; set; }
+ ///
+ /// Gets or sets the title.
+ ///
public string Title { get; set; }
+ ///
+ /// Gets or sets the second text.
+ ///
public string SecondText { get; set; }
+ ///
+ /// Gets or sets the icon URL.
+ ///
public string IconUrl { get; set; }
+ ///
+ /// Gets or sets the meta data.
+ ///
public string MetaData { get; set; }
+ ///
+ /// Gets or sets the URL.
+ ///
public string Url { get; set; }
+ ///
+ /// Gets or sets the protocol info.
+ ///
public IReadOnlyList ProtocolInfo { get; set; }
+ ///
+ /// Gets or sets the UPnP class.
+ ///
public string UpnpClass { get; set; }
+ ///
+ /// Gets or sets the media type.
+ ///
public string MediaType
{
get
@@ -52,6 +83,7 @@ public string MediaType
}
}
+ ///
public bool Equals(UBaseObject obj)
{
ArgumentNullException.ThrowIfNull(obj);
diff --git a/src/Jellyfin.Plugin.Dlna/PlayTo/uPnpNamespaces.cs b/src/Jellyfin.Plugin.Dlna/PlayTo/uPnpNamespaces.cs
index 0d2ca8f..0c2cf47 100644
--- a/src/Jellyfin.Plugin.Dlna/PlayTo/uPnpNamespaces.cs
+++ b/src/Jellyfin.Plugin.Dlna/PlayTo/uPnpNamespaces.cs
@@ -1,66 +1,154 @@
-#pragma warning disable CS1591
-
using System.Xml.Linq;
namespace Jellyfin.Plugin.Dlna.PlayTo;
+///
+/// Defines the .
+///
public static class UPnpNamespaces
{
+ ///
+ /// Gets the Dc namespace.
+ ///
public static XNamespace Dc { get; } = "http://purl.org/dc/elements/1.1/";
+ ///
+ /// Gets the Ns namespace.
+ ///
public static XNamespace Ns { get; } = "urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/";
+ ///
+ /// Gets the service namespace.
+ ///
public static XNamespace Svc { get; } = "urn:schemas-upnp-org:service-1-0";
+ ///
+ /// Gets the device namespace.
+ ///
public static XNamespace Ud { get; } = "urn:schemas-upnp-org:device-1-0";
+ ///
+ /// Gets the Upnp namespace.
+ ///
public static XNamespace UPnp { get; } = "urn:schemas-upnp-org:metadata-1-0/upnp/";
+ ///
+ /// Gets the RenderingControl namespace.
+ ///
public static XNamespace RenderingControl { get; } = "urn:schemas-upnp-org:service:RenderingControl:1";
+ ///
+ /// Gets the AvTransport namespace.
+ ///
public static XNamespace AvTransport { get; } = "urn:schemas-upnp-org:service:AVTransport:1";
+ ///
+ /// Gets the ContentDirectory namespace.
+ ///
public static XNamespace ContentDirectory { get; } = "urn:schemas-upnp-org:service:ContentDirectory:1";
+ ///
+ /// Gets the container element name.
+ ///
public static XName Containers { get; } = Ns + "container";
+ ///
+ /// Gets the item element name.
+ ///
public static XName Items { get; } = Ns + "item";
+ ///
+ /// Gets the title element name.
+ ///
public static XName Title { get; } = Dc + "title";
+ ///
+ /// Gets the creator element name.
+ ///
public static XName Creator { get; } = Dc + "creator";
+ ///
+ /// Gets the artist element name.
+ ///
public static XName Artist { get; } = UPnp + "artist";
+ ///
+ /// Gets the id element name.
+ ///
public static XName Id { get; } = "id";
+ ///
+ /// Gets the parent id element name.
+ ///
public static XName ParentId { get; } = "parentID";
+ ///
+ /// Gets the class element name.
+ ///
public static XName Class { get; } = UPnp + "class";
+ ///
+ /// Gets the artwork element name.
+ ///
public static XName Artwork { get; } = UPnp + "albumArtURI";
+ ///
+ /// Gets the description element name.
+ ///
public static XName Description { get; } = Dc + "description";
+ ///
+ /// Gets the long description element name.
+ ///
public static XName LongDescription { get; } = UPnp + "longDescription";
+ ///
+ /// Gets the album element name.
+ ///
public static XName Album { get; } = UPnp + "album";
+ ///
+ /// Gets the author element name.
+ ///
public static XName Author { get; } = UPnp + "author";
+ ///
+ /// Gets the director element name.
+ ///
public static XName Director { get; } = UPnp + "director";
+ ///
+ /// Gets the playback count element name.
+ ///
public static XName PlayCount { get; } = UPnp + "playbackCount";
+ ///
+ /// Gets the track number element name.
+ ///
public static XName Tracknumber { get; } = UPnp + "originalTrackNumber";
+ ///
+ /// Gets the resolution element name.
+ ///
public static XName Res { get; } = Ns + "res";
+ ///
+ /// Gets the duration element name.
+ ///
public static XName Duration { get; } = "duration";
+ ///
+ /// Gets the protocol info element name.
+ ///
public static XName ProtocolInfo { get; } = "protocolInfo";
+ ///
+ /// Gets the service state table element name.
+ ///
public static XName ServiceStateTable { get; } = Svc + "serviceStateTable";
+ ///
+ /// Gets the state variable element name.
+ ///
public static XName StateVariable { get; } = Svc + "stateVariable";
}
diff --git a/src/Jellyfin.Plugin.Dlna/Profiles/DefaultProfile.cs b/src/Jellyfin.Plugin.Dlna/Profiles/DefaultProfile.cs
index 71c809f..60f05bb 100644
--- a/src/Jellyfin.Plugin.Dlna/Profiles/DefaultProfile.cs
+++ b/src/Jellyfin.Plugin.Dlna/Profiles/DefaultProfile.cs
@@ -1,15 +1,18 @@
-#pragma warning disable CS1591
-
using System;
-using System.Globalization;
using Jellyfin.Plugin.Dlna.Model;
using MediaBrowser.Model.Dlna;
namespace Jellyfin.Plugin.Dlna.Profiles;
+///
+/// Defines the .
+///
[System.Xml.Serialization.XmlRoot("Profile")]
public class DefaultProfile : DlnaDeviceProfile
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
public DefaultProfile()
{
Id = Guid.NewGuid();
@@ -38,8 +41,8 @@ public DefaultProfile()
EnableAlbumArtInDidl = false;
- TranscodingProfiles = new[]
- {
+ TranscodingProfiles =
+ [
new TranscodingProfile
{
Container = "mp3",
@@ -60,10 +63,10 @@ public DefaultProfile()
Container = "jpeg",
Type = DlnaProfileType.Photo
}
- };
+ ];
- DirectPlayProfiles = new[]
- {
+ DirectPlayProfiles =
+ [
new DirectPlayProfile
{
// play all
@@ -77,10 +80,10 @@ public DefaultProfile()
Container = string.Empty,
Type = DlnaProfileType.Audio
}
- };
+ ];
- SubtitleProfiles = new[]
- {
+ SubtitleProfiles =
+ [
new SubtitleProfile
{
Format = "srt",
@@ -164,16 +167,16 @@ public DefaultProfile()
Format = "vtt",
Method = SubtitleDeliveryMethod.Embed
}
- };
+ ];
- ResponseProfiles = new[]
- {
+ ResponseProfiles =
+ [
new ResponseProfile
{
Container = "m4v",
Type = DlnaProfileType.Video,
MimeType = "video/mp4"
}
- };
+ ];
}
}
diff --git a/src/Jellyfin.Plugin.Dlna/Server/DescriptionXmlBuilder.cs b/src/Jellyfin.Plugin.Dlna/Server/DescriptionXmlBuilder.cs
index 24e2ff8..f95389a 100644
--- a/src/Jellyfin.Plugin.Dlna/Server/DescriptionXmlBuilder.cs
+++ b/src/Jellyfin.Plugin.Dlna/Server/DescriptionXmlBuilder.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -11,6 +9,9 @@
namespace Jellyfin.Plugin.Dlna.Server;
+///
+/// Defines the .
+///
public class DescriptionXmlBuilder
{
private readonly DlnaDeviceProfile _profile;
@@ -20,6 +21,14 @@ public class DescriptionXmlBuilder
private readonly string _serverName;
private readonly string _serverId;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The .
+ /// The server UDN.
+ /// The address.
+ /// The name.
+ /// The id.
public DescriptionXmlBuilder(DlnaDeviceProfile profile, string serverUdn, string serverAddress, string serverName, string serverId)
{
ArgumentException.ThrowIfNullOrEmpty(serverUdn);
@@ -31,6 +40,9 @@ public DescriptionXmlBuilder(DlnaDeviceProfile profile, string serverUdn, string
_serverId = serverId;
}
+ ///
+ /// Gets the description XML.
+ ///
public string GetXml()
{
var builder = new StringBuilder();
@@ -254,9 +266,9 @@ private string BuildUrl(string url)
return SecurityElement.Escape(url);
}
- private IEnumerable GetIcons()
- => new[]
- {
+ private static IEnumerable GetIcons()
+ =>
+ [
new DeviceIcon
{
MimeType = "image/png",
@@ -310,29 +322,27 @@ private IEnumerable GetIcons()
Height = 48,
Url = "icons/logo48.jpg"
}
- };
+ ];
- private IEnumerable GetServices()
+ private List GetServices()
{
- var list = new List();
-
- list.Add(new DeviceService
+ var list = new List
{
- ServiceType = "urn:schemas-upnp-org:service:ContentDirectory:1",
- ServiceId = "urn:upnp-org:serviceId:ContentDirectory",
- ScpdUrl = "contentdirectory/contentdirectory.xml",
- ControlUrl = "contentdirectory/control",
- EventSubUrl = "contentdirectory/events"
- });
-
- list.Add(new DeviceService
- {
- ServiceType = "urn:schemas-upnp-org:service:ConnectionManager:1",
- ServiceId = "urn:upnp-org:serviceId:ConnectionManager",
- ScpdUrl = "connectionmanager/connectionmanager.xml",
- ControlUrl = "connectionmanager/control",
- EventSubUrl = "connectionmanager/events"
- });
+ new() {
+ ServiceType = "urn:schemas-upnp-org:service:ContentDirectory:1",
+ ServiceId = "urn:upnp-org:serviceId:ContentDirectory",
+ ScpdUrl = "contentdirectory/contentdirectory.xml",
+ ControlUrl = "contentdirectory/control",
+ EventSubUrl = "contentdirectory/events"
+ },
+ new() {
+ ServiceType = "urn:schemas-upnp-org:service:ConnectionManager:1",
+ ServiceId = "urn:upnp-org:serviceId:ConnectionManager",
+ ScpdUrl = "connectionmanager/connectionmanager.xml",
+ ControlUrl = "connectionmanager/control",
+ EventSubUrl = "connectionmanager/events"
+ }
+ };
if (_profile.EnableMSMediaReceiverRegistrar)
{
@@ -349,6 +359,7 @@ private IEnumerable GetServices()
return list;
}
+ ///
public override string ToString()
{
return GetXml();
diff --git a/src/Jellyfin.Plugin.Dlna/Service/BaseControlHandler.cs b/src/Jellyfin.Plugin.Dlna/Service/BaseControlHandler.cs
index 330c3de..3b1ed3a 100644
--- a/src/Jellyfin.Plugin.Dlna/Service/BaseControlHandler.cs
+++ b/src/Jellyfin.Plugin.Dlna/Service/BaseControlHandler.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System;
using System.Collections.Generic;
using System.IO;
@@ -12,17 +10,32 @@
namespace Jellyfin.Plugin.Dlna.Service;
+///
+/// Defines the .
+///
public abstract class BaseControlHandler
{
private const string NsSoapEnv = "http://schemas.xmlsoap.org/soap/envelope/";
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Instance of the interface.
protected BaseControlHandler(ILogger logger)
{
Logger = logger;
}
+ ///
+ /// Gets the instance.
+ ///
protected ILogger Logger { get; }
+ ///
+ /// Processes a control request asynchronously.
+ ///
+ /// The .
+ /// Task{ControlResponse}.
public async Task ProcessControlRequestAsync(ControlRequest request)
{
try
@@ -178,7 +191,7 @@ private async Task ParseBodyTagAsync(XmlReader reader)
throw new EndOfStreamException("Stream ended but no control found.");
}
- private async Task ParseFirstBodyChildAsync(XmlReader reader, IDictionary headers)
+ private static async Task ParseFirstBodyChildAsync(XmlReader reader, IDictionary headers)
{
await reader.MoveToContentAsync().ConfigureAwait(false);
await reader.ReadAsync().ConfigureAwait(false);
@@ -198,9 +211,15 @@ private async Task ParseFirstBodyChildAsync(XmlReader reader, IDictionary
+ /// Writes the result.
+ ///
+ /// The method name.
+ /// The method parameters.
+ /// The .
protected abstract void WriteResult(string methodName, IReadOnlyDictionary methodParams, XmlWriter xmlWriter);
- private class ControlRequestInfo
+ private sealed class ControlRequestInfo
{
public ControlRequestInfo(string localName, string namespaceUri)
{
diff --git a/src/Jellyfin.Plugin.Dlna/Service/BaseService.cs b/src/Jellyfin.Plugin.Dlna/Service/BaseService.cs
index 4d700cf..24235b4 100644
--- a/src/Jellyfin.Plugin.Dlna/Service/BaseService.cs
+++ b/src/Jellyfin.Plugin.Dlna/Service/BaseService.cs
@@ -1,35 +1,66 @@
-#nullable disable
-#pragma warning disable CS1591
-
using System.Net.Http;
using Jellyfin.Plugin.Dlna.Eventing;
using Microsoft.Extensions.Logging;
namespace Jellyfin.Plugin.Dlna.Service;
+///
+/// Defines the .
+///
public class BaseService : IDlnaEventManager
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Instance of the interface.
+ /// Instance of the interface.
protected BaseService(ILogger logger, IHttpClientFactory httpClientFactory)
{
Logger = logger;
EventManager = new DlnaEventManager(logger, httpClientFactory);
}
+ ///
+ /// Gets the instance.
+ ///
protected IDlnaEventManager EventManager { get; }
+ ///
+ /// Gets the instance.
+ ///
protected ILogger Logger { get; }
- public EventSubscriptionResponse CancelEventSubscription(string subscriptionId)
+ ///
+ /// Cancels an event subscription.
+ ///
+ /// The subscription id.
+ /// EventSubscriptionResponse.
+ public EventSubscriptionResponse CancelEventSubscription(string? subscriptionId)
{
return EventManager.CancelEventSubscription(subscriptionId);
}
- public EventSubscriptionResponse RenewEventSubscription(string subscriptionId, string notificationType, string requestedTimeoutString, string callbackUrl)
+ ///
+ /// Renews an event subscription.
+ ///
+ /// The subscription id.
+ /// The notification type.
+ /// The requested timeout string.
+ /// The callback URL.
+ /// EventSubscriptionResponse.
+ public EventSubscriptionResponse RenewEventSubscription(string? subscriptionId, string? notificationType, string? requestedTimeoutString, string? callbackUrl)
{
return EventManager.RenewEventSubscription(subscriptionId, notificationType, requestedTimeoutString, callbackUrl);
}
- public EventSubscriptionResponse CreateEventSubscription(string notificationType, string requestedTimeoutString, string callbackUrl)
+ ///
+ /// Creates an event subscription.
+ ///
+ /// The notification type.
+ /// The requested timeout string.
+ /// The callback URL.
+ /// EventSubscriptionResponse.
+ public EventSubscriptionResponse CreateEventSubscription(string? notificationType, string? requestedTimeoutString, string? callbackUrl)
{
return EventManager.CreateEventSubscription(notificationType, requestedTimeoutString, callbackUrl);
}
diff --git a/src/Jellyfin.Plugin.Dlna/Service/ControlErrorHandler.cs b/src/Jellyfin.Plugin.Dlna/Service/ControlErrorHandler.cs
index 442be4e..9b2bbae 100644
--- a/src/Jellyfin.Plugin.Dlna/Service/ControlErrorHandler.cs
+++ b/src/Jellyfin.Plugin.Dlna/Service/ControlErrorHandler.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System;
using System.IO;
using System.Text;
@@ -8,10 +6,17 @@
namespace Jellyfin.Plugin.Dlna.Service;
+///
+/// Defines the .
+///
public static class ControlErrorHandler
{
private const string NsSoapEnv = "http://schemas.xmlsoap.org/soap/envelope/";
+ ///
+ /// Gets the response for an .
+ ///
+ /// The .
public static ControlResponse GetResponse(Exception ex)
{
var settings = new XmlWriterSettings
diff --git a/src/Jellyfin.Plugin.Dlna/Service/ServiceXmlBuilder.cs b/src/Jellyfin.Plugin.Dlna/Service/ServiceXmlBuilder.cs
index be599f2..a5b9aec 100644
--- a/src/Jellyfin.Plugin.Dlna/Service/ServiceXmlBuilder.cs
+++ b/src/Jellyfin.Plugin.Dlna/Service/ServiceXmlBuilder.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
using System.Collections.Generic;
using System.Security;
using System.Text;
@@ -7,9 +5,17 @@
namespace Jellyfin.Plugin.Dlna.Service;
-public class ServiceXmlBuilder
+///
+/// Defines the .
+///
+public static class ServiceXmlBuilder
{
- public string GetXml(IEnumerable actions, IEnumerable stateVariables)
+ ///
+ /// Gets the XML equivalent of the action and state variable inputs.
+ ///
+ /// The actions.
+ /// The state variables.
+ public static string GetXml(IEnumerable actions, IEnumerable stateVariables)
{
var builder = new StringBuilder();
diff --git a/src/Jellyfin.Plugin.Dlna/Ssdp/DeviceDiscovery.cs b/src/Jellyfin.Plugin.Dlna/Ssdp/DeviceDiscovery.cs
index 9f2a01d..cf5ef01 100644
--- a/src/Jellyfin.Plugin.Dlna/Ssdp/DeviceDiscovery.cs
+++ b/src/Jellyfin.Plugin.Dlna/Ssdp/DeviceDiscovery.cs
@@ -1,9 +1,6 @@
#nullable disable
-#pragma warning disable CS1591
-
using System;
-using System.Collections.Generic;
using System.Linq;
using Jellyfin.Data.Events;
using Jellyfin.Plugin.Dlna.Model;
@@ -12,9 +9,12 @@
namespace Jellyfin.Plugin.Dlna.Ssdp;
+///
+/// Defines the .
+///
public sealed class DeviceDiscovery : IDeviceDiscovery, IDisposable
{
- private readonly object _syncLock = new object();
+ private readonly object _syncLock = new();
private SsdpDeviceLocator _deviceLocator;
private ISsdpCommunicationsServer _commsServer;
@@ -51,7 +51,9 @@ public event EventHandler> DeviceDiscovered
///
public event EventHandler> DeviceLeft;
- // Call this method from somewhere in your code to start the search.
+ ///
+ /// Starts device discovery.
+ ///
public void Start(ISsdpCommunicationsServer communicationsServer)
{
_commsServer = communicationsServer;
@@ -94,7 +96,7 @@ private void OnDeviceLocatorDeviceAvailable(object sender, DeviceAvailableEventA
{
var originalHeaders = e.DiscoveredDevice.ResponseHeaders;
- var headerDict = originalHeaders is null ? new Dictionary>>() : originalHeaders.ToDictionary(i => i.Key, StringComparer.OrdinalIgnoreCase);
+ var headerDict = originalHeaders is null ? [] : originalHeaders.ToDictionary(i => i.Key, StringComparer.OrdinalIgnoreCase);
var headers = headerDict.ToDictionary(i => i.Key, i => i.Value.Value.FirstOrDefault(), StringComparer.OrdinalIgnoreCase);
@@ -113,7 +115,7 @@ private void OnDeviceLocatorDeviceUnavailable(object sender, DeviceUnavailableEv
{
var originalHeaders = e.DiscoveredDevice.ResponseHeaders;
- var headerDict = originalHeaders is null ? new Dictionary>>() : originalHeaders.ToDictionary(i => i.Key, StringComparer.OrdinalIgnoreCase);
+ var headerDict = originalHeaders is null ? [] : originalHeaders.ToDictionary(i => i.Key, StringComparer.OrdinalIgnoreCase);
var headers = headerDict.ToDictionary(i => i.Key, i => i.Value.Value.FirstOrDefault(), StringComparer.OrdinalIgnoreCase);
diff --git a/src/Jellyfin.Plugin.Dlna/Ssdp/SsdpExtensions.cs b/src/Jellyfin.Plugin.Dlna/Ssdp/SsdpExtensions.cs
index 21ecb22..a954797 100644
--- a/src/Jellyfin.Plugin.Dlna/Ssdp/SsdpExtensions.cs
+++ b/src/Jellyfin.Plugin.Dlna/Ssdp/SsdpExtensions.cs
@@ -1,12 +1,18 @@
-#pragma warning disable CS1591
-
using System.Linq;
using System.Xml.Linq;
namespace Jellyfin.Plugin.Dlna.Ssdp;
+///
+/// Defines the .
+///
public static class SsdpExtensions
{
+ ///
+ /// Gets the value.
+ ///
+ /// The .
+ /// The .
public static string? GetValue(this XElement container, XName name)
{
var node = container.Element(name);
@@ -14,6 +20,11 @@ public static class SsdpExtensions
return node?.Value;
}
+ ///
+ /// Gets the attribute value.
+ ///
+ /// The .
+ /// The .
public static string? GetAttributeValue(this XElement container, XName name)
{
var node = container.Attribute(name);
@@ -21,6 +32,11 @@ public static class SsdpExtensions
return node?.Value;
}
+ ///
+ /// Gets the descendant value.
+ ///
+ /// The .
+ /// The .
public static string? GetDescendantValue(this XElement container, XName name)
=> container.Descendants(name).FirstOrDefault()?.Value;
}
diff --git a/src/Rssdp/HttpParserBase.cs b/src/Rssdp/HttpParserBase.cs
index 1949a9d..9770ce3 100644
--- a/src/Rssdp/HttpParserBase.cs
+++ b/src/Rssdp/HttpParserBase.cs
@@ -46,7 +46,7 @@ protected virtual void Parse(T message, System.Net.Http.Headers.HttpHeaders head
throw new ArgumentException("data is not a valid request, it does not contain any CRLF/LF terminators.", nameof(data));
}
- using (var retVal = new ByteArrayContent(Array.Empty()))
+ using (var retVal = new ByteArrayContent([]))
{
var lines = data.Split(LineTerminators, StringSplitOptions.None);
diff --git a/src/Rssdp/IEnumerableExtensions.cs b/src/Rssdp/IEnumerableExtensions.cs
index 1f0daad..3a0f03c 100644
--- a/src/Rssdp/IEnumerableExtensions.cs
+++ b/src/Rssdp/IEnumerableExtensions.cs
@@ -28,7 +28,7 @@ public static IEnumerable SelectManyRecursive(this IEnumerable source,
public static IEnumerable EmptyIfNull(this IEnumerable source)
{
- return source ?? Enumerable.Empty();
+ return source ?? [];
}
}
}
diff --git a/src/Rssdp/SsdpCommunicationsServer.cs b/src/Rssdp/SsdpCommunicationsServer.cs
index c567002..9aa0203 100644
--- a/src/Rssdp/SsdpCommunicationsServer.cs
+++ b/src/Rssdp/SsdpCommunicationsServer.cs
@@ -3,7 +3,6 @@
using System.Linq;
using System.Net;
using System.Net.Http;
-using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
@@ -441,13 +440,13 @@ private void EnsureSendSocketCreated()
}
}
- private void ProcessMessage(string data, IPEndPoint endPoint, IPAddress receivedOnlocalIPAddress)
+ private void ProcessMessage(string data, IPEndPoint endPoint, IPAddress receivedOnLocalIPAddress)
{
// Responses start with the HTTP version, prefixed with HTTP/ while
// requests start with a method which can vary and might be one we haven't
// seen/don't know. We'll check if this message is a request or a response
// by checking for the HTTP/ prefix on the start of the message.
- _logger.LogDebug("Received data from {From} on {Port} at {Address}:\n{Data}", endPoint.Address, endPoint.Port, receivedOnlocalIPAddress, data);
+ _logger.LogDebug("Received data from {From} on {Port} at {Address}:\n{Data}", endPoint.Address, endPoint.Port, receivedOnLocalIPAddress, data);
if (data.StartsWith("HTTP/", StringComparison.OrdinalIgnoreCase))
{
HttpResponseMessage responseMessage = null;
@@ -462,7 +461,7 @@ private void ProcessMessage(string data, IPEndPoint endPoint, IPAddress received
if (responseMessage is not null)
{
- OnResponseReceived(responseMessage, endPoint, receivedOnlocalIPAddress);
+ OnResponseReceived(responseMessage, endPoint, receivedOnLocalIPAddress);
}
}
else
@@ -479,12 +478,12 @@ private void ProcessMessage(string data, IPEndPoint endPoint, IPAddress received
if (requestMessage is not null)
{
- OnRequestReceived(requestMessage, endPoint, receivedOnlocalIPAddress);
+ OnRequestReceived(requestMessage, endPoint, receivedOnLocalIPAddress);
}
}
}
- private void OnRequestReceived(HttpRequestMessage data, IPEndPoint remoteEndPoint, IPAddress receivedOnlocalIPAddress)
+ private void OnRequestReceived(HttpRequestMessage data, IPEndPoint remoteEndPoint, IPAddress receivedOnLocalIPAddress)
{
// SSDP specification says only * is currently used but other uri's might
// be implemented in the future and should be ignored unless understood.
@@ -495,7 +494,7 @@ private void OnRequestReceived(HttpRequestMessage data, IPEndPoint remoteEndPoin
}
var handlers = RequestReceived;
- handlers?.Invoke(this, new RequestReceivedEventArgs(data, remoteEndPoint, receivedOnlocalIPAddress));
+ handlers?.Invoke(this, new RequestReceivedEventArgs(data, remoteEndPoint, receivedOnLocalIPAddress));
}
private void OnResponseReceived(HttpResponseMessage data, IPEndPoint endPoint, IPAddress localIPAddress)