Merge pull request #10056 from Bond-009/nullable2

This commit is contained in:
Bond-009 2023-09-12 11:09:20 +02:00 committed by GitHub
commit 3087881d93
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 161 additions and 190 deletions

View File

@ -1,5 +1,3 @@
#nullable disable
#pragma warning disable CS1591 #pragma warning disable CS1591
using System; using System;
@ -45,8 +43,8 @@ namespace Emby.Dlna.Didl
private readonly DeviceProfile _profile; private readonly DeviceProfile _profile;
private readonly IImageProcessor _imageProcessor; private readonly IImageProcessor _imageProcessor;
private readonly string _serverAddress; private readonly string _serverAddress;
private readonly string _accessToken; private readonly string? _accessToken;
private readonly User _user; private readonly User? _user;
private readonly IUserDataManager _userDataManager; private readonly IUserDataManager _userDataManager;
private readonly ILocalizationManager _localization; private readonly ILocalizationManager _localization;
private readonly IMediaSourceManager _mediaSourceManager; private readonly IMediaSourceManager _mediaSourceManager;
@ -56,10 +54,10 @@ namespace Emby.Dlna.Didl
public DidlBuilder( public DidlBuilder(
DeviceProfile profile, DeviceProfile profile,
User user, User? user,
IImageProcessor imageProcessor, IImageProcessor imageProcessor,
string serverAddress, string serverAddress,
string accessToken, string? accessToken,
IUserDataManager userDataManager, IUserDataManager userDataManager,
ILocalizationManager localization, ILocalizationManager localization,
IMediaSourceManager mediaSourceManager, IMediaSourceManager mediaSourceManager,
@ -85,7 +83,7 @@ namespace Emby.Dlna.Didl
return url + "&dlnaheaders=true"; 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 var settings = new XmlWriterSettings
{ {
@ -140,12 +138,12 @@ namespace Emby.Dlna.Didl
public void WriteItemElement( public void WriteItemElement(
XmlWriter writer, XmlWriter writer,
BaseItem item, BaseItem item,
User user, User? user,
BaseItem context, BaseItem? context,
StubType? contextStubType, StubType? contextStubType,
string deviceId, string deviceId,
Filter filter, Filter filter,
StreamInfo streamInfo = null) StreamInfo? streamInfo = null)
{ {
var clientId = GetClientId(item, null); var clientId = GetClientId(item, null);
@ -190,7 +188,7 @@ namespace Emby.Dlna.Didl
writer.WriteFullEndElement(); 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) if (streamInfo is null)
{ {
@ -203,7 +201,7 @@ namespace Emby.Dlna.Didl
Profile = _profile, Profile = _profile,
DeviceId = deviceId, DeviceId = deviceId,
MaxBitrate = _profile.MaxStreamingBitrate MaxBitrate = _profile.MaxStreamingBitrate
}); }) ?? throw new InvalidOperationException("No optimal video stream found");
} }
var targetWidth = streamInfo.TargetWidth; var targetWidth = streamInfo.TargetWidth;
@ -315,7 +313,7 @@ namespace Emby.Dlna.Didl
var mediaSource = streamInfo.MediaSource; 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)); writer.WriteAttributeString("duration", TimeSpan.FromTicks(mediaSource.RunTimeTicks.Value).ToString("c", CultureInfo.InvariantCulture));
} }
@ -410,7 +408,7 @@ namespace Emby.Dlna.Didl
writer.WriteFullEndElement(); writer.WriteFullEndElement();
} }
private string GetDisplayName(BaseItem item, StubType? itemStubType, BaseItem context) private string GetDisplayName(BaseItem item, StubType? itemStubType, BaseItem? context)
{ {
if (itemStubType.HasValue) if (itemStubType.HasValue)
{ {
@ -452,7 +450,7 @@ namespace Emby.Dlna.Didl
/// <param name="episode">The episode.</param> /// <param name="episode">The episode.</param>
/// <param name="context">Current context.</param> /// <param name="context">Current context.</param>
/// <returns>Formatted name of the episode.</returns> /// <returns>Formatted name of the episode.</returns>
private string GetEpisodeDisplayName(Episode episode, BaseItem context) private string GetEpisodeDisplayName(Episode episode, BaseItem? context)
{ {
string[] components; string[] components;
@ -530,7 +528,7 @@ namespace Emby.Dlna.Didl
private bool NotNullOrWhiteSpace(string s) => !string.IsNullOrWhiteSpace(s); 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); writer.WriteStartElement(string.Empty, "res", NsDidl);
@ -544,14 +542,14 @@ namespace Emby.Dlna.Didl
MediaSources = sources.ToArray(), MediaSources = sources.ToArray(),
Profile = _profile, Profile = _profile,
DeviceId = deviceId DeviceId = deviceId
}); }) ?? throw new InvalidOperationException("No optimal audio stream found");
} }
var url = NormalizeDlnaMediaUrl(streamInfo.ToUrl(_serverAddress, _accessToken)); var url = NormalizeDlnaMediaUrl(streamInfo.ToUrl(_serverAddress, _accessToken));
var mediaSource = streamInfo.MediaSource; 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)); 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 // Samsung sometimes uses 1 as root
|| string.Equals(id, "1", StringComparison.OrdinalIgnoreCase); || 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); writer.WriteStartElement(string.Empty, "container", NsDidl);
@ -678,14 +676,14 @@ namespace Emby.Dlna.Didl
writer.WriteFullEndElement(); 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) if (!item.SupportsPositionTicksResume || item is Folder)
{ {
return; return;
} }
XmlAttribute secAttribute = null; XmlAttribute? secAttribute = null;
foreach (var attribute in _profile.XmlRootAttributes) foreach (var attribute in _profile.XmlRootAttributes)
{ {
if (string.Equals(attribute.Name, "xmlns:sec", StringComparison.OrdinalIgnoreCase)) if (string.Equals(attribute.Name, "xmlns:sec", StringComparison.OrdinalIgnoreCase))
@ -695,8 +693,8 @@ namespace Emby.Dlna.Didl
} }
} }
// Not a samsung device // Not a samsung device or no user data
if (secAttribute is null) if (secAttribute is null || user is null)
{ {
return; return;
} }
@ -717,7 +715,7 @@ namespace Emby.Dlna.Didl
/// <summary> /// <summary>
/// Adds fields used by both items and folders. /// Adds fields used by both items and folders.
/// </summary> /// </summary>
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 // 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 // MediaMonkey for example won't display content without a title
@ -795,7 +793,7 @@ namespace Emby.Dlna.Didl
if (item.IsDisplayedAsFolder || stubType.HasValue) if (item.IsDisplayedAsFolder || stubType.HasValue)
{ {
string classType = null; string? classType = null;
if (!_profile.RequiresPlainFolders) 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); AddCommonFields(item, itemStubType, context, writer, filter);
@ -975,7 +973,7 @@ namespace Emby.Dlna.Didl
private void AddCover(BaseItem item, StubType? stubType, XmlWriter writer) private void AddCover(BaseItem item, StubType? stubType, XmlWriter writer)
{ {
ImageDownloadInfo imageInfo = GetImageInfo(item); ImageDownloadInfo? imageInfo = GetImageInfo(item);
if (imageInfo is null) if (imageInfo is null)
{ {
@ -1073,7 +1071,7 @@ namespace Emby.Dlna.Didl
writer.WriteFullEndElement(); writer.WriteFullEndElement();
} }
private ImageDownloadInfo GetImageInfo(BaseItem item) private ImageDownloadInfo? GetImageInfo(BaseItem item)
{ {
if (item.HasImage(ImageType.Primary)) if (item.HasImage(ImageType.Primary))
{ {
@ -1118,7 +1116,7 @@ namespace Emby.Dlna.Didl
return null; return null;
} }
private BaseItem GetFirstParentWithImageBelowUserRoot(BaseItem item) private BaseItem? GetFirstParentWithImageBelowUserRoot(BaseItem item)
{ {
if (item is null) if (item is null)
{ {
@ -1148,7 +1146,7 @@ namespace Emby.Dlna.Didl
private ImageDownloadInfo GetImageInfo(BaseItem item, ImageType type) private ImageDownloadInfo GetImageInfo(BaseItem item, ImageType type)
{ {
var imageInfo = item.GetImageInfo(type, 0); var imageInfo = item.GetImageInfo(type, 0);
string tag = null; string? tag = null;
try try
{ {
@ -1250,7 +1248,7 @@ namespace Emby.Dlna.Didl
{ {
internal Guid ItemId { get; set; } internal Guid ItemId { get; set; }
internal string ImageTag { get; set; } internal string? ImageTag { get; set; }
internal ImageType Type { get; set; } internal ImageType Type { get; set; }
@ -1260,9 +1258,9 @@ namespace Emby.Dlna.Didl
internal bool IsDirectStream { get; set; } 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; }
} }
} }
} }

View File

@ -1,5 +1,3 @@
#nullable disable
#pragma warning disable CS1591 #pragma warning disable CS1591
using System; using System;
@ -25,7 +23,7 @@ namespace Emby.Dlna.PlayTo
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly object _timerLock = new object(); private readonly object _timerLock = new object();
private Timer _timer; private Timer? _timer;
private int _muteVol; private int _muteVol;
private int _volume; private int _volume;
private DateTime _lastVolumeRefresh; private DateTime _lastVolumeRefresh;
@ -40,13 +38,13 @@ namespace Emby.Dlna.PlayTo
_logger = logger; _logger = logger;
} }
public event EventHandler<PlaybackStartEventArgs> PlaybackStart; public event EventHandler<PlaybackStartEventArgs>? PlaybackStart;
public event EventHandler<PlaybackProgressEventArgs> PlaybackProgress; public event EventHandler<PlaybackProgressEventArgs>? PlaybackProgress;
public event EventHandler<PlaybackStoppedEventArgs> PlaybackStopped; public event EventHandler<PlaybackStoppedEventArgs>? PlaybackStopped;
public event EventHandler<MediaChangedEventArgs> MediaChanged; public event EventHandler<MediaChangedEventArgs>? MediaChanged;
public DeviceInfo Properties { get; set; } public DeviceInfo Properties { get; set; }
@ -75,13 +73,13 @@ namespace Emby.Dlna.PlayTo
public bool IsStopped => TransportState == TransportState.STOPPED; 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() public void Start()
{ {
@ -131,7 +129,7 @@ namespace Emby.Dlna.PlayTo
_volumeRefreshActive = true; _volumeRefreshActive = true;
var time = immediate ? 100 : 10000; 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; _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; 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)); 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; var services = Properties.Services;
@ -240,7 +238,7 @@ namespace Emby.Dlna.PlayTo
Properties.BaseUrl, Properties.BaseUrl,
service, service,
command.Name, command.Name,
rendererCommands.BuildPost(command, service.ServiceType, value), rendererCommands!.BuildPost(command, service.ServiceType, value), // null checked above
cancellationToken: cancellationToken) cancellationToken: cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
@ -265,12 +263,7 @@ namespace Emby.Dlna.PlayTo
return; return;
} }
var service = GetServiceRenderingControl(); var service = GetServiceRenderingControl() ?? throw new InvalidOperationException("Unable to find service");
if (service is null)
{
throw new InvalidOperationException("Unable to find service");
}
// Set it early and assume it will succeed // Set it early and assume it will succeed
// Remote control will perform better // Remote control will perform better
@ -281,7 +274,7 @@ namespace Emby.Dlna.PlayTo
Properties.BaseUrl, Properties.BaseUrl,
service, service,
command.Name, command.Name,
rendererCommands.BuildPost(command, service.ServiceType, value), rendererCommands!.BuildPost(command, service.ServiceType, value), // null checked above
cancellationToken: cancellationToken) cancellationToken: cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
} }
@ -296,26 +289,20 @@ namespace Emby.Dlna.PlayTo
return; return;
} }
var service = GetAvTransportService(); var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
if (service is null)
{
throw new InvalidOperationException("Unable to find service");
}
await new DlnaHttpClient(_logger, _httpClientFactory) await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync( .SendCommandAsync(
Properties.BaseUrl, Properties.BaseUrl,
service, service,
command.Name, 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) cancellationToken: cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
RestartTimer(true); 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); var avCommands = await GetAVProtocolAsync(cancellationToken).ConfigureAwait(false);
@ -335,14 +322,8 @@ namespace Emby.Dlna.PlayTo
{ "CurrentURIMetaData", CreateDidlMeta(metaData) } { "CurrentURIMetaData", CreateDidlMeta(metaData) }
}; };
var service = GetAvTransportService(); var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
var post = avCommands!.BuildPost(command, service.ServiceType, url, dictionary); // null checked above
if (service is null)
{
throw new InvalidOperationException("Unable to find service");
}
var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary);
await new DlnaHttpClient(_logger, _httpClientFactory) await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync( .SendCommandAsync(
Properties.BaseUrl, 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. * 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. * 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); 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); _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) if (command is null)
{ {
return; return;
@ -392,14 +373,8 @@ namespace Emby.Dlna.PlayTo
{ "NextURIMetaData", CreateDidlMeta(metaData) } { "NextURIMetaData", CreateDidlMeta(metaData) }
}; };
var service = GetAvTransportService(); var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
var post = avCommands!.BuildPost(command, service.ServiceType, url, dictionary); // null checked above
if (service is null)
{
throw new InvalidOperationException("Unable to find service");
}
var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary);
await new DlnaHttpClient(_logger, _httpClientFactory) await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header, cancellationToken) .SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header, cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
@ -423,12 +398,7 @@ namespace Emby.Dlna.PlayTo
return Task.CompletedTask; return Task.CompletedTask;
} }
var service = GetAvTransportService(); var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
if (service is null)
{
throw new InvalidOperationException("Unable to find service");
}
return new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync( return new DlnaHttpClient(_logger, _httpClientFactory).SendCommandAsync(
Properties.BaseUrl, Properties.BaseUrl,
service, service,
@ -460,14 +430,13 @@ namespace Emby.Dlna.PlayTo
return; return;
} }
var service = GetAvTransportService(); var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
await new DlnaHttpClient(_logger, _httpClientFactory) await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync( .SendCommandAsync(
Properties.BaseUrl, Properties.BaseUrl,
service, service,
command.Name, command.Name,
avCommands.BuildPost(command, service.ServiceType, 1), avCommands!.BuildPost(command, service.ServiceType, 1), // null checked above
cancellationToken: cancellationToken) cancellationToken: cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
@ -484,14 +453,13 @@ namespace Emby.Dlna.PlayTo
return; return;
} }
var service = GetAvTransportService(); var service = GetAvTransportService() ?? throw new InvalidOperationException("Unable to find service");
await new DlnaHttpClient(_logger, _httpClientFactory) await new DlnaHttpClient(_logger, _httpClientFactory)
.SendCommandAsync( .SendCommandAsync(
Properties.BaseUrl, Properties.BaseUrl,
service, service,
command.Name, command.Name,
avCommands.BuildPost(command, service.ServiceType, 1), avCommands!.BuildPost(command, service.ServiceType, 1), // null checked above
cancellationToken: cancellationToken) cancellationToken: cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
@ -500,7 +468,7 @@ namespace Emby.Dlna.PlayTo
RestartTimer(true); RestartTimer(true);
} }
private async void TimerCallback(object sender) private async void TimerCallback(object? sender)
{ {
if (_disposed) if (_disposed)
{ {
@ -623,7 +591,7 @@ namespace Emby.Dlna.PlayTo
Properties.BaseUrl, Properties.BaseUrl,
service, service,
command.Name, command.Name,
rendererCommands.BuildPost(command, service.ServiceType), rendererCommands!.BuildPost(command, service.ServiceType), // null checked above
cancellationToken: cancellationToken).ConfigureAwait(false); cancellationToken: cancellationToken).ConfigureAwait(false);
if (result is null || result.Document is null) if (result is null || result.Document is null)
@ -673,7 +641,7 @@ namespace Emby.Dlna.PlayTo
Properties.BaseUrl, Properties.BaseUrl,
service, service,
command.Name, command.Name,
rendererCommands.BuildPost(command, service.ServiceType), rendererCommands!.BuildPost(command, service.ServiceType), // null checked above
cancellationToken: cancellationToken).ConfigureAwait(false); cancellationToken: cancellationToken).ConfigureAwait(false);
if (result is null || result.Document is null) if (result is null || result.Document is null)
@ -728,7 +696,7 @@ namespace Emby.Dlna.PlayTo
return null; return null;
} }
private async Task<UBaseObject> GetMediaInfo(TransportCommands avCommands, CancellationToken cancellationToken) private async Task<UBaseObject?> GetMediaInfo(TransportCommands avCommands, CancellationToken cancellationToken)
{ {
var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMediaInfo"); var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetMediaInfo");
if (command is null) if (command is null)
@ -798,7 +766,7 @@ namespace Emby.Dlna.PlayTo
return null; 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"); var command = avCommands.ServiceActions.FirstOrDefault(c => c.Name == "GetPositionInfo");
if (command is null) if (command is null)
@ -871,7 +839,7 @@ namespace Emby.Dlna.PlayTo
return (true, null); return (true, null);
} }
XElement uPnpResponse = null; XElement? uPnpResponse = null;
try try
{ {
@ -895,7 +863,7 @@ namespace Emby.Dlna.PlayTo
return (true, uTrack); return (true, uTrack);
} }
private XElement ParseResponse(string xml) private XElement? ParseResponse(string xml)
{ {
// Handle different variations sent back by devices. // Handle different variations sent back by devices.
try try
@ -929,7 +897,7 @@ namespace Emby.Dlna.PlayTo
return null; return null;
} }
private static UBaseObject CreateUBaseObject(XElement container, string trackUri) private static UBaseObject CreateUBaseObject(XElement? container, string? trackUri)
{ {
ArgumentNullException.ThrowIfNull(container); ArgumentNullException.ThrowIfNull(container);
@ -972,7 +940,7 @@ namespace Emby.Dlna.PlayTo
return new string[4]; return new string[4];
} }
private async Task<TransportCommands> GetAVProtocolAsync(CancellationToken cancellationToken) private async Task<TransportCommands?> GetAVProtocolAsync(CancellationToken cancellationToken)
{ {
if (AvCommands is not null) if (AvCommands is not null)
{ {
@ -1004,7 +972,7 @@ namespace Emby.Dlna.PlayTo
return AvCommands; return AvCommands;
} }
private async Task<TransportCommands> GetRenderingProtocolAsync(CancellationToken cancellationToken) private async Task<TransportCommands?> GetRenderingProtocolAsync(CancellationToken cancellationToken)
{ {
if (RendererCommands is not null) if (RendererCommands is not null)
{ {
@ -1054,7 +1022,7 @@ namespace Emby.Dlna.PlayTo
return baseUrl + url; return baseUrl + url;
} }
public static async Task<Device> CreateuPnpDeviceAsync(Uri url, IHttpClientFactory httpClientFactory, ILogger logger, CancellationToken cancellationToken) public static async Task<Device?> CreateuPnpDeviceAsync(Uri url, IHttpClientFactory httpClientFactory, ILogger logger, CancellationToken cancellationToken)
{ {
var ssdpHttpClient = new DlnaHttpClient(logger, httpClientFactory); var ssdpHttpClient = new DlnaHttpClient(logger, httpClientFactory);
@ -1287,7 +1255,7 @@ namespace Emby.Dlna.PlayTo
} }
_timer = null; _timer = null;
Properties = null; Properties = null!;
_disposed = true; _disposed = true;
} }

View File

@ -42,7 +42,7 @@ namespace Emby.Dlna.PlayTo
private readonly IDeviceDiscovery _deviceDiscovery; private readonly IDeviceDiscovery _deviceDiscovery;
private readonly string _serverAddress; private readonly string _serverAddress;
private readonly string _accessToken; private readonly string? _accessToken;
private readonly List<PlaylistItem> _playlist = new List<PlaylistItem>(); private readonly List<PlaylistItem> _playlist = new List<PlaylistItem>();
private Device _device; private Device _device;
@ -59,7 +59,7 @@ namespace Emby.Dlna.PlayTo
IUserManager userManager, IUserManager userManager,
IImageProcessor imageProcessor, IImageProcessor imageProcessor,
string serverAddress, string serverAddress,
string accessToken, string? accessToken,
IDeviceDiscovery deviceDiscovery, IDeviceDiscovery deviceDiscovery,
IUserDataManager userDataManager, IUserDataManager userDataManager,
ILocalizationManager localization, ILocalizationManager localization,

View File

@ -1,5 +1,3 @@
#nullable disable
#pragma warning disable CS1591 #pragma warning disable CS1591
using System; using System;
@ -67,7 +65,7 @@ namespace Emby.Dlna.PlayTo
_deviceDiscovery.DeviceDiscovered += OnDeviceDiscoveryDeviceDiscovered; _deviceDiscovery.DeviceDiscovered += OnDeviceDiscoveryDeviceDiscovered;
} }
private async void OnDeviceDiscoveryDeviceDiscovered(object sender, GenericEventArgs<UpnpDeviceInfo> e) private async void OnDeviceDiscoveryDeviceDiscovered(object? sender, GenericEventArgs<UpnpDeviceInfo> e)
{ {
if (_disposed) if (_disposed)
{ {
@ -76,12 +74,12 @@ namespace Emby.Dlna.PlayTo
var info = e.Argument; var info = e.Argument;
if (!info.Headers.TryGetValue("USN", out string usn)) if (!info.Headers.TryGetValue("USN", out string? usn))
{ {
usn = string.Empty; usn = string.Empty;
} }
if (!info.Headers.TryGetValue("NT", out string nt)) if (!info.Headers.TryGetValue("NT", out string? nt))
{ {
nt = string.Empty; nt = string.Empty;
} }
@ -161,7 +159,7 @@ namespace Emby.Dlna.PlayTo
var uri = info.Location; var uri = info.Location;
_logger.LogDebug("Attempting to create PlayToController from location {0}", uri); _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); uuid = GetUuid(uuid);
} }

View File

@ -677,7 +677,7 @@ namespace Emby.Server.Implementations.Plugins
} }
catch (JsonException ex) 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) if (manifest is not null)

