Merge pull request #10056 from Bond-009/nullable2
This commit is contained in:
commit
3087881d93
|
@ -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
|
|||
/// <param name="episode">The episode.</param>
|
||||
/// <param name="context">Current context.</param>
|
||||
/// <returns>Formatted name of the episode.</returns>
|
||||
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
|
|||
/// <summary>
|
||||
/// Adds fields used by both items and folders.
|
||||
/// </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
|
||||
// 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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<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; }
|
||||
|
||||
|
@ -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<UBaseObject> GetMediaInfo(TransportCommands avCommands, CancellationToken cancellationToken)
|
||||
private async Task<UBaseObject?> 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<TransportCommands> GetAVProtocolAsync(CancellationToken cancellationToken)
|
||||
private async Task<TransportCommands?> GetAVProtocolAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (AvCommands is not null)
|
||||
{
|
||||
|
@ -1004,7 +972,7 @@ namespace Emby.Dlna.PlayTo
|
|||
return AvCommands;
|
||||
}
|
||||
|
||||
private async Task<TransportCommands> GetRenderingProtocolAsync(CancellationToken cancellationToken)
|
||||
private async Task<TransportCommands?> GetRenderingProtocolAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
if (RendererCommands is not null)
|
||||
{
|
||||
|
@ -1054,7 +1022,7 @@ namespace Emby.Dlna.PlayTo
|
|||
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);
|
||||
|
||||
|
@ -1287,7 +1255,7 @@ namespace Emby.Dlna.PlayTo
|
|||
}
|
||||
|
||||
_timer = null;
|
||||
Properties = null;
|
||||
Properties = null!;
|
||||
|
||||
_disposed = true;
|
||||
}
|
||||
|
|
|
@ -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<PlaylistItem> _playlist = new List<PlaylistItem>();
|
||||
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,
|
||||
|
|
|
@ -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<UpnpDeviceInfo> e)
|
||||
private async void OnDeviceDiscoveryDeviceDiscovered(object? sender, GenericEventArgs<UpnpDeviceInfo> 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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -314,7 +314,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
/// <param name="audioSampleRate">The audio sample rate.</param>
|
||||
/// <param name="audioBitDepth">The audio bit depth.</param>
|
||||
/// <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)
|
||||
{
|
||||
|
@ -438,14 +438,14 @@ namespace MediaBrowser.Model.Dlna
|
|||
/// <param name="isAvc">True if Avc.</param>
|
||||
/// <returns>The <see cref="ResponseProfile"/>.</returns>
|
||||
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)
|
||||
|
|
|
@ -179,15 +179,9 @@ namespace MediaBrowser.Model.Dlna
|
|||
{
|
||||
ValidateMediaOptions(options, true);
|
||||
|
||||
var mediaSources = new List<MediaSourceInfo>();
|
||||
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<StreamInfo>();
|
||||
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<string>() : 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<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)
|
||||
&& PlayMethod is PlayMethod.DirectStream or PlayMethod.DirectPlay;
|
||||
|
@ -114,12 +114,12 @@ namespace MediaBrowser.Model.Dlna
|
|||
/// <summary>
|
||||
/// Gets the audio stream that will be used.
|
||||
/// </summary>
|
||||
public MediaStream TargetAudioStream => MediaSource?.GetDefaultAudioStream(AudioStreamIndex);
|
||||
public MediaStream? TargetAudioStream => MediaSource?.GetDefaultAudioStream(AudioStreamIndex);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the video stream that will be used.
|
||||
/// </summary>
|
||||
public MediaStream TargetVideoStream => MediaSource?.VideoStream;
|
||||
public MediaStream? TargetVideoStream => MediaSource?.VideoStream;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the audio sample rate that will be in the output stream.
|
||||
|
@ -259,7 +259,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
/// <summary>
|
||||
/// Gets the audio sample rate that will be in the output stream.
|
||||
/// </summary>
|
||||
public string TargetVideoProfile
|
||||
public string? TargetVideoProfile
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -307,7 +307,7 @@ namespace MediaBrowser.Model.Dlna
|
|||
/// Gets the target video codec tag.
|
||||
/// </summary>
|
||||
/// <value>The target video codec tag.</value>
|
||||
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<NameValuePair> BuildParams(StreamInfo item, string accessToken)
|
||||
private static IEnumerable<NameValuePair> BuildParams(StreamInfo item, string? accessToken)
|
||||
{
|
||||
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("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<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);
|
||||
}
|
||||
|
||||
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>();
|
||||
|
||||
// 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<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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -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<string>());
|
||||
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<string>());
|
||||
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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user