diff --git a/Emby.Dlna/Didl/DidlBuilder.cs b/Emby.Dlna/Didl/DidlBuilder.cs
index f668dc829a..5ed982876d 100644
--- a/Emby.Dlna/Didl/DidlBuilder.cs
+++ b/Emby.Dlna/Didl/DidlBuilder.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
#pragma warning disable CS1591
using System;
@@ -45,8 +43,8 @@ namespace Emby.Dlna.Didl
private readonly DeviceProfile _profile;
private readonly IImageProcessor _imageProcessor;
private readonly string _serverAddress;
- private readonly string _accessToken;
- private readonly User _user;
+ private readonly string? _accessToken;
+ private readonly User? _user;
private readonly IUserDataManager _userDataManager;
private readonly ILocalizationManager _localization;
private readonly IMediaSourceManager _mediaSourceManager;
@@ -56,10 +54,10 @@ namespace Emby.Dlna.Didl
public DidlBuilder(
DeviceProfile profile,
- User user,
+ User? user,
IImageProcessor imageProcessor,
string serverAddress,
- string accessToken,
+ string? accessToken,
IUserDataManager userDataManager,
ILocalizationManager localization,
IMediaSourceManager mediaSourceManager,
@@ -85,7 +83,7 @@ namespace Emby.Dlna.Didl
return url + "&dlnaheaders=true";
}
- public string GetItemDidl(BaseItem item, User user, BaseItem context, string deviceId, Filter filter, StreamInfo streamInfo)
+ public string GetItemDidl(BaseItem item, User? user, BaseItem? context, string deviceId, Filter filter, StreamInfo streamInfo)
{
var settings = new XmlWriterSettings
{
@@ -140,12 +138,12 @@ namespace Emby.Dlna.Didl
public void WriteItemElement(
XmlWriter writer,
BaseItem item,
- User user,
- BaseItem context,
+ User? user,
+ BaseItem? context,
StubType? contextStubType,
string deviceId,
Filter filter,
- StreamInfo streamInfo = null)
+ StreamInfo? streamInfo = null)
{
var clientId = GetClientId(item, null);
@@ -190,7 +188,7 @@ namespace Emby.Dlna.Didl
writer.WriteFullEndElement();
}
- private void AddVideoResource(XmlWriter writer, BaseItem video, string deviceId, Filter filter, StreamInfo streamInfo = null)
+ private void AddVideoResource(XmlWriter writer, BaseItem video, string deviceId, Filter filter, StreamInfo? streamInfo = null)
{
if (streamInfo is null)
{
@@ -203,7 +201,7 @@ namespace Emby.Dlna.Didl
Profile = _profile,
DeviceId = deviceId,
MaxBitrate = _profile.MaxStreamingBitrate
- });
+ }) ?? throw new InvalidOperationException("No optimal video stream found");
}
var targetWidth = streamInfo.TargetWidth;
@@ -315,7 +313,7 @@ namespace Emby.Dlna.Didl
var mediaSource = streamInfo.MediaSource;
- if (mediaSource.RunTimeTicks.HasValue)
+ if (mediaSource?.RunTimeTicks.HasValue == true)
{
writer.WriteAttributeString("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", CultureInfo.InvariantCulture));
}
@@ -410,7 +408,7 @@ namespace Emby.Dlna.Didl
writer.WriteFullEndElement();
}
- private string GetDisplayName(BaseItem item, StubType? itemStubType, BaseItem context)
+ private string GetDisplayName(BaseItem item, StubType? itemStubType, BaseItem? context)
{
if (itemStubType.HasValue)
{
@@ -452,7 +450,7 @@ namespace Emby.Dlna.Didl
/// The episode.
/// Current context.
/// Formatted name of the episode.
- private string GetEpisodeDisplayName(Episode episode, BaseItem context)
+ private string GetEpisodeDisplayName(Episode episode, BaseItem? context)
{
string[] components;
@@ -530,7 +528,7 @@ namespace Emby.Dlna.Didl
private bool NotNullOrWhiteSpace(string s) => !string.IsNullOrWhiteSpace(s);
- private void AddAudioResource(XmlWriter writer, BaseItem audio, string deviceId, Filter filter, StreamInfo streamInfo = null)
+ private void AddAudioResource(XmlWriter writer, BaseItem audio, string deviceId, Filter filter, StreamInfo? streamInfo = null)
{
writer.WriteStartElement(string.Empty, "res", NsDidl);
@@ -544,14 +542,14 @@ namespace Emby.Dlna.Didl
MediaSources = sources.ToArray(),
Profile = _profile,
DeviceId = deviceId
- });
+ }) ?? throw new InvalidOperationException("No optimal audio stream found");
}
var url = NormalizeDlnaMediaUrl(streamInfo.ToUrl(_serverAddress, _accessToken));
var mediaSource = streamInfo.MediaSource;
- if (mediaSource.RunTimeTicks.HasValue)
+ if (mediaSource?.RunTimeTicks is not null)
{
writer.WriteAttributeString("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", CultureInfo.InvariantCulture));
}
@@ -634,7 +632,7 @@ namespace Emby.Dlna.Didl
// 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)
+ public void WriteFolderElement(XmlWriter writer, BaseItem folder, StubType? stubType, BaseItem context, int childCount, Filter filter, string? requestedId = null)
{
writer.WriteStartElement(string.Empty, "container", NsDidl);
@@ -678,14 +676,14 @@ namespace Emby.Dlna.Didl
writer.WriteFullEndElement();
}
- private void AddSamsungBookmarkInfo(BaseItem item, User user, XmlWriter writer, StreamInfo streamInfo)
+ private void AddSamsungBookmarkInfo(BaseItem item, User? user, XmlWriter writer, StreamInfo? streamInfo)
{
if (!item.SupportsPositionTicksResume || item is Folder)
{
return;
}
- XmlAttribute secAttribute = null;
+ XmlAttribute? secAttribute = null;
foreach (var attribute in _profile.XmlRootAttributes)
{
if (string.Equals(attribute.Name, "xmlns:sec", StringComparison.OrdinalIgnoreCase))
@@ -695,8 +693,8 @@ namespace Emby.Dlna.Didl
}
}
- // Not a samsung device
- if (secAttribute is null)
+ // Not a samsung device or no user data
+ if (secAttribute is null || user is null)
{
return;
}
@@ -717,7 +715,7 @@ namespace Emby.Dlna.Didl
///
/// Adds fields used by both items and folders.
///
- private void AddCommonFields(BaseItem item, StubType? itemStubType, BaseItem context, XmlWriter writer, Filter filter)
+ 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
// MediaMonkey for example won't display content without a title
@@ -795,7 +793,7 @@ namespace Emby.Dlna.Didl
if (item.IsDisplayedAsFolder || stubType.HasValue)
{
- string classType = null;
+ string? classType = null;
if (!_profile.RequiresPlainFolders)
{
@@ -899,7 +897,7 @@ namespace Emby.Dlna.Didl
}
}
- private void AddGeneralProperties(BaseItem item, StubType? itemStubType, BaseItem context, XmlWriter writer, Filter filter)
+ private void AddGeneralProperties(BaseItem item, StubType? itemStubType, BaseItem? context, XmlWriter writer, Filter filter)
{
AddCommonFields(item, itemStubType, context, writer, filter);
@@ -975,7 +973,7 @@ namespace Emby.Dlna.Didl
private void AddCover(BaseItem item, StubType? stubType, XmlWriter writer)
{
- ImageDownloadInfo imageInfo = GetImageInfo(item);
+ ImageDownloadInfo? imageInfo = GetImageInfo(item);
if (imageInfo is null)
{
@@ -1073,7 +1071,7 @@ namespace Emby.Dlna.Didl
writer.WriteFullEndElement();
}
- private ImageDownloadInfo GetImageInfo(BaseItem item)
+ private ImageDownloadInfo? GetImageInfo(BaseItem item)
{
if (item.HasImage(ImageType.Primary))
{
@@ -1118,7 +1116,7 @@ namespace Emby.Dlna.Didl
return null;
}
- private BaseItem GetFirstParentWithImageBelowUserRoot(BaseItem item)
+ private BaseItem? GetFirstParentWithImageBelowUserRoot(BaseItem item)
{
if (item is null)
{
@@ -1148,7 +1146,7 @@ namespace Emby.Dlna.Didl
private ImageDownloadInfo GetImageInfo(BaseItem item, ImageType type)
{
var imageInfo = item.GetImageInfo(type, 0);
- string tag = null;
+ string? tag = null;
try
{
@@ -1250,7 +1248,7 @@ namespace Emby.Dlna.Didl
{
internal Guid ItemId { get; set; }
- internal string ImageTag { get; set; }
+ internal string? ImageTag { get; set; }
internal ImageType Type { get; set; }
@@ -1260,9 +1258,9 @@ namespace Emby.Dlna.Didl
internal bool IsDirectStream { get; set; }
- internal string Format { get; set; }
+ internal required string Format { get; set; }
- internal ItemImageInfo ItemImageInfo { get; set; }
+ internal required ItemImageInfo ItemImageInfo { get; set; }
}
}
}
diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs
index 9c476119df..d21cc69132 100644
--- a/Emby.Dlna/PlayTo/Device.cs
+++ b/Emby.Dlna/PlayTo/Device.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
#pragma warning disable CS1591
using System;
@@ -25,7 +23,7 @@ namespace Emby.Dlna.PlayTo
private readonly ILogger _logger;
private readonly object _timerLock = new object();
- private Timer _timer;
+ private Timer? _timer;
private int _muteVol;
private int _volume;
private DateTime _lastVolumeRefresh;
@@ -40,13 +38,13 @@ namespace Emby.Dlna.PlayTo
_logger = logger;
}
- public event EventHandler PlaybackStart;
+ public event EventHandler? PlaybackStart;
- public event EventHandler PlaybackProgress;
+ public event EventHandler? PlaybackProgress;
- public event EventHandler PlaybackStopped;
+ public event EventHandler? PlaybackStopped;
- public event EventHandler MediaChanged;
+ public event EventHandler? MediaChanged;
public DeviceInfo Properties { get; set; }
@@ -75,13 +73,13 @@ namespace Emby.Dlna.PlayTo
public bool IsStopped => TransportState == TransportState.STOPPED;
- public Action OnDeviceUnavailable { get; set; }
+ public Action? OnDeviceUnavailable { get; set; }
- private TransportCommands AvCommands { get; set; }
+ private TransportCommands? AvCommands { get; set; }
- private TransportCommands RendererCommands { get; set; }
+ private TransportCommands? RendererCommands { get; set; }
- public UBaseObject CurrentMediaInfo { get; private set; }
+ public UBaseObject? CurrentMediaInfo { get; private set; }
public void Start()
{
@@ -131,7 +129,7 @@ namespace Emby.Dlna.PlayTo
_volumeRefreshActive = true;
var time = immediate ? 100 : 10000;
- _timer.Change(time, Timeout.Infinite);
+ _timer?.Change(time, Timeout.Infinite);
}
}
@@ -149,7 +147,7 @@ namespace Emby.Dlna.PlayTo
_volumeRefreshActive = false;
- _timer.Change(Timeout.Infinite, Timeout.Infinite);
+ _timer?.Change(Timeout.Infinite, Timeout.Infinite);
}
}
@@ -199,7 +197,7 @@ namespace Emby.Dlna.PlayTo
}
}
- private DeviceService GetServiceRenderingControl()
+ private DeviceService? GetServiceRenderingControl()
{
var services = Properties.Services;
@@ -207,7 +205,7 @@ namespace Emby.Dlna.PlayTo
services.FirstOrDefault(s => (s.ServiceType ?? string.Empty).StartsWith("urn:schemas-upnp-org:service:RenderingControl", StringComparison.OrdinalIgnoreCase));
}
- private DeviceService GetAvTransportService()
+ private DeviceService? GetAvTransportService()
{
var services = Properties.Services;
@@ -240,7 +238,7 @@ namespace Emby.Dlna.PlayTo
Properties.BaseUrl,
service,
command.Name,
- rendererCommands.BuildPost(command, service.ServiceType, value),
+ rendererCommands!.BuildPost(command, service.ServiceType, value), // null checked above
cancellationToken: cancellationToken)
.ConfigureAwait(false);
@@ -265,12 +263,7 @@ namespace Emby.Dlna.PlayTo
return;
}
- var service = GetServiceRenderingControl();
-
- if (service is null)
- {
- throw new InvalidOperationException("Unable to find service");
- }
+ var service = GetServiceRenderingControl() ?? throw new InvalidOperationException("Unable to find service");
// Set it early and assume it will succeed
// Remote control will perform better
@@ -281,7 +274,7 @@ namespace Emby.Dlna.PlayTo
Properties.BaseUrl,
service,
command.Name,
- rendererCommands.BuildPost(command, service.ServiceType, value),
+ rendererCommands!.BuildPost(command, service.ServiceType, value), // null checked above
cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
@@ -296,26 +289,20 @@ namespace Emby.Dlna.PlayTo
return;
}
- var service = GetAvTransportService();
-
- if (service is null)
- {
- throw new InvalidOperationException("Unable to find service");
- }
-
+ var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
- avCommands.BuildPost(command, service.ServiceType, string.Format(CultureInfo.InvariantCulture, "{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"),
+ avCommands!.BuildPost(command, service.ServiceType, string.Format(CultureInfo.InvariantCulture, "{0:hh}:{0:mm}:{0:ss}", value), "REL_TIME"), // null checked above
cancellationToken: cancellationToken)
.ConfigureAwait(false);
RestartTimer(true);
}
- public async Task SetAvTransport(string url, string header, string metaData, CancellationToken cancellationToken)
+ public async Task SetAvTransport(string url, string? header, string metaData, CancellationToken cancellationToken)
{
var avCommands = await GetAVProtocolAsync(cancellationToken).ConfigureAwait(false);
@@ -335,14 +322,8 @@ namespace Emby.Dlna.PlayTo
{ "CurrentURIMetaData", CreateDidlMeta(metaData) }
};
- var service = GetAvTransportService();
-
- if (service is null)
- {
- throw new InvalidOperationException("Unable to find service");
- }
-
- var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary);
+ var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
+ var post = avCommands!.BuildPost(command, service.ServiceType, url, dictionary); // null checked above
await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync(
Properties.BaseUrl,
@@ -372,7 +353,7 @@ namespace Emby.Dlna.PlayTo
* 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)
+ public async Task SetNextAvTransport(string url, string? header, string metaData, CancellationToken cancellationToken = default)
{
var avCommands = await GetAVProtocolAsync(cancellationToken).ConfigureAwait(false);
@@ -380,7 +361,7 @@ namespace Emby.Dlna.PlayTo
_logger.LogDebug("{PropertyName} - SetNextAvTransport Uri: {Url} DlnaHeaders: {Header}", Properties.Name, url, header);
- var command = avCommands.ServiceActions.FirstOrDefault(c => string.Equals(c.Name, "SetNextAVTransportURI", StringComparison.OrdinalIgnoreCase));
+ var command = avCommands?.ServiceActions.FirstOrDefault(c => string.Equals(c.Name, "SetNextAVTransportURI", StringComparison.OrdinalIgnoreCase));
if (command is null)
{
return;
@@ -392,14 +373,8 @@ namespace Emby.Dlna.PlayTo
{ "NextURIMetaData", CreateDidlMeta(metaData) }
};
- var service = GetAvTransportService();
-
- if (service is null)
- {
- throw new InvalidOperationException("Unable to find service");
- }
-
- var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary);
+ var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
+ var post = avCommands!.BuildPost(command, service.ServiceType, url, dictionary); // null checked above
await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header, cancellationToken)
.ConfigureAwait(false);
@@ -423,12 +398,7 @@ namespace Emby.Dlna.PlayTo
return Task.CompletedTask;
}
- var service = GetAvTransportService();
- if (service is null)
- {
- throw new InvalidOperationException("Unable to find service");
- }
-
+ var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
return new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync(
Properties.BaseUrl,
service,
@@ -460,14 +430,13 @@ namespace Emby.Dlna.PlayTo
return;
}
- var service = GetAvTransportService();
-
+ var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
- avCommands.BuildPost(command, service.ServiceType, 1),
+ avCommands!.BuildPost(command, service.ServiceType, 1), // null checked above
cancellationToken: cancellationToken)
.ConfigureAwait(false);
@@ -484,14 +453,13 @@ namespace Emby.Dlna.PlayTo
return;
}
- var service = GetAvTransportService();
-
+ var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync(
Properties.BaseUrl,
service,
command.Name,
- avCommands.BuildPost(command, service.ServiceType, 1),
+ avCommands!.BuildPost(command, service.ServiceType, 1), // null checked above
cancellationToken: cancellationToken)
.ConfigureAwait(false);
@@ -500,7 +468,7 @@ namespace Emby.Dlna.PlayTo
RestartTimer(true);
}
- private async void TimerCallback(object sender)
+ private async void TimerCallback(object? sender)
{
if (_disposed)
{
@@ -623,7 +591,7 @@ namespace Emby.Dlna.PlayTo
Properties.BaseUrl,
service,
command.Name,
- rendererCommands.BuildPost(command, service.ServiceType),
+ rendererCommands!.BuildPost(command, service.ServiceType), // null checked above
cancellationToken: cancellationToken).ConfigureAwait(false);
if (result is null || result.Document is null)
@@ -673,7 +641,7 @@ namespace Emby.Dlna.PlayTo
Properties.BaseUrl,
service,
command.Name,
- rendererCommands.BuildPost(command, service.ServiceType),
+ rendererCommands!.BuildPost(command, service.ServiceType), // null checked above
cancellationToken: cancellationToken).ConfigureAwait(false);
if (result is null || result.Document is null)
@@ -728,7 +696,7 @@ namespace Emby.Dlna.PlayTo
return null;
}
- private async Task GetMediaInfo(TransportCommands avCommands, CancellationToken cancellationToken)
+ private async Task GetMediaInfo(TransportCommands avCommands, CancellationToken cancellationToken)
{
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMediaInfo");
if (command is null)
@@ -798,7 +766,7 @@ namespace Emby.Dlna.PlayTo
return null;
}
- private async Task<(bool Success, UBaseObject Track)> GetPositionInfo(TransportCommands avCommands, CancellationToken cancellationToken)
+ private async Task<(bool Success, UBaseObject? Track)> GetPositionInfo(TransportCommands avCommands, CancellationToken cancellationToken)
{
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetPositionInfo");
if (command is null)
@@ -871,7 +839,7 @@ namespace Emby.Dlna.PlayTo
return (true, null);
}
- XElement uPnpResponse = null;
+ XElement? uPnpResponse = null;
try
{
@@ -895,7 +863,7 @@ namespace Emby.Dlna.PlayTo
return (true, uTrack);
}
- private XElement ParseResponse(string xml)
+ private XElement? ParseResponse(string xml)
{
// Handle different variations sent back by devices.
try
@@ -929,7 +897,7 @@ namespace Emby.Dlna.PlayTo
return null;
}
- private static UBaseObject CreateUBaseObject(XElement container, string trackUri)
+ private static UBaseObject CreateUBaseObject(XElement? container, string? trackUri)
{
ArgumentNullException.ThrowIfNull(container);
@@ -972,7 +940,7 @@ namespace Emby.Dlna.PlayTo
return new string[4];
}
- private async Task GetAVProtocolAsync(CancellationToken cancellationToken)
+ private async Task GetAVProtocolAsync(CancellationToken cancellationToken)
{
if (AvCommands is not null)
{
@@ -1004,7 +972,7 @@ namespace Emby.Dlna.PlayTo
return AvCommands;
}
- private async Task GetRenderingProtocolAsync(CancellationToken cancellationToken)
+ private async Task GetRenderingProtocolAsync(CancellationToken cancellationToken)
{
if (RendererCommands is not null)
{
@@ -1054,7 +1022,7 @@ namespace Emby.Dlna.PlayTo
return baseUrl + url;
}
- public static async Task CreateuPnpDeviceAsync(Uri url, IHttpClientFactory httpClientFactory, ILogger logger, CancellationToken cancellationToken)
+ public static async Task CreateuPnpDeviceAsync(Uri url, IHttpClientFactory httpClientFactory, ILogger logger, CancellationToken cancellationToken)
{
var ssdpHttpClient = new DlnaHttpClient(logger, httpClientFactory);
@@ -1287,7 +1255,7 @@ namespace Emby.Dlna.PlayTo
}
_timer = null;
- Properties = null;
+ Properties = null!;
_disposed = true;
}
diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs
index 86db363374..b1ad15cdc9 100644
--- a/Emby.Dlna/PlayTo/PlayToController.cs
+++ b/Emby.Dlna/PlayTo/PlayToController.cs
@@ -42,7 +42,7 @@ namespace Emby.Dlna.PlayTo
private readonly IDeviceDiscovery _deviceDiscovery;
private readonly string _serverAddress;
- private readonly string _accessToken;
+ private readonly string? _accessToken;
private readonly List _playlist = new List();
private Device _device;
@@ -59,7 +59,7 @@ namespace Emby.Dlna.PlayTo
IUserManager userManager,
IImageProcessor imageProcessor,
string serverAddress,
- string accessToken,
+ string? accessToken,
IDeviceDiscovery deviceDiscovery,
IUserDataManager userDataManager,
ILocalizationManager localization,
diff --git a/Emby.Dlna/PlayTo/PlayToManager.cs b/Emby.Dlna/PlayTo/PlayToManager.cs
index 241dff5ae3..ef617422c4 100644
--- a/Emby.Dlna/PlayTo/PlayToManager.cs
+++ b/Emby.Dlna/PlayTo/PlayToManager.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
#pragma warning disable CS1591
using System;
@@ -67,7 +65,7 @@ namespace Emby.Dlna.PlayTo
_deviceDiscovery.DeviceDiscovered += OnDeviceDiscoveryDeviceDiscovered;
}
- private async void OnDeviceDiscoveryDeviceDiscovered(object sender, GenericEventArgs e)
+ private async void OnDeviceDiscoveryDeviceDiscovered(object? sender, GenericEventArgs e)
{
if (_disposed)
{
@@ -76,12 +74,12 @@ namespace Emby.Dlna.PlayTo
var info = e.Argument;
- if (!info.Headers.TryGetValue("USN", out string usn))
+ if (!info.Headers.TryGetValue("USN", out string? usn))
{
usn = string.Empty;
}
- if (!info.Headers.TryGetValue("NT", out string nt))
+ if (!info.Headers.TryGetValue("NT", out string? nt))
{
nt = string.Empty;
}
@@ -161,7 +159,7 @@ namespace Emby.Dlna.PlayTo
var uri = info.Location;
_logger.LogDebug("Attempting to create PlayToController from location {0}", uri);
- if (info.Headers.TryGetValue("USN", out string uuid))
+ if (info.Headers.TryGetValue("USN", out string? uuid))
{
uuid = GetUuid(uuid);
}
diff --git a/Emby.Server.Implementations/Plugins/PluginManager.cs b/Emby.Server.Implementations/Plugins/PluginManager.cs
index 48584ae0cb..1303012e1a 100644
--- a/Emby.Server.Implementations/Plugins/PluginManager.cs
+++ b/Emby.Server.Implementations/Plugins/PluginManager.cs
@@ -677,7 +677,7 @@ namespace Emby.Server.Implementations.Plugins
}
catch (JsonException ex)
{
- _logger.LogError(ex, "Error deserializing {Json}.", Encoding.UTF8.GetString(data!));
+ _logger.LogError(ex, "Error deserializing {Json}.", Encoding.UTF8.GetString(data));
}
if (manifest is not null)
diff --git a/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs b/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs
index 62b70ce53c..10326363a9 100644
--- a/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs
+++ b/MediaBrowser.Controller/Drawing/ImageProcessorExtensions.cs
@@ -1,5 +1,3 @@
-#nullable disable
-
#pragma warning disable CS1591
using MediaBrowser.Controller.Entities;
@@ -9,12 +7,12 @@ namespace MediaBrowser.Controller.Drawing
{
public static class ImageProcessorExtensions
{
- public static string GetImageCacheTag(this IImageProcessor processor, BaseItem item, ImageType imageType)
+ public static string? GetImageCacheTag(this IImageProcessor processor, BaseItem item, ImageType imageType)
{
return processor.GetImageCacheTag(item, imageType, 0);
}
- public static string GetImageCacheTag(this IImageProcessor processor, BaseItem item, ImageType imageType, int imageIndex)
+ public static string? GetImageCacheTag(this IImageProcessor processor, BaseItem item, ImageType imageType, int imageIndex)
{
var imageInfo = item.GetImageInfo(imageType, imageIndex);
diff --git a/MediaBrowser.Model/Dlna/DeviceProfile.cs b/MediaBrowser.Model/Dlna/DeviceProfile.cs
index b7c23669df..07bb002eae 100644
--- a/MediaBrowser.Model/Dlna/DeviceProfile.cs
+++ b/MediaBrowser.Model/Dlna/DeviceProfile.cs
@@ -314,7 +314,7 @@ namespace MediaBrowser.Model.Dlna
/// The audio sample rate.
/// The audio bit depth.
/// The .
- public ResponseProfile? GetAudioMediaProfile(string container, string? audioCodec, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth)
+ public ResponseProfile? GetAudioMediaProfile(string? container, string? audioCodec, int? audioChannels, int? audioBitrate, int? audioSampleRate, int? audioBitDepth)
{
foreach (var i in ResponseProfiles)
{
@@ -438,14 +438,14 @@ namespace MediaBrowser.Model.Dlna
/// True if Avc.
/// The .
public ResponseProfile? GetVideoMediaProfile(
- string container,
+ string? container,
string? audioCodec,
string? videoCodec,
int? width,
int? height,
int? bitDepth,
int? videoBitrate,
- string videoProfile,
+ string? videoProfile,
VideoRangeType videoRangeType,
double? videoLevel,
float? videoFramerate,
@@ -456,7 +456,7 @@ namespace MediaBrowser.Model.Dlna
int? refFrames,
int? numVideoStreams,
int? numAudioStreams,
- string videoCodecTag,
+ string? videoCodecTag,
bool? isAvc)
{
foreach (var i in ResponseProfiles)
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index adfe0da281..889e2494a0 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -179,15 +179,9 @@ namespace MediaBrowser.Model.Dlna
{
ValidateMediaOptions(options, true);
- var mediaSources = new List();
- foreach (var mediaSourceInfo in options.MediaSources)
- {
- if (string.IsNullOrEmpty(options.MediaSourceId)
- || string.Equals(mediaSourceInfo.Id, options.MediaSourceId, StringComparison.OrdinalIgnoreCase))
- {
- mediaSources.Add(mediaSourceInfo);
- }
- }
+ var mediaSources = string.IsNullOrEmpty(options.MediaSourceId)
+ ? options.MediaSources
+ : options.MediaSources.Where(x => string.Equals(x.Id, options.MediaSourceId, StringComparison.OrdinalIgnoreCase));
var streams = new List();
foreach (var mediaSourceInfo in mediaSources)
@@ -216,7 +210,7 @@ namespace MediaBrowser.Model.Dlna
return streams.OrderBy(i =>
{
// Nothing beats direct playing a file
- if (i.PlayMethod == PlayMethod.DirectPlay && i.MediaSource.Protocol == MediaProtocol.File)
+ if (i.PlayMethod == PlayMethod.DirectPlay && i.MediaSource?.Protocol == MediaProtocol.File)
{
return 0;
}
@@ -235,7 +229,7 @@ namespace MediaBrowser.Model.Dlna
}
}).ThenBy(i =>
{
- switch (i.MediaSource.Protocol)
+ switch (i.MediaSource?.Protocol)
{
case MediaProtocol.File:
return 0;
@@ -246,7 +240,7 @@ namespace MediaBrowser.Model.Dlna
{
if (maxBitrate > 0)
{
- if (i.MediaSource.Bitrate.HasValue)
+ if (i.MediaSource?.Bitrate is not null)
{
return Math.Abs(i.MediaSource.Bitrate.Value - maxBitrate);
}
@@ -585,10 +579,10 @@ namespace MediaBrowser.Model.Dlna
MediaSource = item,
RunTimeTicks = item.RunTimeTicks,
Context = options.Context,
- DeviceProfile = options.Profile
+ DeviceProfile = options.Profile,
+ SubtitleStreamIndex = options.SubtitleStreamIndex ?? GetDefaultSubtitleStreamIndex(item, options.Profile.SubtitleProfiles)
};
- playlistItem.SubtitleStreamIndex = options.SubtitleStreamIndex ?? GetDefaultSubtitleStreamIndex(item, options.Profile.SubtitleProfiles);
var subtitleStream = playlistItem.SubtitleStreamIndex.HasValue ? item.GetMediaStream(MediaStreamType.Subtitle, playlistItem.SubtitleStreamIndex.Value) : null;
var audioStream = item.GetDefaultAudioStream(options.AudioStreamIndex ?? item.DefaultAudioStreamIndex);
@@ -659,7 +653,8 @@ namespace MediaBrowser.Model.Dlna
if (audioStreamIndex.HasValue)
{
playlistItem.AudioStreamIndex = audioStreamIndex;
- playlistItem.AudioCodecs = new[] { item.GetMediaStream(MediaStreamType.Audio, audioStreamIndex.Value)?.Codec };
+ var audioCodec = item.GetMediaStream(MediaStreamType.Audio, audioStreamIndex.Value)?.Codec;
+ playlistItem.AudioCodecs = audioCodec is null ? Array.Empty() : new[] { audioCodec };
}
}
else if (directPlay == PlayMethod.DirectStream)
@@ -842,7 +837,7 @@ namespace MediaBrowser.Model.Dlna
if (videoStream is not null && videoStream.Level != 0)
{
- playlistItem.SetOption(qualifier, "level", videoStream.Level.ToString());
+ playlistItem.SetOption(qualifier, "level", videoStream.Level.ToString() ?? string.Empty);
}
// Prefer matching audio codecs, could do better here
@@ -871,7 +866,7 @@ namespace MediaBrowser.Model.Dlna
// Copy matching audio codec options
playlistItem.AudioSampleRate = audioStream.SampleRate;
- playlistItem.SetOption(qualifier, "audiochannels", audioStream.Channels.ToString());
+ playlistItem.SetOption(qualifier, "audiochannels", audioStream.Channels.ToString() ?? string.Empty);
if (!string.IsNullOrEmpty(audioStream.Profile))
{
@@ -880,7 +875,7 @@ namespace MediaBrowser.Model.Dlna
if (audioStream.Level != 0)
{
- playlistItem.SetOption(audioStream.Codec, "level", audioStream.Level.ToString());
+ playlistItem.SetOption(audioStream.Codec, "level", audioStream.Level.ToString() ?? string.Empty);
}
}
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index 00543616d1..fc146df306 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -1,9 +1,9 @@
-#nullable disable
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;
+using System.Linq;
using Jellyfin.Data.Enums;
using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto;
@@ -34,9 +34,9 @@ namespace MediaBrowser.Model.Dlna
public DlnaProfileType MediaType { get; set; }
- public string Container { get; set; }
+ public string? Container { get; set; }
- public string SubProtocol { get; set; }
+ public string? SubProtocol { get; set; }
public long StartPositionTicks { get; set; }
@@ -80,11 +80,11 @@ namespace MediaBrowser.Model.Dlna
public float? MaxFramerate { get; set; }
- public DeviceProfile DeviceProfile { get; set; }
+ public required DeviceProfile DeviceProfile { get; set; }
- public string DeviceProfileId { get; set; }
+ public string? DeviceProfileId { get; set; }
- public string DeviceId { get; set; }
+ public string? DeviceId { get; set; }
public long? RunTimeTicks { get; set; }
@@ -92,21 +92,21 @@ namespace MediaBrowser.Model.Dlna
public bool EstimateContentLength { get; set; }
- public MediaSourceInfo MediaSource { get; set; }
+ public MediaSourceInfo? MediaSource { get; set; }
public string[] SubtitleCodecs { get; set; }
public SubtitleDeliveryMethod SubtitleDeliveryMethod { get; set; }
- public string SubtitleFormat { get; set; }
+ public string? SubtitleFormat { get; set; }
- public string PlaySessionId { get; set; }
+ public string? PlaySessionId { get; set; }
public TranscodeReason TranscodeReasons { get; set; }
public Dictionary StreamOptions { get; private set; }
- public string MediaSourceId => MediaSource?.Id;
+ public string? MediaSourceId => MediaSource?.Id;
public bool IsDirectStream => MediaSource?.VideoType is not (VideoType.Dvd or VideoType.BluRay)
&& PlayMethod is PlayMethod.DirectStream or PlayMethod.DirectPlay;
@@ -114,12 +114,12 @@ namespace MediaBrowser.Model.Dlna
///
/// Gets the audio stream that will be used.
///
- public MediaStream TargetAudioStream => MediaSource?.GetDefaultAudioStream(AudioStreamIndex);
+ public MediaStream? TargetAudioStream => MediaSource?.GetDefaultAudioStream(AudioStreamIndex);
///
/// Gets the video stream that will be used.
///
- public MediaStream TargetVideoStream => MediaSource?.VideoStream;
+ public MediaStream? TargetVideoStream => MediaSource?.VideoStream;
///
/// Gets the audio sample rate that will be in the output stream.
@@ -259,7 +259,7 @@ namespace MediaBrowser.Model.Dlna
///
/// Gets the audio sample rate that will be in the output stream.
///
- public string TargetVideoProfile
+ public string? TargetVideoProfile
{
get
{
@@ -307,7 +307,7 @@ namespace MediaBrowser.Model.Dlna
/// Gets the target video codec tag.
///
/// The target video codec tag.
- public string TargetVideoCodecTag
+ public string? TargetVideoCodecTag
{
get
{
@@ -364,7 +364,7 @@ namespace MediaBrowser.Model.Dlna
{
var stream = TargetAudioStream;
- string inputCodec = stream?.Codec;
+ string? inputCodec = stream?.Codec;
if (IsDirectStream)
{
@@ -389,7 +389,7 @@ namespace MediaBrowser.Model.Dlna
{
var stream = TargetVideoStream;
- string inputCodec = stream?.Codec;
+ string? inputCodec = stream?.Codec;
if (IsDirectStream)
{
@@ -417,7 +417,7 @@ namespace MediaBrowser.Model.Dlna
{
if (IsDirectStream)
{
- return MediaSource.Size;
+ return MediaSource?.Size;
}
if (RunTimeTicks.HasValue)
@@ -580,7 +580,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- public void SetOption(string qualifier, string name, string value)
+ public void SetOption(string? qualifier, string name, string value)
{
if (string.IsNullOrEmpty(qualifier))
{
@@ -597,7 +597,7 @@ namespace MediaBrowser.Model.Dlna
StreamOptions[name] = value;
}
- public string GetOption(string qualifier, string name)
+ public string? GetOption(string? qualifier, string name)
{
var value = GetOption(qualifier + "-" + name);
@@ -609,7 +609,7 @@ namespace MediaBrowser.Model.Dlna
return value;
}
- public string GetOption(string name)
+ public string? GetOption(string name)
{
if (StreamOptions.TryGetValue(name, out var value))
{
@@ -619,7 +619,7 @@ namespace MediaBrowser.Model.Dlna
return null;
}
- public string ToUrl(string baseUrl, string accessToken)
+ public string ToUrl(string baseUrl, string? accessToken)
{
ArgumentException.ThrowIfNullOrEmpty(baseUrl);
@@ -686,7 +686,7 @@ namespace MediaBrowser.Model.Dlna
return string.Format(CultureInfo.InvariantCulture, "{0}/videos/{1}/stream{2}?{3}", baseUrl, ItemId, extension, queryString);
}
- private static IEnumerable BuildParams(StreamInfo item, string accessToken)
+ private static IEnumerable BuildParams(StreamInfo item, string? accessToken)
{
var list = new List();
@@ -730,7 +730,7 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("PlaySessionId", item.PlaySessionId ?? string.Empty));
list.Add(new NameValuePair("api_key", accessToken ?? string.Empty));
- string liveStreamId = item.MediaSource?.LiveStreamId;
+ string? liveStreamId = item.MediaSource?.LiveStreamId;
list.Add(new NameValuePair("LiveStreamId", liveStreamId ?? string.Empty));
list.Add(new NameValuePair("SubtitleMethod", item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External ? item.SubtitleDeliveryMethod.ToString() : string.Empty));
@@ -772,7 +772,7 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("RequireAvc", item.RequireAvc.ToString(CultureInfo.InvariantCulture).ToLowerInvariant()));
}
- list.Add(new NameValuePair("Tag", item.MediaSource.ETag ?? string.Empty));
+ list.Add(new NameValuePair("Tag", item.MediaSource?.ETag ?? string.Empty));
string subtitleCodecs = item.SubtitleCodecs.Length == 0 ?
string.Empty :
@@ -816,13 +816,18 @@ namespace MediaBrowser.Model.Dlna
return list;
}
- public IEnumerable GetSubtitleProfiles(ITranscoderSupport transcoderSupport, bool includeSelectedTrackOnly, string baseUrl, string accessToken)
+ public IEnumerable GetSubtitleProfiles(ITranscoderSupport transcoderSupport, bool includeSelectedTrackOnly, string baseUrl, string? accessToken)
{
return GetSubtitleProfiles(transcoderSupport, includeSelectedTrackOnly, false, baseUrl, accessToken);
}
- public IEnumerable GetSubtitleProfiles(ITranscoderSupport transcoderSupport, bool includeSelectedTrackOnly, bool enableAllProfiles, string baseUrl, string accessToken)
+ public IEnumerable GetSubtitleProfiles(ITranscoderSupport transcoderSupport, bool includeSelectedTrackOnly, bool enableAllProfiles, string baseUrl, string? accessToken)
{
+ if (MediaSource is null)
+ {
+ return Enumerable.Empty();
+ }
+
var list = new List();
// HLS will preserve timestamps so we can just grab the full subtitle stream
@@ -856,27 +861,36 @@ namespace MediaBrowser.Model.Dlna
return list;
}
- private void AddSubtitleProfiles(List list, MediaStream stream, ITranscoderSupport transcoderSupport, bool enableAllProfiles, string baseUrl, string accessToken, long startPositionTicks)
+ private void AddSubtitleProfiles(List list, MediaStream stream, ITranscoderSupport transcoderSupport, bool enableAllProfiles, string baseUrl, string? accessToken, long startPositionTicks)
{
if (enableAllProfiles)
{
foreach (var profile in DeviceProfile.SubtitleProfiles)
{
var info = GetSubtitleStreamInfo(stream, baseUrl, accessToken, startPositionTicks, new[] { profile }, transcoderSupport);
-
- list.Add(info);
+ if (info is not null)
+ {
+ list.Add(info);
+ }
}
}
else
{
var info = GetSubtitleStreamInfo(stream, baseUrl, accessToken, startPositionTicks, DeviceProfile.SubtitleProfiles, transcoderSupport);
-
- list.Add(info);
+ if (info is not null)
+ {
+ list.Add(info);
+ }
}
}
- private SubtitleStreamInfo GetSubtitleStreamInfo(MediaStream stream, string baseUrl, string accessToken, long startPositionTicks, SubtitleProfile[] subtitleProfiles, ITranscoderSupport transcoderSupport)
+ private SubtitleStreamInfo? GetSubtitleStreamInfo(MediaStream stream, string baseUrl, string? accessToken, long startPositionTicks, SubtitleProfile[] subtitleProfiles, ITranscoderSupport transcoderSupport)
{
+ if (MediaSource is null)
+ {
+ return null;
+ }
+
var subtitleProfile = StreamBuilder.GetSubtitleProfile(MediaSource, stream, subtitleProfiles, PlayMethod, transcoderSupport, Container, SubProtocol);
var info = new SubtitleStreamInfo
{
@@ -920,7 +934,7 @@ namespace MediaBrowser.Model.Dlna
return info;
}
- public int? GetTargetVideoBitDepth(string codec)
+ public int? GetTargetVideoBitDepth(string? codec)
{
var value = GetOption(codec, "videobitdepth");
@@ -932,7 +946,7 @@ namespace MediaBrowser.Model.Dlna
return null;
}
- public int? GetTargetAudioBitDepth(string codec)
+ public int? GetTargetAudioBitDepth(string? codec)
{
var value = GetOption(codec, "audiobitdepth");
@@ -944,7 +958,7 @@ namespace MediaBrowser.Model.Dlna
return null;
}
- public double? GetTargetVideoLevel(string codec)
+ public double? GetTargetVideoLevel(string? codec)
{
var value = GetOption(codec, "level");
@@ -956,7 +970,7 @@ namespace MediaBrowser.Model.Dlna
return null;
}
- public int? GetTargetRefFrames(string codec)
+ public int? GetTargetRefFrames(string? codec)
{
var value = GetOption(codec, "maxrefframes");
@@ -968,7 +982,7 @@ namespace MediaBrowser.Model.Dlna
return null;
}
- public int? GetTargetAudioChannels(string codec)
+ public int? GetTargetAudioChannels(string? codec)
{
var defaultValue = GlobalMaxAudioChannels ?? TranscodingMaxAudioChannels;
@@ -988,7 +1002,7 @@ namespace MediaBrowser.Model.Dlna
private int? GetMediaStreamCount(MediaStreamType type, int limit)
{
- var count = MediaSource.GetStreamCount(type);
+ var count = MediaSource?.GetStreamCount(type);
if (count.HasValue)
{
diff --git a/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs b/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs
index 4c727428b4..210ce4a47f 100644
--- a/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs
+++ b/tests/Jellyfin.Model.Tests/Dlna/StreamBuilderTests.cs
@@ -351,11 +351,11 @@ namespace Jellyfin.Model.Tests
// Assert.Contains(uri.Extension, containers);
// Check expected video codec (1)
- Assert.Contains(targetVideoStream.Codec, streamInfo.TargetVideoCodec);
+ Assert.Contains(targetVideoStream?.Codec, streamInfo.TargetVideoCodec);
Assert.Single(streamInfo.TargetVideoCodec);
// Check expected audio codecs (1)
- Assert.Contains(targetAudioStream.Codec, streamInfo.TargetAudioCodec);
+ Assert.Contains(targetAudioStream?.Codec, streamInfo.TargetAudioCodec);
Assert.Single(streamInfo.TargetAudioCodec);
// Assert.Single(val.AudioCodecs);
@@ -410,13 +410,13 @@ namespace Jellyfin.Model.Tests
else
{
// Check expected video codec (1)
- Assert.Contains(targetVideoStream.Codec, streamInfo.TargetVideoCodec);
+ Assert.Contains(targetVideoStream?.Codec, streamInfo.TargetVideoCodec);
Assert.Single(streamInfo.TargetVideoCodec);
if (transcodeMode.Equals("DirectStream", StringComparison.Ordinal))
{
// Check expected audio codecs (1)
- if (!targetAudioStream.IsExternal)
+ if (targetAudioStream?.IsExternal == false)
{
// Check expected audio codecs (1)
if (streamInfo.TranscodeReasons.HasFlag(TranscodeReason.ContainerNotSupported))
@@ -432,7 +432,7 @@ namespace Jellyfin.Model.Tests
else if (transcodeMode.Equals("Remux", StringComparison.Ordinal))
{
// Check expected audio codecs (1)
- Assert.Contains(targetAudioStream.Codec, streamInfo.AudioCodecs);
+ Assert.Contains(targetAudioStream?.Codec, streamInfo.AudioCodecs);
Assert.Single(streamInfo.AudioCodecs);
}
@@ -440,10 +440,10 @@ namespace Jellyfin.Model.Tests
var videoStream = targetVideoStream;
Assert.False(streamInfo.EstimateContentLength);
Assert.Equal(TranscodeSeekInfo.Auto, streamInfo.TranscodeSeekInfo);
- Assert.Contains(videoStream.Profile?.ToLowerInvariant() ?? string.Empty, streamInfo.TargetVideoProfile?.Split(",").Select(s => s.ToLowerInvariant()) ?? Array.Empty());
- Assert.Equal(videoStream.Level, streamInfo.TargetVideoLevel);
- Assert.Equal(videoStream.BitDepth, streamInfo.TargetVideoBitDepth);
- Assert.InRange(streamInfo.VideoBitrate.GetValueOrDefault(), videoStream.BitRate.GetValueOrDefault(), int.MaxValue);
+ Assert.Contains(videoStream?.Profile?.ToLowerInvariant() ?? string.Empty, streamInfo.TargetVideoProfile?.Split(",").Select(s => s.ToLowerInvariant()) ?? Array.Empty());
+ Assert.Equal(videoStream?.Level, streamInfo.TargetVideoLevel);
+ Assert.Equal(videoStream?.BitDepth, streamInfo.TargetVideoBitDepth);
+ Assert.InRange(streamInfo.VideoBitrate.GetValueOrDefault(), videoStream?.BitRate.GetValueOrDefault() ?? 0, int.MaxValue);
// Audio codec not supported
if ((why & TranscodeReason.AudioCodecNotSupported) != 0)
@@ -452,7 +452,7 @@ namespace Jellyfin.Model.Tests
if (options.AudioStreamIndex >= 0)
{
// TODO:fixme
- if (!targetAudioStream.IsExternal)
+ if (targetAudioStream?.IsExternal == false)
{
Assert.DoesNotContain(targetAudioStream.Codec, streamInfo.AudioCodecs);
}