View File

@ -1,5 +1,3 @@
#nullable disable
#pragma warning disable CS1591 #pragma warning disable CS1591
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
@ -9,12 +7,12 @@ namespace MediaBrowser.Controller.Drawing
{ {
public static class ImageProcessorExtensions 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); 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); var imageInfo = item.GetImageInfo(imageType, imageIndex);

View File

@ -314,7 +314,7 @@ namespace MediaBrowser.Model.Dlna
/// <param name="audioSampleRate">The audio sample rate.</param> /// <param name="audioSampleRate">The audio sample rate.</param>
/// <param name="audioBitDepth">The audio bit depth.</param> /// <param name="audioBitDepth">The audio bit depth.</param>
/// <returns>The <see cref="ResponseProfile"/>.</returns> /// <returns>The <see cref="ResponseProfile"/>.</returns>
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) foreach (var i in ResponseProfiles)
{ {
@ -438,14 +438,14 @@ namespace MediaBrowser.Model.Dlna
/// <param name="isAvc">True if Avc.</param> /// <param name="isAvc">True if Avc.</param>
/// <returns>The <see cref="ResponseProfile"/>.</returns> /// <returns>The <see cref="ResponseProfile"/>.</returns>
public ResponseProfile? GetVideoMediaProfile( public ResponseProfile? GetVideoMediaProfile(
string container, string? container,
string? audioCodec, string? audioCodec,
string? videoCodec, string? videoCodec,
int? width, int? width,
int? height, int? height,
int? bitDepth, int? bitDepth,
int? videoBitrate, int? videoBitrate,
string videoProfile, string? videoProfile,
VideoRangeType videoRangeType, VideoRangeType videoRangeType,
double? videoLevel, double? videoLevel,
float? videoFramerate, float? videoFramerate,
@ -456,7 +456,7 @@ namespace MediaBrowser.Model.Dlna
int? refFrames, int? refFrames,
int? numVideoStreams, int? numVideoStreams,
int? numAudioStreams, int? numAudioStreams,
string videoCodecTag, string? videoCodecTag,
bool? isAvc) bool? isAvc)
{ {
foreach (var i in ResponseProfiles) foreach (var i in ResponseProfiles)

View File

@ -179,15 +179,9 @@ namespace MediaBrowser.Model.Dlna
{ {
ValidateMediaOptions(options, true); ValidateMediaOptions(options, true);
var mediaSources = new List<MediaSourceInfo>(); var mediaSources = string.IsNullOrEmpty(options.MediaSourceId)
foreach (var mediaSourceInfo in options.MediaSources) ? options.MediaSources
{ : options.MediaSources.Where(x => string.Equals(x.Id, options.MediaSourceId, StringComparison.OrdinalIgnoreCase));
if (string.IsNullOrEmpty(options.MediaSourceId)
|| string.Equals(mediaSourceInfo.Id, options.MediaSourceId, StringComparison.OrdinalIgnoreCase))
{
mediaSources.Add(mediaSourceInfo);
}
}
var streams = new List<StreamInfo>(); var streams = new List<StreamInfo>();
foreach (var mediaSourceInfo in mediaSources) foreach (var mediaSourceInfo in mediaSources)
@ -216,7 +210,7 @@ namespace MediaBrowser.Model.Dlna
return streams.OrderBy(i => return streams.OrderBy(i =>
{ {
// Nothing beats direct playing a file // 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; return 0;
} }
@ -235,7 +229,7 @@ namespace MediaBrowser.Model.Dlna
} }
}).ThenBy(i => }).ThenBy(i =>
{ {
switch (i.MediaSource.Protocol) switch (i.MediaSource?.Protocol)
{ {
case MediaProtocol.File: case MediaProtocol.File:
return 0; return 0;
@ -246,7 +240,7 @@ namespace MediaBrowser.Model.Dlna
{ {
if (maxBitrate > 0) if (maxBitrate > 0)
{ {
if (i.MediaSource.Bitrate.HasValue) if (i.MediaSource?.Bitrate is not null)
{ {
return Math.Abs(i.MediaSource.Bitrate.Value - maxBitrate); return Math.Abs(i.MediaSource.Bitrate.Value - maxBitrate);
} }
@ -585,10 +579,10 @@ namespace MediaBrowser.Model.Dlna
MediaSource = item, MediaSource = item,
RunTimeTicks = item.RunTimeTicks, RunTimeTicks = item.RunTimeTicks,
Context = options.Context, 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 subtitleStream = playlistItem.SubtitleStreamIndex.HasValue ? item.GetMediaStream(MediaStreamType.Subtitle, playlistItem.SubtitleStreamIndex.Value) : null;
var audioStream = item.GetDefaultAudioStream(options.AudioStreamIndex ?? item.DefaultAudioStreamIndex); var audioStream = item.GetDefaultAudioStream(options.AudioStreamIndex ?? item.DefaultAudioStreamIndex);
@ -659,7 +653,8 @@ namespace MediaBrowser.Model.Dlna
if (audioStreamIndex.HasValue) if (audioStreamIndex.HasValue)
{ {
playlistItem.AudioStreamIndex = audioStreamIndex; 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<string>() : new[] { audioCodec };
} }
} }
else if (directPlay == PlayMethod.DirectStream) else if (directPlay == PlayMethod.DirectStream)
@ -842,7 +837,7 @@ namespace MediaBrowser.Model.Dlna
if (videoStream is not null && videoStream.Level != 0) 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 // Prefer matching audio codecs, could do better here
@ -871,7 +866,7 @@ namespace MediaBrowser.Model.Dlna
// Copy matching audio codec options // Copy matching audio codec options
playlistItem.AudioSampleRate = audioStream.SampleRate; 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)) if (!string.IsNullOrEmpty(audioStream.Profile))
{ {
@ -880,7 +875,7 @@ namespace MediaBrowser.Model.Dlna
if (audioStream.Level != 0) if (audioStream.Level != 0)
{ {
playlistItem.SetOption(audioStream.Codec, "level", audioStream.Level.ToString()); playlistItem.SetOption(audioStream.Codec, "level", audioStream.Level.ToString() ?? string.Empty);
} }
} }

View File

@ -1,9 +1,9 @@
#nullable disable
#pragma warning disable CS1591 #pragma warning disable CS1591
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq;
using Jellyfin.Data.Enums; using Jellyfin.Data.Enums;
using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Drawing;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
@ -34,9 +34,9 @@ namespace MediaBrowser.Model.Dlna
public DlnaProfileType MediaType { get; set; } 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; } public long StartPositionTicks { get; set; }
@ -80,11 +80,11 @@ namespace MediaBrowser.Model.Dlna
public float? MaxFramerate { get; set; } 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; } public long? RunTimeTicks { get; set; }
@ -92,21 +92,21 @@ namespace MediaBrowser.Model.Dlna
public bool EstimateContentLength { get; set; } public bool EstimateContentLength { get; set; }
public MediaSourceInfo MediaSource { get; set; } public MediaSourceInfo? MediaSource { get; set; }
public string[] SubtitleCodecs { get; set; } public string[] SubtitleCodecs { get; set; }
public SubtitleDeliveryMethod SubtitleDeliveryMethod { 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 TranscodeReason TranscodeReasons { get; set; }
public Dictionary<string, string> StreamOptions { get; private set; } public Dictionary<string, string> 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) public bool IsDirectStream => MediaSource?.VideoType is not (VideoType.Dvd or VideoType.BluRay)
&& PlayMethod is PlayMethod.DirectStream or PlayMethod.DirectPlay; && PlayMethod is PlayMethod.DirectStream or PlayMethod.DirectPlay;
@ -114,12 +114,12 @@ namespace MediaBrowser.Model.Dlna
/// <summary> /// <summary>
/// Gets the audio stream that will be used. /// Gets the audio stream that will be used.
/// </summary> /// </summary>
public MediaStream TargetAudioStream => MediaSource?.GetDefaultAudioStream(AudioStreamIndex); public MediaStream? TargetAudioStream => MediaSource?.GetDefaultAudioStream(AudioStreamIndex);
/// <summary> /// <summary>
/// Gets the video stream that will be used. /// Gets the video stream that will be used.
/// </summary> /// </summary>
public MediaStream TargetVideoStream => MediaSource?.VideoStream; public MediaStream? TargetVideoStream => MediaSource?.VideoStream;
/// <summary> /// <summary>
/// Gets the audio sample rate that will be in the output stream. /// Gets the audio sample rate that will be in the output stream.
@ -259,7 +259,7 @@ namespace MediaBrowser.Model.Dlna
/// <summary> /// <summary>
/// Gets the audio sample rate that will be in the output stream. /// Gets the audio sample rate that will be in the output stream.
/// </summary> /// </summary>
public string TargetVideoProfile public string? TargetVideoProfile
{ {
get get
{ {
@ -307,7 +307,7 @@ namespace MediaBrowser.Model.Dlna
/// Gets the target video codec tag. /// Gets the target video codec tag.
/// </summary> /// </summary>
/// <value>The target video codec tag.</value> /// <value>The target video codec tag.</value>
public string TargetVideoCodecTag public string? TargetVideoCodecTag
{ {
get get
{ {
@ -364,7 +364,7 @@ namespace MediaBrowser.Model.Dlna
{ {
var stream = TargetAudioStream; var stream = TargetAudioStream;
string inputCodec = stream?.Codec; string? inputCodec = stream?.Codec;
if (IsDirectStream) if (IsDirectStream)
{ {
@ -389,7 +389,7 @@ namespace MediaBrowser.Model.Dlna
{ {
var stream = TargetVideoStream; var stream = TargetVideoStream;
string inputCodec = stream?.Codec; string? inputCodec = stream?.Codec;
if (IsDirectStream) if (IsDirectStream)
{ {
@ -417,7 +417,7 @@ namespace MediaBrowser.Model.Dlna
{ {
if (IsDirectStream) if (IsDirectStream)
{ {
return MediaSource.Size; return MediaSource?.Size;
} }
if (RunTimeTicks.HasValue) 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)) if (string.IsNullOrEmpty(qualifier))
{ {
@ -597,7 +597,7 @@ namespace MediaBrowser.Model.Dlna
StreamOptions[name] = value; StreamOptions[name] = value;
} }
public string GetOption(string qualifier, string name) public string? GetOption(string? qualifier, string name)
{ {
var value = GetOption(qualifier + "-" + name); var value = GetOption(qualifier + "-" + name);
@ -609,7 +609,7 @@ namespace MediaBrowser.Model.Dlna
return value; return value;
} }
public string GetOption(string name) public string? GetOption(string name)
{ {
if (StreamOptions.TryGetValue(name, out var value)) if (StreamOptions.TryGetValue(name, out var value))
{ {
@ -619,7 +619,7 @@ namespace MediaBrowser.Model.Dlna
return null; return null;
} }
public string ToUrl(string baseUrl, string accessToken) public string ToUrl(string baseUrl, string? accessToken)
{ {
ArgumentException.ThrowIfNullOrEmpty(baseUrl); 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); return string.Format(CultureInfo.InvariantCulture, "{0}/videos/{1}/stream{2}?{3}", baseUrl, ItemId, extension, queryString);
} }
private static IEnumerable<NameValuePair> BuildParams(StreamInfo item, string accessToken) private static IEnumerable<NameValuePair> BuildParams(StreamInfo item, string? accessToken)
{ {
var list = new List<NameValuePair>(); var list = new List<NameValuePair>();
@ -730,7 +730,7 @@ namespace MediaBrowser.Model.Dlna
list.Add(new NameValuePair("PlaySessionId", item.PlaySessionId ?? string.Empty)); list.Add(new NameValuePair("PlaySessionId", item.PlaySessionId ?? string.Empty));
list.Add(new NameValuePair("api_key", accessToken ?? 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("LiveStreamId", liveStreamId ?? string.Empty));
list.Add(new NameValuePair("SubtitleMethod", item.SubtitleStreamIndex.HasValue && item.SubtitleDeliveryMethod != SubtitleDeliveryMethod.External ? item.SubtitleDeliveryMethod.ToString() : 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("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 subtitleCodecs = item.SubtitleCodecs.Length == 0 ?
string.Empty : string.Empty :
@ -816,13 +816,18 @@ namespace MediaBrowser.Model.Dlna
return list; return list;
} }
public IEnumerable<SubtitleStreamInfo> GetSubtitleProfiles(ITranscoderSupport transcoderSupport, bool includeSelectedTrackOnly, string baseUrl, string accessToken) public IEnumerable<SubtitleStreamInfo> GetSubtitleProfiles(ITranscoderSupport transcoderSupport, bool includeSelectedTrackOnly, string baseUrl, string? accessToken)
{ {
return GetSubtitleProfiles(transcoderSupport, includeSelectedTrackOnly, false, baseUrl, accessToken); return GetSubtitleProfiles(transcoderSupport, includeSelectedTrackOnly, false, baseUrl, accessToken);
} }
public IEnumerable<SubtitleStreamInfo> GetSubtitleProfiles(ITranscoderSupport transcoderSupport, bool includeSelectedTrackOnly, bool enableAllProfiles, string baseUrl, string accessToken) public IEnumerable<SubtitleStreamInfo> GetSubtitleProfiles(ITranscoderSupport transcoderSupport, bool includeSelectedTrackOnly, bool enableAllProfiles, string baseUrl, string? accessToken)
{ {
if (MediaSource is null)
{
return Enumerable.Empty<SubtitleStreamInfo>();
}
var list = new List<SubtitleStreamInfo>(); var list = new List<SubtitleStreamInfo>();
// HLS will preserve timestamps so we can just grab the full subtitle stream // HLS will preserve timestamps so we can just grab the full subtitle stream
@ -856,27 +861,36 @@ namespace MediaBrowser.Model.Dlna
return list; return list;
} }
private void AddSubtitleProfiles(List<SubtitleStreamInfo> list, MediaStream stream, ITranscoderSupport transcoderSupport, bool enableAllProfiles, string baseUrl, string accessToken, long startPositionTicks) private void AddSubtitleProfiles(List<SubtitleStreamInfo> list, MediaStream stream, ITranscoderSupport transcoderSupport, bool enableAllProfiles, string baseUrl, string? accessToken, long startPositionTicks)
{ {
if (enableAllProfiles) if (enableAllProfiles)
{ {
foreach (var profile in DeviceProfile.SubtitleProfiles) foreach (var profile in DeviceProfile.SubtitleProfiles)
{ {
var info = GetSubtitleStreamInfo(stream, baseUrl, accessToken, startPositionTicks, new[] { profile }, transcoderSupport); var info = GetSubtitleStreamInfo(stream, baseUrl, accessToken, startPositionTicks, new[] { profile }, transcoderSupport);
if (info is not null)
list.Add(info); {
list.Add(info);
}
} }
} }
else else
{ {
var info = GetSubtitleStreamInfo(stream, baseUrl, accessToken, startPositionTicks, DeviceProfile.SubtitleProfiles, transcoderSupport); var info = GetSubtitleStreamInfo(stream, baseUrl, accessToken, startPositionTicks, DeviceProfile.SubtitleProfiles, transcoderSupport);
if (info is not null)
list.Add(info); {
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 subtitleProfile = StreamBuilder.GetSubtitleProfile(MediaSource, stream, subtitleProfiles, PlayMethod, transcoderSupport, Container, SubProtocol);
var info = new SubtitleStreamInfo var info = new SubtitleStreamInfo
{ {
@ -920,7 +934,7 @@ namespace MediaBrowser.Model.Dlna
return info; return info;
} }
public int? GetTargetVideoBitDepth(string codec) public int? GetTargetVideoBitDepth(string? codec)
{ {
var value = GetOption(codec, "videobitdepth"); var value = GetOption(codec, "videobitdepth");
@ -932,7 +946,7 @@ namespace MediaBrowser.Model.Dlna
return null; return null;
} }
public int? GetTargetAudioBitDepth(string codec) public int? GetTargetAudioBitDepth(string? codec)
{ {
var value = GetOption(codec, "audiobitdepth"); var value = GetOption(codec, "audiobitdepth");
@ -944,7 +958,7 @@ namespace MediaBrowser.Model.Dlna
return null; return null;
} }
public double? GetTargetVideoLevel(string codec) public double? GetTargetVideoLevel(string? codec)
{ {
var value = GetOption(codec, "level"); var value = GetOption(codec, "level");
@ -956,7 +970,7 @@ namespace MediaBrowser.Model.Dlna
return null; return null;
} }
public int? GetTargetRefFrames(string codec) public int? GetTargetRefFrames(string? codec)
{ {
var value = GetOption(codec, "maxrefframes"); var value = GetOption(codec, "maxrefframes");
@ -968,7 +982,7 @@ namespace MediaBrowser.Model.Dlna
return null; return null;
} }
public int? GetTargetAudioChannels(string codec) public int? GetTargetAudioChannels(string? codec)
{ {
var defaultValue = GlobalMaxAudioChannels ?? TranscodingMaxAudioChannels; var defaultValue = GlobalMaxAudioChannels ?? TranscodingMaxAudioChannels;
@ -988,7 +1002,7 @@ namespace MediaBrowser.Model.Dlna
private int? GetMediaStreamCount(MediaStreamType type, int limit) private int? GetMediaStreamCount(MediaStreamType type, int limit)
{ {
var count = MediaSource.GetStreamCount(type); var count = MediaSource?.GetStreamCount(type);
if (count.HasValue) if (count.HasValue)
{ {

View File

@ -351,11 +351,11 @@ namespace Jellyfin.Model.Tests
// Assert.Contains(uri.Extension, containers); // Assert.Contains(uri.Extension, containers);
// Check expected video codec (1) // Check expected video codec (1)
Assert.Contains(targetVideoStream.Codec, streamInfo.TargetVideoCodec); Assert.Contains(targetVideoStream?.Codec, streamInfo.TargetVideoCodec);
Assert.Single(streamInfo.TargetVideoCodec); Assert.Single(streamInfo.TargetVideoCodec);
// Check expected audio codecs (1) // Check expected audio codecs (1)
Assert.Contains(targetAudioStream.Codec, streamInfo.TargetAudioCodec); Assert.Contains(targetAudioStream?.Codec, streamInfo.TargetAudioCodec);
Assert.Single(streamInfo.TargetAudioCodec); Assert.Single(streamInfo.TargetAudioCodec);
// Assert.Single(val.AudioCodecs); // Assert.Single(val.AudioCodecs);
@ -410,13 +410,13 @@ namespace Jellyfin.Model.Tests
else else
{ {
// Check expected video codec (1) // Check expected video codec (1)
Assert.Contains(targetVideoStream.Codec, streamInfo.TargetVideoCodec); Assert.Contains(targetVideoStream?.Codec, streamInfo.TargetVideoCodec);
Assert.Single(streamInfo.TargetVideoCodec); Assert.Single(streamInfo.TargetVideoCodec);
if (transcodeMode.Equals("DirectStream", StringComparison.Ordinal)) if (transcodeMode.Equals("DirectStream", StringComparison.Ordinal))
{ {
// Check expected audio codecs (1) // Check expected audio codecs (1)
if (!targetAudioStream.IsExternal) if (targetAudioStream?.IsExternal == false)
{ {
// Check expected audio codecs (1) // Check expected audio codecs (1)
if (streamInfo.TranscodeReasons.HasFlag(TranscodeReason.ContainerNotSupported)) if (streamInfo.TranscodeReasons.HasFlag(TranscodeReason.ContainerNotSupported))
@ -432,7 +432,7 @@ namespace Jellyfin.Model.Tests
else if (transcodeMode.Equals("Remux", StringComparison.Ordinal)) else if (transcodeMode.Equals("Remux", StringComparison.Ordinal))
{ {
// Check expected audio codecs (1) // Check expected audio codecs (1)
Assert.Contains(targetAudioStream.Codec, streamInfo.AudioCodecs); Assert.Contains(targetAudioStream?.Codec, streamInfo.AudioCodecs);
Assert.Single(streamInfo.AudioCodecs); Assert.Single(streamInfo.AudioCodecs);
} }
@ -440,10 +440,10 @@ namespace Jellyfin.Model.Tests
var videoStream = targetVideoStream; var videoStream = targetVideoStream;
Assert.False(streamInfo.EstimateContentLength); Assert.False(streamInfo.EstimateContentLength);
Assert.Equal(TranscodeSeekInfo.Auto, streamInfo.TranscodeSeekInfo); Assert.Equal(TranscodeSeekInfo.Auto, streamInfo.TranscodeSeekInfo);
Assert.Contains(videoStream.Profile?.ToLowerInvariant() ?? string.Empty, streamInfo.TargetVideoProfile?.Split(",").Select(s => s.ToLowerInvariant()) ?? Array.Empty<string>()); Assert.Contains(videoStream?.Profile?.ToLowerInvariant() ?? string.Empty, streamInfo.TargetVideoProfile?.Split(",").Select(s => s.ToLowerInvariant()) ?? Array.Empty<string>());
Assert.Equal(videoStream.Level, streamInfo.TargetVideoLevel); Assert.Equal(videoStream?.Level, streamInfo.TargetVideoLevel);
Assert.Equal(videoStream.BitDepth, streamInfo.TargetVideoBitDepth); Assert.Equal(videoStream?.BitDepth, streamInfo.TargetVideoBitDepth);
Assert.InRange(streamInfo.VideoBitrate.GetValueOrDefault(), videoStream.BitRate.GetValueOrDefault(), int.MaxValue); Assert.InRange(streamInfo.VideoBitrate.GetValueOrDefault(), videoStream?.BitRate.GetValueOrDefault() ?? 0, int.MaxValue);
// Audio codec not supported // Audio codec not supported
if ((why & TranscodeReason.AudioCodecNotSupported) != 0) if ((why & TranscodeReason.AudioCodecNotSupported) != 0)
@ -452,7 +452,7 @@ namespace Jellyfin.Model.Tests
if (options.AudioStreamIndex >= 0) if (options.AudioStreamIndex >= 0)
{ {
// TODO:fixme // TODO:fixme
if (!targetAudioStream.IsExternal) if (targetAudioStream?.IsExternal == false)
{ {
Assert.DoesNotContain(targetAudioStream.Codec, streamInfo.AudioCodecs); Assert.DoesNotContain(targetAudioStream.Codec, streamInfo.AudioCodecs);
} }