diff --git a/Emby.Dlna/ContentDirectory/StubType.cs b/Emby.Dlna/ContentDirectory/StubType.cs
index 982ae5d68..187dc1d75 100644
--- a/Emby.Dlna/ContentDirectory/StubType.cs
+++ b/Emby.Dlna/ContentDirectory/StubType.cs
@@ -1,5 +1,4 @@
#pragma warning disable CS1591
-#pragma warning disable SA1602
namespace Emby.Dlna.ContentDirectory
{
diff --git a/Emby.Dlna/DlnaManager.cs b/Emby.Dlna/DlnaManager.cs
index 21ba1c755..9ab324038 100644
--- a/Emby.Dlna/DlnaManager.cs
+++ b/Emby.Dlna/DlnaManager.cs
@@ -553,7 +553,7 @@ namespace Emby.Dlna
private void DumpProfiles()
{
- DeviceProfile[] list = new []
+ DeviceProfile[] list = new[]
{
new SamsungSmartTvProfile(),
new XboxOneProfile(),
diff --git a/Emby.Dlna/Main/DlnaEntryPoint.cs b/Emby.Dlna/Main/DlnaEntryPoint.cs
index 82490ec31..8f60c3f78 100644
--- a/Emby.Dlna/Main/DlnaEntryPoint.cs
+++ b/Emby.Dlna/Main/DlnaEntryPoint.cs
@@ -228,7 +228,10 @@ namespace Emby.Dlna.Main
{
try
{
- ((DeviceDiscovery)_deviceDiscovery).Start(communicationsServer);
+ if (communicationsServer != null)
+ {
+ ((DeviceDiscovery)_deviceDiscovery).Start(communicationsServer);
+ }
}
catch (Exception ex)
{
diff --git a/Emby.Dlna/PlayTo/Device.cs b/Emby.Dlna/PlayTo/Device.cs
index 938ce5fbf..7bf7047fb 100644
--- a/Emby.Dlna/PlayTo/Device.cs
+++ b/Emby.Dlna/PlayTo/Device.cs
@@ -235,7 +235,13 @@ namespace Emby.Dlna.PlayTo
_logger.LogDebug("Setting mute");
var value = mute ? 1 : 0;
- await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
+ await new SsdpHttpClient(_httpClientFactory)
+ .SendCommandAsync(
+ Properties.BaseUrl,
+ service,
+ command.Name,
+ rendererCommands.BuildPost(command, service.ServiceType, value),
+ cancellationToken: cancellationToken)
.ConfigureAwait(false);
IsMuted = mute;
@@ -270,7 +276,13 @@ namespace Emby.Dlna.PlayTo
// Remote control will perform better
Volume = value;
- await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, rendererCommands.BuildPost(command, service.ServiceType, value))
+ await new SsdpHttpClient(_httpClientFactory)
+ .SendCommandAsync(
+ Properties.BaseUrl,
+ service,
+ command.Name,
+ rendererCommands.BuildPost(command, service.ServiceType, value),
+ cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
@@ -291,7 +303,13 @@ namespace Emby.Dlna.PlayTo
throw new InvalidOperationException("Unable to find service");
}
- await new SsdpHttpClient(_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"))
+ await new SsdpHttpClient(_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"),
+ cancellationToken: cancellationToken)
.ConfigureAwait(false);
RestartTimer(true);
@@ -325,14 +343,21 @@ namespace Emby.Dlna.PlayTo
}
var post = avCommands.BuildPost(command, service.ServiceType, url, dictionary);
- await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, post, header: header)
+ await new SsdpHttpClient(_httpClientFactory)
+ .SendCommandAsync(
+ Properties.BaseUrl,
+ service,
+ command.Name,
+ post,
+ header: header,
+ cancellationToken: cancellationToken)
.ConfigureAwait(false);
- await Task.Delay(50).ConfigureAwait(false);
+ await Task.Delay(50, cancellationToken).ConfigureAwait(false);
try
{
- await SetPlay(avCommands, CancellationToken.None).ConfigureAwait(false);
+ await SetPlay(avCommands, cancellationToken).ConfigureAwait(false);
}
catch
{
@@ -396,7 +421,13 @@ namespace Emby.Dlna.PlayTo
var service = GetAvTransportService();
- await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
+ await new SsdpHttpClient(_httpClientFactory)
+ .SendCommandAsync(
+ Properties.BaseUrl,
+ service,
+ command.Name,
+ avCommands.BuildPost(command, service.ServiceType, 1),
+ cancellationToken: cancellationToken)
.ConfigureAwait(false);
RestartTimer(true);
@@ -414,7 +445,13 @@ namespace Emby.Dlna.PlayTo
var service = GetAvTransportService();
- await new SsdpHttpClient(_httpClientFactory).SendCommandAsync(Properties.BaseUrl, service, command.Name, avCommands.BuildPost(command, service.ServiceType, 1))
+ await new SsdpHttpClient(_httpClientFactory)
+ .SendCommandAsync(
+ Properties.BaseUrl,
+ service,
+ command.Name,
+ avCommands.BuildPost(command, service.ServiceType, 1),
+ cancellationToken: cancellationToken)
.ConfigureAwait(false);
TransportState = TransportState.Paused;
@@ -990,7 +1027,7 @@ namespace Emby.Dlna.PlayTo
var deviceProperties = new DeviceInfo()
{
- Name = string.Join(" ", friendlyNames),
+ Name = string.Join(' ', friendlyNames),
BaseUrl = string.Format(CultureInfo.InvariantCulture, "http://{0}:{1}", url.Host, url.Port)
};
diff --git a/Emby.Dlna/PlayTo/PlayToController.cs b/Emby.Dlna/PlayTo/PlayToController.cs
index 315be1e8b..e4923b9eb 100644
--- a/Emby.Dlna/PlayTo/PlayToController.cs
+++ b/Emby.Dlna/PlayTo/PlayToController.cs
@@ -777,7 +777,7 @@ namespace Emby.Dlna.PlayTo
var currentWait = 0;
while (_device.TransportState != TransportState.Playing && currentWait < MaxWait)
{
- await Task.Delay(Interval).ConfigureAwait(false);
+ await Task.Delay(Interval, cancellationToken).ConfigureAwait(false);
currentWait += Interval;
}
diff --git a/Emby.Dlna/PlayTo/TransportState.cs b/Emby.Dlna/PlayTo/TransportState.cs
index 7068a5d24..2058e9dc7 100644
--- a/Emby.Dlna/PlayTo/TransportState.cs
+++ b/Emby.Dlna/PlayTo/TransportState.cs
@@ -1,5 +1,4 @@
#pragma warning disable CS1591
-#pragma warning disable SA1602
namespace Emby.Dlna.PlayTo
{
diff --git a/Emby.Naming/AudioBook/AudioBookListResolver.cs b/Emby.Naming/AudioBook/AudioBookListResolver.cs
index e9ea9b7a5..ca5322890 100644
--- a/Emby.Naming/AudioBook/AudioBookListResolver.cs
+++ b/Emby.Naming/AudioBook/AudioBookListResolver.cs
@@ -73,7 +73,7 @@ namespace Emby.Naming.AudioBook
var haveChaptersOrPages = stackFiles.Any(x => x.ChapterNumber != null || x.PartNumber != null);
var groupedBy = stackFiles.GroupBy(file => new { file.ChapterNumber, file.PartNumber });
- var nameWithReplacedDots = nameParserResult.Name.Replace(" ", ".");
+ var nameWithReplacedDots = nameParserResult.Name.Replace(' ', '.');
foreach (var group in groupedBy)
{
diff --git a/Emby.Naming/TV/SeasonPathParser.cs b/Emby.Naming/TV/SeasonPathParser.cs
index d11c7c99e..6236f86c4 100644
--- a/Emby.Naming/TV/SeasonPathParser.cs
+++ b/Emby.Naming/TV/SeasonPathParser.cs
@@ -60,7 +60,7 @@ namespace Emby.Naming.TV
bool supportSpecialAliases,
bool supportNumericSeasonFolders)
{
- var filename = Path.GetFileName(path) ?? string.Empty;
+ string filename = Path.GetFileName(path);
if (supportSpecialAliases)
{
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 1b9bb86bb..0a7c5c1fb 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -374,7 +374,7 @@ namespace Emby.Server.Implementations
///
/// Creates an instance of type and resolves all constructor dependencies.
///
- /// /// The type.
+ /// The type.
/// T.
public T CreateInstance()
=> ActivatorUtilities.CreateInstance(ServiceProvider);
diff --git a/Emby.Server.Implementations/Data/SqliteExtensions.cs b/Emby.Server.Implementations/Data/SqliteExtensions.cs
index 1af301ceb..a04d63088 100644
--- a/Emby.Server.Implementations/Data/SqliteExtensions.cs
+++ b/Emby.Server.Implementations/Data/SqliteExtensions.cs
@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.Globalization;
using SQLitePCL.pretty;
@@ -59,7 +60,7 @@ namespace Emby.Server.Implementations.Data
connection.RunInTransaction(conn =>
{
- conn.ExecuteAll(string.Join(";", queries));
+ conn.ExecuteAll(string.Join(';', queries));
});
}
@@ -142,11 +143,10 @@ namespace Emby.Server.Implementations.Data
return result[index].ReadGuidFromBlob();
}
+ [Conditional("DEBUG")]
private static void CheckName(string name)
{
-#if DEBUG
throw new ArgumentException("Invalid param name: " + name, nameof(name));
-#endif
}
public static void TryBind(this IStatement statement, string name, double value)
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 6e1f2feae..d78b93bd7 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -687,7 +687,7 @@ namespace Emby.Server.Implementations.Data
if (item.Genres.Length > 0)
{
- saveItemStatement.TryBind("@Genres", string.Join("|", item.Genres));
+ saveItemStatement.TryBind("@Genres", string.Join('|', item.Genres));
}
else
{
@@ -749,7 +749,7 @@ namespace Emby.Server.Implementations.Data
if (item.LockedFields.Length > 0)
{
- saveItemStatement.TryBind("@LockedFields", string.Join("|", item.LockedFields));
+ saveItemStatement.TryBind("@LockedFields", string.Join('|', item.LockedFields));
}
else
{
@@ -758,7 +758,7 @@ namespace Emby.Server.Implementations.Data
if (item.Studios.Length > 0)
{
- saveItemStatement.TryBind("@Studios", string.Join("|", item.Studios));
+ saveItemStatement.TryBind("@Studios", string.Join('|', item.Studios));
}
else
{
@@ -785,7 +785,7 @@ namespace Emby.Server.Implementations.Data
if (item.Tags.Length > 0)
{
- saveItemStatement.TryBind("@Tags", string.Join("|", item.Tags));
+ saveItemStatement.TryBind("@Tags", string.Join('|', item.Tags));
}
else
{
@@ -807,7 +807,7 @@ namespace Emby.Server.Implementations.Data
if (item is Trailer trailer && trailer.TrailerTypes.Length > 0)
{
- saveItemStatement.TryBind("@TrailerTypes", string.Join("|", trailer.TrailerTypes));
+ saveItemStatement.TryBind("@TrailerTypes", string.Join('|', trailer.TrailerTypes));
}
else
{
@@ -902,7 +902,7 @@ namespace Emby.Server.Implementations.Data
if (item.ProductionLocations.Length > 0)
{
- saveItemStatement.TryBind("@ProductionLocations", string.Join("|", item.ProductionLocations));
+ saveItemStatement.TryBind("@ProductionLocations", string.Join('|', item.ProductionLocations));
}
else
{
@@ -911,7 +911,7 @@ namespace Emby.Server.Implementations.Data
if (item.ExtraIds.Length > 0)
{
- saveItemStatement.TryBind("@ExtraIds", string.Join("|", item.ExtraIds));
+ saveItemStatement.TryBind("@ExtraIds", string.Join('|', item.ExtraIds));
}
else
{
@@ -931,7 +931,7 @@ namespace Emby.Server.Implementations.Data
string artists = null;
if (item is IHasArtist hasArtists && hasArtists.Artists.Count > 0)
{
- artists = string.Join("|", hasArtists.Artists);
+ artists = string.Join('|', hasArtists.Artists);
}
saveItemStatement.TryBind("@Artists", artists);
@@ -940,7 +940,7 @@ namespace Emby.Server.Implementations.Data
if (item is IHasAlbumArtist hasAlbumArtists
&& hasAlbumArtists.AlbumArtists.Count > 0)
{
- albumArtists = string.Join("|", hasAlbumArtists.AlbumArtists);
+ albumArtists = string.Join('|', hasAlbumArtists.AlbumArtists);
}
saveItemStatement.TryBind("@AlbumArtists", albumArtists);
@@ -2549,7 +2549,7 @@ namespace Emby.Server.Implementations.Data
if (groups.Count > 0)
{
- return " Group by " + string.Join(",", groups);
+ return " Group by " + string.Join(',', groups);
}
return string.Empty;
@@ -2578,7 +2578,7 @@ namespace Emby.Server.Implementations.Data
}
var commandText = "select "
- + string.Join(",", GetFinalColumnsToSelect(query, new[] { "count(distinct PresentationUniqueKey)" }))
+ + string.Join(',', GetFinalColumnsToSelect(query, new[] { "count(distinct PresentationUniqueKey)" }))
+ GetFromText()
+ GetJoinUserDataText(query);
@@ -2630,7 +2630,7 @@ namespace Emby.Server.Implementations.Data
}
var commandText = "select "
- + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns))
+ + string.Join(',', GetFinalColumnsToSelect(query, _retriveItemColumns))
+ GetFromText()
+ GetJoinUserDataText(query);
@@ -2880,7 +2880,7 @@ namespace Emby.Server.Implementations.Data
}
var commandText = "select "
- + string.Join(",", GetFinalColumnsToSelect(query, _retriveItemColumns))
+ + string.Join(',', GetFinalColumnsToSelect(query, _retriveItemColumns))
+ GetFromText()
+ GetJoinUserDataText(query);
@@ -2923,15 +2923,15 @@ namespace Emby.Server.Implementations.Data
if (EnableGroupByPresentationUniqueKey(query))
{
- commandText += " select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "count (distinct PresentationUniqueKey)" })) + GetFromText();
+ commandText += " select " + string.Join(',', GetFinalColumnsToSelect(query, new[] { "count (distinct PresentationUniqueKey)" })) + GetFromText();
}
else if (query.GroupBySeriesPresentationUniqueKey)
{
- commandText += " select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "count (distinct SeriesPresentationUniqueKey)" })) + GetFromText();
+ commandText += " select " + string.Join(',', GetFinalColumnsToSelect(query, new[] { "count (distinct SeriesPresentationUniqueKey)" })) + GetFromText();
}
else
{
- commandText += " select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "count (guid)" })) + GetFromText();
+ commandText += " select " + string.Join(',', GetFinalColumnsToSelect(query, new[] { "count (guid)" })) + GetFromText();
}
commandText += GetJoinUserDataText(query)
@@ -3039,7 +3039,7 @@ namespace Emby.Server.Implementations.Data
return string.Empty;
}
- return " ORDER BY " + string.Join(",", orderBy.Select(i =>
+ return " ORDER BY " + string.Join(',', orderBy.Select(i =>
{
var columnMap = MapOrderByField(i.Item1, query);
@@ -3137,7 +3137,7 @@ namespace Emby.Server.Implementations.Data
var now = DateTime.UtcNow;
var commandText = "select "
- + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }))
+ + string.Join(',', GetFinalColumnsToSelect(query, new[] { "guid" }))
+ GetFromText()
+ GetJoinUserDataText(query);
@@ -3203,7 +3203,7 @@ namespace Emby.Server.Implementations.Data
var now = DateTime.UtcNow;
- var commandText = "select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid", "path" })) + GetFromText();
+ var commandText = "select " + string.Join(',', GetFinalColumnsToSelect(query, new[] { "guid", "path" })) + GetFromText();
var whereClauses = GetWhereClauses(query, null);
if (whereClauses.Count != 0)
@@ -3284,7 +3284,7 @@ namespace Emby.Server.Implementations.Data
var now = DateTime.UtcNow;
var commandText = "select "
- + string.Join(",", GetFinalColumnsToSelect(query, new[] { "guid" }))
+ + string.Join(',', GetFinalColumnsToSelect(query, new[] { "guid" }))
+ GetFromText()
+ GetJoinUserDataText(query);
@@ -3327,15 +3327,15 @@ namespace Emby.Server.Implementations.Data
if (EnableGroupByPresentationUniqueKey(query))
{
- commandText += " select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "count (distinct PresentationUniqueKey)" })) + GetFromText();
+ commandText += " select " + string.Join(',', GetFinalColumnsToSelect(query, new[] { "count (distinct PresentationUniqueKey)" })) + GetFromText();
}
else if (query.GroupBySeriesPresentationUniqueKey)
{
- commandText += " select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "count (distinct SeriesPresentationUniqueKey)" })) + GetFromText();
+ commandText += " select " + string.Join(',', GetFinalColumnsToSelect(query, new[] { "count (distinct SeriesPresentationUniqueKey)" })) + GetFromText();
}
else
{
- commandText += " select " + string.Join(",", GetFinalColumnsToSelect(query, new[] { "count (guid)" })) + GetFromText();
+ commandText += " select " + string.Join(',', GetFinalColumnsToSelect(query, new[] { "count (guid)" })) + GetFromText();
}
commandText += GetJoinUserDataText(query)
@@ -3596,7 +3596,7 @@ namespace Emby.Server.Implementations.Data
}
else if (excludeTypes.Length > 1)
{
- var inClause = string.Join(",", excludeTypes.Select(i => "'" + i + "'"));
+ var inClause = string.Join(',', excludeTypes.Select(i => "'" + i + "'"));
whereClauses.Add($"type not in ({inClause})");
}
}
@@ -3607,7 +3607,7 @@ namespace Emby.Server.Implementations.Data
}
else if (includeTypes.Length > 1)
{
- var inClause = string.Join(",", includeTypes.Select(i => "'" + i + "'"));
+ var inClause = string.Join(',', includeTypes.Select(i => "'" + i + "'"));
whereClauses.Add($"type in ({inClause})");
}
@@ -3618,7 +3618,7 @@ namespace Emby.Server.Implementations.Data
}
else if (query.ChannelIds.Count > 1)
{
- var inClause = string.Join(",", query.ChannelIds.Select(i => "'" + i.ToString("N", CultureInfo.InvariantCulture) + "'"));
+ var inClause = string.Join(',', query.ChannelIds.Select(i => "'" + i.ToString("N", CultureInfo.InvariantCulture) + "'"));
whereClauses.Add($"ChannelId in ({inClause})");
}
@@ -4351,7 +4351,7 @@ namespace Emby.Server.Implementations.Data
}
else if (query.Years.Length > 1)
{
- var val = string.Join(",", query.Years);
+ var val = string.Join(',', query.Years);
whereClauses.Add("ProductionYear in (" + val + ")");
}
@@ -4401,7 +4401,7 @@ namespace Emby.Server.Implementations.Data
}
else if (queryMediaTypes.Length > 1)
{
- var val = string.Join(",", queryMediaTypes.Select(i => "'" + i + "'"));
+ var val = string.Join(',', queryMediaTypes.Select(i => "'" + i + "'"));
whereClauses.Add("MediaType in (" + val + ")");
}
@@ -4498,7 +4498,7 @@ namespace Emby.Server.Implementations.Data
var paramName = "@HasAnyProviderId" + index;
// this is a search for the placeholder
- hasProviderIds.Add("ProviderIds like " + paramName + "");
+ hasProviderIds.Add("ProviderIds like " + paramName);
// this replaces the placeholder with a value, here: %key=val%
if (statement != null)
@@ -4549,7 +4549,7 @@ namespace Emby.Server.Implementations.Data
}
else if (enableItemsByName && includedItemByNameTypes.Count > 1)
{
- var itemByNameTypeVal = string.Join(",", includedItemByNameTypes.Select(i => "'" + i + "'"));
+ var itemByNameTypeVal = string.Join(',', includedItemByNameTypes.Select(i => "'" + i + "'"));
whereClauses.Add("(TopParentId=@TopParentId or Type in (" + itemByNameTypeVal + "))");
}
else
@@ -4564,7 +4564,7 @@ namespace Emby.Server.Implementations.Data
}
else if (queryTopParentIds.Length > 1)
{
- var val = string.Join(",", queryTopParentIds.Select(i => "'" + i.ToString("N", CultureInfo.InvariantCulture) + "'"));
+ var val = string.Join(',', queryTopParentIds.Select(i => "'" + i.ToString("N", CultureInfo.InvariantCulture) + "'"));
if (enableItemsByName && includedItemByNameTypes.Count == 1)
{
@@ -4576,7 +4576,7 @@ namespace Emby.Server.Implementations.Data
}
else if (enableItemsByName && includedItemByNameTypes.Count > 1)
{
- var itemByNameTypeVal = string.Join(",", includedItemByNameTypes.Select(i => "'" + i + "'"));
+ var itemByNameTypeVal = string.Join(',', includedItemByNameTypes.Select(i => "'" + i + "'"));
whereClauses.Add("(Type in (" + itemByNameTypeVal + ") or TopParentId in (" + val + "))");
}
else
@@ -4597,7 +4597,7 @@ namespace Emby.Server.Implementations.Data
if (query.AncestorIds.Length > 1)
{
- var inClause = string.Join(",", query.AncestorIds.Select(i => "'" + i.ToString("N", CultureInfo.InvariantCulture) + "'"));
+ var inClause = string.Join(',', query.AncestorIds.Select(i => "'" + i.ToString("N", CultureInfo.InvariantCulture) + "'"));
whereClauses.Add(string.Format(CultureInfo.InvariantCulture, "Guid in (select itemId from AncestorIds where AncestorIdText in ({0}))", inClause));
}
@@ -5148,7 +5148,7 @@ AND Type = @InternalPersonType)");
}
else if (queryPersonTypes.Count > 1)
{
- var val = string.Join(",", queryPersonTypes.Select(i => "'" + i + "'"));
+ var val = string.Join(',', queryPersonTypes.Select(i => "'" + i + "'"));
whereClauses.Add("PersonType in (" + val + ")");
}
@@ -5162,7 +5162,7 @@ AND Type = @InternalPersonType)");
}
else if (queryExcludePersonTypes.Count > 1)
{
- var val = string.Join(",", queryExcludePersonTypes.Select(i => "'" + i + "'"));
+ var val = string.Join(',', queryExcludePersonTypes.Select(i => "'" + i + "'"));
whereClauses.Add("PersonType not in (" + val + ")");
}
@@ -5308,19 +5308,19 @@ AND Type = @InternalPersonType)");
var typeClause = itemValueTypes.Length == 1 ?
("Type=" + itemValueTypes[0].ToString(CultureInfo.InvariantCulture)) :
- ("Type in (" + string.Join(",", itemValueTypes.Select(i => i.ToString(CultureInfo.InvariantCulture))) + ")");
+ ("Type in (" + string.Join(',', itemValueTypes.Select(i => i.ToString(CultureInfo.InvariantCulture))) + ")");
var commandText = "Select Value From ItemValues where " + typeClause;
if (withItemTypes.Count > 0)
{
- var typeString = string.Join(",", withItemTypes.Select(i => "'" + i + "'"));
+ var typeString = string.Join(',', withItemTypes.Select(i => "'" + i + "'"));
commandText += " AND ItemId In (select guid from typedbaseitems where type in (" + typeString + "))";
}
if (excludeItemTypes.Count > 0)
{
- var typeString = string.Join(",", excludeItemTypes.Select(i => "'" + i + "'"));
+ var typeString = string.Join(',', excludeItemTypes.Select(i => "'" + i + "'"));
commandText += " AND ItemId not In (select guid from typedbaseitems where type in (" + typeString + "))";
}
@@ -5363,7 +5363,7 @@ AND Type = @InternalPersonType)");
var typeClause = itemValueTypes.Length == 1 ?
("Type=" + itemValueTypes[0].ToString(CultureInfo.InvariantCulture)) :
- ("Type in (" + string.Join(",", itemValueTypes.Select(i => i.ToString(CultureInfo.InvariantCulture))) + ")");
+ ("Type in (" + string.Join(',', itemValueTypes.Select(i => i.ToString(CultureInfo.InvariantCulture))) + ")");
InternalItemsQuery typeSubQuery = null;
@@ -5427,7 +5427,7 @@ AND Type = @InternalPersonType)");
columns = GetFinalColumnsToSelect(query, columns);
var commandText = "select "
- + string.Join(",", columns)
+ + string.Join(',', columns)
+ GetFromText()
+ GetJoinUserDataText(query);
@@ -5504,7 +5504,7 @@ AND Type = @InternalPersonType)");
if (query.EnableTotalRecordCount)
{
var countText = "select "
- + string.Join(",", GetFinalColumnsToSelect(query, new[] { "count (distinct PresentationUniqueKey)" }))
+ + string.Join(',', GetFinalColumnsToSelect(query, new[] { "count (distinct PresentationUniqueKey)" }))
+ GetFromText()
+ GetJoinUserDataText(query)
+ whereText;
@@ -5565,7 +5565,7 @@ AND Type = @InternalPersonType)");
if (query.EnableTotalRecordCount)
{
commandText = "select "
- + string.Join(",", GetFinalColumnsToSelect(query, new[] { "count (distinct PresentationUniqueKey)" }))
+ + string.Join(',', GetFinalColumnsToSelect(query, new[] { "count (distinct PresentationUniqueKey)" }))
+ GetFromText()
+ GetJoinUserDataText(query)
+ whereText;
@@ -6207,9 +6207,9 @@ AND Type = @InternalPersonType)");
if (item.Type == MediaStreamType.Subtitle)
{
- item.localizedUndefined = _localization.GetLocalizedString("Undefined");
- item.localizedDefault = _localization.GetLocalizedString("Default");
- item.localizedForced = _localization.GetLocalizedString("Forced");
+ item.LocalizedUndefined = _localization.GetLocalizedString("Undefined");
+ item.LocalizedDefault = _localization.GetLocalizedString("Default");
+ item.LocalizedForced = _localization.GetLocalizedString("Forced");
}
return item;
diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
index 2c4e8e0fc..6574db607 100644
--- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
@@ -47,7 +47,7 @@ namespace Emby.Server.Implementations.Data
connection.RunInTransaction(
db =>
{
- db.ExecuteAll(string.Join(";", new[] {
+ db.ExecuteAll(string.Join(';', new[] {
"create table if not exists UserDatas (key nvarchar not null, userId INT not null, rating float null, played bit not null, playCount int not null, isFavorite bit not null, playbackPositionTicks bigint not null, lastPlayedDate datetime null, AudioStreamIndex INT, SubtitleStreamIndex INT)",
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index 08047ba47..f03f04e02 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -29,7 +29,7 @@
-
+
diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
index 9486874d5..a12a6b26c 100644
--- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
+++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
@@ -1,3 +1,5 @@
+#nullable enable
+
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
@@ -29,7 +31,7 @@ namespace Emby.Server.Implementations.EntryPoints
///
/// The UDP server.
///
- private UdpServer _udpServer;
+ private UdpServer? _udpServer;
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private bool _disposed = false;
@@ -71,9 +73,8 @@ namespace Emby.Server.Implementations.EntryPoints
}
_cancellationTokenSource.Cancel();
- _udpServer.Dispose();
_cancellationTokenSource.Dispose();
- _cancellationTokenSource = null;
+ _udpServer?.Dispose();
_udpServer = null;
_disposed = true;
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
index e9e688fa6..60f82806f 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs
@@ -79,11 +79,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
return new MusicArtist();
}
- if (_config.Configuration.EnableSimpleArtistDetection)
- {
- return null;
- }
-
// Avoid mis-identifying top folders
if (args.Parent.IsRoot)
{
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index 7567ea312..6d7c5ac6e 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -35,8 +35,8 @@ namespace Emby.Server.Implementations.LiveTv.Listings
private readonly ICryptoProvider _cryptoProvider;
private readonly ConcurrentDictionary _tokens = new ConcurrentDictionary();
- private DateTime _lastErrorResponse;
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.GetOptions();
+ private DateTime _lastErrorResponse;
public SchedulesDirect(
ILogger logger,
@@ -111,7 +111,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
options.Headers.TryAddWithoutValidation("token", token);
using var response = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
await using var responseStream = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
- var dailySchedules = await JsonSerializer.DeserializeAsync>(responseStream, _jsonOptions).ConfigureAwait(false);
+ var dailySchedules = await JsonSerializer.DeserializeAsync>(responseStream, _jsonOptions, cancellationToken).ConfigureAwait(false);
_logger.LogDebug("Found {ScheduleCount} programs on {ChannelID} ScheduleDirect", dailySchedules.Count, channelId);
using var programRequestOptions = new HttpRequestMessage(HttpMethod.Post, ApiUrl + "/programs");
@@ -122,12 +122,12 @@ namespace Emby.Server.Implementations.LiveTv.Listings
using var innerResponse = await Send(programRequestOptions, true, info, cancellationToken).ConfigureAwait(false);
await using var innerResponseStream = await innerResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
- var programDetails = await JsonSerializer.DeserializeAsync>(innerResponseStream, _jsonOptions).ConfigureAwait(false);
+ var programDetails = await JsonSerializer.DeserializeAsync>(innerResponseStream, _jsonOptions, cancellationToken).ConfigureAwait(false);
var programDict = programDetails.ToDictionary(p => p.programID, y => y);
- var programIdsWithImages =
- programDetails.Where(p => p.hasImageArtwork).Select(p => p.programID)
- .ToList();
+ var programIdsWithImages = programDetails
+ .Where(p => p.hasImageArtwork).Select(p => p.programID)
+ .ToList();
var images = await GetImageForPrograms(info, programIdsWithImages, cancellationToken).ConfigureAwait(false);
@@ -182,8 +182,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
private static int GetSizeOrder(ScheduleDirect.ImageData image)
{
- if (!string.IsNullOrWhiteSpace(image.height)
- && int.TryParse(image.height, out int value))
+ if (int.TryParse(image.height, out int value))
{
return value;
}
@@ -704,7 +703,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
httpResponse.EnsureSuccessStatusCode();
await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
using var response = httpResponse.Content;
- var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions).ConfigureAwait(false);
+ var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false);
return root.lineups.Any(i => string.Equals(info.ListingsId, i.lineup, StringComparison.OrdinalIgnoreCase));
}
@@ -776,7 +775,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
using var httpResponse = await Send(options, true, info, cancellationToken).ConfigureAwait(false);
await using var stream = await httpResponse.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false);
- var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions).ConfigureAwait(false);
+ var root = await JsonSerializer.DeserializeAsync(stream, _jsonOptions, cancellationToken).ConfigureAwait(false);
_logger.LogInformation("Found {ChannelCount} channels on the lineup on ScheduleDirect", root.map.Count);
_logger.LogInformation("Mapping Stations to Channel");
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 5ef83f274..0760e8127 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -335,11 +335,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
return new Uri(url).AbsoluteUri.TrimEnd('/');
}
- protected EncodingOptions GetEncodingOptions()
- {
- return Config.GetConfiguration("encoding");
- }
-
private static string GetHdHrIdFromChannelId(string channelId)
{
return channelId.Split('_')[1];
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
index cf653f87d..b16ccc561 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
@@ -92,7 +92,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
try
{
- await tcpClient.ConnectAsync(remoteAddress, HdHomerunManager.HdHomeRunPort).ConfigureAwait(false);
+ await tcpClient.ConnectAsync(remoteAddress, HdHomerunManager.HdHomeRunPort, openCancellationToken).ConfigureAwait(false);
localAddress = ((IPEndPoint)tcpClient.Client.LocalEndPoint).Address;
tcpClient.Close();
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
index c82b67b41..c4f173c7a 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
@@ -155,7 +155,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
if (channelIdValues.Count > 0)
{
- channel.Id = string.Join("_", channelIdValues);
+ channel.Id = string.Join('_', channelIdValues);
}
return channel;
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
index f7507e6ba..eeb2426f4 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
@@ -159,7 +159,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
EnableStreamSharing = false;
await DeleteTempFiles(new List { TempFilePath }).ConfigureAwait(false);
- });
+ }, CancellationToken.None);
}
private void Resolve(TaskCompletionSource openTaskCompletionSource)
diff --git a/Emby.Server.Implementations/Localization/Core/bg-BG.json b/Emby.Server.Implementations/Localization/Core/bg-BG.json
index 7ff30df71..9db3b50d9 100644
--- a/Emby.Server.Implementations/Localization/Core/bg-BG.json
+++ b/Emby.Server.Implementations/Localization/Core/bg-BG.json
@@ -55,26 +55,26 @@
"NotificationOptionPluginInstalled": "Приставката е инсталирана",
"NotificationOptionPluginUninstalled": "Приставката е деинсталирана",
"NotificationOptionPluginUpdateInstalled": "Обновлението на приставката е инсталирано",
- "NotificationOptionServerRestartRequired": "Нужно е повторно пускане на сървъра",
+ "NotificationOptionServerRestartRequired": "Сървърът трябва да се рестартира",
"NotificationOptionTaskFailed": "Грешка в планирана задача",
- "NotificationOptionUserLockedOut": "Потребителя е заключен",
+ "NotificationOptionUserLockedOut": "Потребителят е заключен",
"NotificationOptionVideoPlayback": "Възпроизвеждането на видео започна",
"NotificationOptionVideoPlaybackStopped": "Възпроизвеждането на видео е спряно",
"Photos": "Снимки",
"Playlists": "Списъци",
"Plugin": "Приставка",
- "PluginInstalledWithName": "{0} е инсталирано",
- "PluginUninstalledWithName": "{0} е деинсталирано",
- "PluginUpdatedWithName": "{0} е обновено",
+ "PluginInstalledWithName": "{0} е инсталиранa",
+ "PluginUninstalledWithName": "{0} е деинсталиранa",
+ "PluginUpdatedWithName": "{0} е обновенa",
"ProviderValue": "Доставчик: {0}",
"ScheduledTaskFailedWithName": "{0} се провали",
"ScheduledTaskStartedWithName": "{0} започна",
- "ServerNameNeedsToBeRestarted": "{0} е нужно да се рестартира",
+ "ServerNameNeedsToBeRestarted": "{0} трябва да се рестартира",
"Shows": "Сериали",
"Songs": "Песни",
"StartupEmbyServerIsLoading": "Сървърът зарежда. Моля, опитайте отново след малко.",
"SubtitleDownloadFailureForItem": "Неуспешно изтегляне на субтитри за {0}",
- "SubtitleDownloadFailureFromForItem": "Поднадписите за {1} от {0} не можаха да се изтеглят",
+ "SubtitleDownloadFailureFromForItem": "Субтитрите за {1} от {0} не можаха да бъдат изтеглени",
"Sync": "Синхронизиране",
"System": "Система",
"TvShows": "Телевизионни сериали",
@@ -92,12 +92,12 @@
"ValueHasBeenAddedToLibrary": "{0} беше добавен във Вашата библиотека",
"ValueSpecialEpisodeName": "Специални - {0}",
"VersionNumber": "Версия {0}",
- "TaskDownloadMissingSubtitlesDescription": "Търси Интернет за липсващи поднадписи, на база конфигурацията за мета-данни.",
- "TaskDownloadMissingSubtitles": "Изтегляне на липсващи поднадписи",
+ "TaskDownloadMissingSubtitlesDescription": "Търси Интернет за липсващи субтитри, на база конфигурацията за мета-данни.",
+ "TaskDownloadMissingSubtitles": "Изтегляне на липсващи субтитри",
"TaskRefreshChannelsDescription": "Обновява информацията за интернет канала.",
"TaskRefreshChannels": "Обновяване на Канали",
- "TaskCleanTranscodeDescription": "Изтрива прекодирани файлове по-стари от един ден.",
- "TaskCleanTranscode": "Изчиства директорията за прекодиране",
+ "TaskCleanTranscodeDescription": "Изтрива транскодирани файлове по-стари от един ден.",
+ "TaskCleanTranscode": "Изчиства директорията за транскодиране",
"TaskUpdatePluginsDescription": "Изтегля и инсталира актуализации за добавките, които са настроени за автоматична актуализация.",
"TaskUpdatePlugins": "Актуализира добавките",
"TaskRefreshPeopleDescription": "Актуализира мета-данните за артистите и режисьорите за Вашата медийна библиотека.",
diff --git a/Emby.Server.Implementations/Localization/Core/sr.json b/Emby.Server.Implementations/Localization/Core/sr.json
index d785bcb90..15fb34186 100644
--- a/Emby.Server.Implementations/Localization/Core/sr.json
+++ b/Emby.Server.Implementations/Localization/Core/sr.json
@@ -4,11 +4,11 @@
"VersionNumber": "Верзија {0}",
"ValueSpecialEpisodeName": "Специјал - {0}",
"ValueHasBeenAddedToLibrary": "{0} је додато у вашу медијску библиотеку",
- "UserStoppedPlayingItemWithValues": "{0} заврши пуштање {1} на {2}",
+ "UserStoppedPlayingItemWithValues": "{0} завршио пуштање {1} на {2}",
"UserStartedPlayingItemWithValues": "{0} пушта {1} на {2}",
"UserPasswordChangedWithName": "Лозинка је промењена за корисника {0}",
"UserOnlineFromDevice": "{0} је на вези од {1}",
- "UserOfflineFromDevice": "{0} се одвезао са {1}",
+ "UserOfflineFromDevice": "{0} је прекинуо/а везу са {1}",
"UserLockedOutWithName": "Корисник {0} је закључан",
"UserDownloadingItemWithValues": "{0} преузима {1}",
"UserDeletedWithName": "Корисник {0} је обрисан",
@@ -41,7 +41,7 @@
"NotificationOptionPluginError": "Грешка прикључка",
"NotificationOptionNewLibraryContent": "Додат нови садржај",
"NotificationOptionInstallationFailed": "Неуспела инсталација",
- "NotificationOptionCameraImageUploaded": "Слика са камере послата",
+ "NotificationOptionCameraImageUploaded": "Слика са камере отпремљена",
"NotificationOptionAudioPlaybackStopped": "Заустављено пуштање звука",
"NotificationOptionAudioPlayback": "Покренуто пуштање звука",
"NotificationOptionApplicationUpdateInstalled": "Ажурирање инсталирано",
@@ -86,7 +86,7 @@
"Channels": "Канали",
"CameraImageUploadedFrom": "Нова фотографија је учитана са {0}",
"Books": "Књиге",
- "AuthenticationSucceededWithUserName": "{0} успешно проверено",
+ "AuthenticationSucceededWithUserName": "{0} Успешна аутентикација",
"Artists": "Извођачи",
"Application": "Апликација",
"AppDeviceValues": "Апликација: {0}, Уређај: {1}",
@@ -100,7 +100,7 @@
"TaskUpdatePluginsDescription": "Преузима и инсталира исправке за додатке који су конфигурисани за аутоматско ажурирање.",
"TaskUpdatePlugins": "Ажурирајте додатке",
"TaskRefreshPeopleDescription": "Ажурира метаподатке за глумце и редитеље у вашој медијској библиотеци.",
- "TaskRefreshPeople": "Освежите људе",
+ "TaskRefreshPeople": "Освежите кориснике",
"TaskCleanLogsDescription": "Брише логове старије од {0} дана.",
"TaskCleanLogs": "Очистите директоријум логова",
"TaskRefreshLibraryDescription": "Скенира вашу медијску библиотеку за нове датотеке и освежава метаподатке.",
@@ -116,6 +116,6 @@
"TaskCleanActivityLogDescription": "Брише историју активности старију од конфигурисаног броја година.",
"TaskCleanActivityLog": "Очисти историју активности",
"Undefined": "Недефинисано",
- "Forced": "Форсирано",
+ "Forced": "Принудно",
"Default": "Подразумевано"
}
diff --git a/Emby.Server.Implementations/Localization/Core/vi.json b/Emby.Server.Implementations/Localization/Core/vi.json
index 40368d464..58652c469 100644
--- a/Emby.Server.Implementations/Localization/Core/vi.json
+++ b/Emby.Server.Implementations/Localization/Core/vi.json
@@ -3,7 +3,7 @@
"Favorites": "Yêu Thích",
"Folders": "Thư Mục",
"Genres": "Thể Loại",
- "HeaderAlbumArtists": "Bộ Sưu Tập Nghệ sĩ",
+ "HeaderAlbumArtists": "Tuyển Tập Nghệ sĩ",
"HeaderContinueWatching": "Xem Tiếp",
"HeaderLiveTV": "TV Trực Tiếp",
"Movies": "Phim",
@@ -13,7 +13,7 @@
"Songs": "Các Bài Hát",
"Sync": "Đồng Bộ",
"ValueSpecialEpisodeName": "Đặc Biệt - {0}",
- "Albums": "Albums",
+ "Albums": "Tuyển Tập",
"Artists": "Các Nghệ Sĩ",
"TaskDownloadMissingSubtitlesDescription": "Tìm kiếm phụ đề bị thiếu trên Internet dựa trên cấu hình dữ liệu mô tả.",
"TaskDownloadMissingSubtitles": "Tải Xuống Phụ Đề Bị Thiếu",
diff --git a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
index f27305cbe..c6e931448 100644
--- a/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
+++ b/Emby.Server.Implementations/MediaEncoder/EncodingManager.cs
@@ -166,7 +166,7 @@ namespace Emby.Server.Implementations.MediaEncoder
}
catch (Exception ex)
{
- _logger.LogError(ex, "Error extracting chapter images for {0}", string.Join(",", video.Path));
+ _logger.LogError(ex, "Error extracting chapter images for {0}", string.Join(',', video.Path));
success = false;
break;
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
index 171e44258..649305fd5 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
@@ -143,7 +143,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
Directory.CreateDirectory(parentPath);
- string text = string.Join("|", previouslyFailedImages);
+ string text = string.Join('|', previouslyFailedImages);
File.WriteAllText(failHistoryPath, text);
}
diff --git a/Emby.Server.Implementations/Session/WebSocketController.cs b/Emby.Server.Implementations/Session/WebSocketController.cs
index f9c6a13c6..a653b58c2 100644
--- a/Emby.Server.Implementations/Session/WebSocketController.cs
+++ b/Emby.Server.Implementations/Session/WebSocketController.cs
@@ -8,7 +8,6 @@ using System.Linq;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
-using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Session;
using MediaBrowser.Model.Net;
diff --git a/Jellyfin.Api/Controllers/DashboardController.cs b/Jellyfin.Api/Controllers/DashboardController.cs
index b2baa9cea..a2c2ecd66 100644
--- a/Jellyfin.Api/Controllers/DashboardController.cs
+++ b/Jellyfin.Api/Controllers/DashboardController.cs
@@ -6,7 +6,6 @@ using System.Net.Mime;
using Jellyfin.Api.Attributes;
using Jellyfin.Api.Models;
using MediaBrowser.Common.Plugins;
-using MediaBrowser.Controller;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Plugins;
using Microsoft.AspNetCore.Http;
@@ -22,22 +21,18 @@ namespace Jellyfin.Api.Controllers
public class DashboardController : BaseJellyfinApiController
{
private readonly ILogger _logger;
- private readonly IServerApplicationHost _appHost;
private readonly IPluginManager _pluginManager;
///
/// Initializes a new instance of the class.
///
/// Instance of interface.
- /// Instance of interface.
/// Instance of interface.
public DashboardController(
ILogger logger,
- IServerApplicationHost appHost,
IPluginManager pluginManager)
{
_logger = logger;
- _appHost = appHost;
_pluginManager = pluginManager;
}
@@ -51,7 +46,7 @@ namespace Jellyfin.Api.Controllers
[HttpGet("web/ConfigurationPages")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
- public ActionResult> GetConfigurationPages(
+ public ActionResult> GetConfigurationPages(
[FromQuery] bool? enableInMainMenu)
{
var configPages = _pluginManager.Plugins.SelectMany(GetConfigPages).ToList();
@@ -77,38 +72,22 @@ namespace Jellyfin.Api.Controllers
[ProducesFile(MediaTypeNames.Text.Html, "application/x-javascript")]
public ActionResult GetDashboardConfigurationPage([FromQuery] string? name)
{
- IPlugin? plugin = null;
- Stream? stream = null;
-
- var isJs = false;
- var isTemplate = false;
-
var altPage = GetPluginPages().FirstOrDefault(p => string.Equals(p.Item1.Name, name, StringComparison.OrdinalIgnoreCase));
- if (altPage != null)
+ if (altPage == null)
{
- plugin = altPage.Item2;
- stream = plugin.GetType().Assembly.GetManifestResourceStream(altPage.Item1.EmbeddedResourcePath);
-
- isJs = string.Equals(Path.GetExtension(altPage.Item1.EmbeddedResourcePath), ".js", StringComparison.OrdinalIgnoreCase);
- isTemplate = altPage.Item1.EmbeddedResourcePath.EndsWith(".template.html", StringComparison.Ordinal);
+ return NotFound();
}
- if (plugin != null && stream != null)
+ IPlugin plugin = altPage.Item2;
+ string resourcePath = altPage.Item1.EmbeddedResourcePath;
+ Stream? stream = plugin.GetType().Assembly.GetManifestResourceStream(resourcePath);
+ if (stream == null)
{
- if (isJs)
- {
- return File(stream, MimeTypes.GetMimeType("page.js"));
- }
-
- if (isTemplate)
- {
- return File(stream, MimeTypes.GetMimeType("page.html"));
- }
-
- return File(stream, MimeTypes.GetMimeType("page.html"));
+ _logger.LogError("Failed to get resource {Resource} from plugin {Plugin}", resourcePath, plugin.Name);
+ return NotFound();
}
- return NotFound();
+ return File(stream, MimeTypes.GetMimeType(resourcePath));
}
private IEnumerable GetConfigPages(LocalPlugin plugin)
@@ -120,7 +99,7 @@ namespace Jellyfin.Api.Controllers
{
if (plugin?.Instance is not IHasWebPages hasWebPages)
{
- return new List>();
+ return Enumerable.Empty>();
}
return hasWebPages.GetPages().Select(i => new Tuple(i, plugin.Instance));
diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs
index dc3634970..a50d6e46b 100644
--- a/Jellyfin.Api/Controllers/ImageController.cs
+++ b/Jellyfin.Api/Controllers/ImageController.cs
@@ -113,7 +113,7 @@ namespace Jellyfin.Api.Controllers
await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false);
}
- user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType)));
+ user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType ?? string.Empty)));
await _providerManager
.SaveImage(memoryStream, mimeType, user.ProfileImage.Path)
@@ -160,7 +160,7 @@ namespace Jellyfin.Api.Controllers
await _userManager.ClearProfileImageAsync(user).ConfigureAwait(false);
}
- user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType)));
+ user.ProfileImage = new Data.Entities.ImageInfo(Path.Combine(userDataPath, "profile" + MimeTypes.ToExtension(mimeType ?? string.Empty)));
await _providerManager
.SaveImage(memoryStream, mimeType, user.ProfileImage.Path)
diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs
index b2e8bee91..a5aa9bfca 100644
--- a/Jellyfin.Api/Controllers/PluginsController.cs
+++ b/Jellyfin.Api/Controllers/PluginsController.cs
@@ -298,9 +298,7 @@ namespace Jellyfin.Api.Controllers
}
var imagePath = Path.Combine(plugin.Path, plugin.Manifest.ImagePath ?? string.Empty);
- if (((ServerConfiguration)_config.CommonConfiguration).DisablePluginImages
- || plugin.Manifest.ImagePath == null
- || !System.IO.File.Exists(imagePath))
+ if (plugin.Manifest.ImagePath == null || !System.IO.File.Exists(imagePath))
{
return NotFound();
}
diff --git a/Jellyfin.Api/Controllers/UniversalAudioController.cs b/Jellyfin.Api/Controllers/UniversalAudioController.cs
index bacd95bac..5aa033ccf 100644
--- a/Jellyfin.Api/Controllers/UniversalAudioController.cs
+++ b/Jellyfin.Api/Controllers/UniversalAudioController.cs
@@ -223,7 +223,7 @@ namespace Jellyfin.Api.Controllers
DeInterlace = true,
RequireNonAnamorphic = true,
EnableMpegtsM2TsMode = true,
- TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()),
+ TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(',', mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()),
Context = EncodingContext.Static,
StreamOptions = new Dictionary(),
EnableAdaptiveBitrateStreaming = true
@@ -254,7 +254,7 @@ namespace Jellyfin.Api.Controllers
CopyTimestamps = true,
StartTimeTicks = startTimeTicks,
SubtitleMethod = SubtitleDeliveryMethod.Embed,
- TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(",", mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()),
+ TranscodeReasons = mediaSource.TranscodeReasons == null ? null : string.Join(',', mediaSource.TranscodeReasons.Select(i => i.ToString()).ToArray()),
Context = EncodingContext.Static
};
diff --git a/Jellyfin.Api/Extensions/DtoExtensions.cs b/Jellyfin.Api/Extensions/DtoExtensions.cs
index f2abd515d..e0c744325 100644
--- a/Jellyfin.Api/Extensions/DtoExtensions.cs
+++ b/Jellyfin.Api/Extensions/DtoExtensions.cs
@@ -113,14 +113,5 @@ namespace Jellyfin.Api.Extensions
return dtoOptions;
}
-
- ///
- /// Check if DtoOptions contains field.
- ///
- /// DtoOptions object.
- /// Field to check.
- /// Field existence.
- internal static bool ContainsField(this DtoOptions dtoOptions, ItemFields field)
- => dtoOptions.Fields != null && dtoOptions.Fields.Contains(field);
}
}
diff --git a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
index 92ff42b49..16380f0bb 100644
--- a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
+++ b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
+using System.Net.Mime;
using System.Security.Claims;
using System.Text;
using System.Threading;
@@ -171,13 +172,15 @@ namespace Jellyfin.Api.Helpers
var queryString = _httpContextAccessor.HttpContext.Request.QueryString.ToString();
// from universal audio service
- if (queryString.IndexOf("SegmentContainer", StringComparison.OrdinalIgnoreCase) == -1 && !string.IsNullOrWhiteSpace(state.Request.SegmentContainer))
+ if (!string.IsNullOrWhiteSpace(state.Request.SegmentContainer)
+ && !queryString.Contains("SegmentContainer", StringComparison.OrdinalIgnoreCase))
{
queryString += "&SegmentContainer=" + state.Request.SegmentContainer;
}
// from universal audio service
- if (!string.IsNullOrWhiteSpace(state.Request.TranscodeReasons) && queryString.IndexOf("TranscodeReasons=", StringComparison.OrdinalIgnoreCase) == -1)
+ if (!string.IsNullOrWhiteSpace(state.Request.TranscodeReasons)
+ && !queryString.Contains("TranscodeReasons=", StringComparison.OrdinalIgnoreCase))
{
queryString += "&TranscodeReasons=" + state.Request.TranscodeReasons;
}
@@ -222,7 +225,7 @@ namespace Jellyfin.Api.Helpers
{
// Force HEVC Main Profile and disable video stream copy.
state.OutputVideoCodec = "hevc";
- var sdrVideoUrl = ReplaceProfile(playlistUrl, "hevc", string.Join(",", requestedVideoProfiles), "main");
+ var sdrVideoUrl = ReplaceProfile(playlistUrl, "hevc", string.Join(',', requestedVideoProfiles), "main");
sdrVideoUrl += "&AllowVideoStreamCopy=false";
EncodingHelper encodingHelper = new EncodingHelper(_mediaEncoder, _fileSystem, _subtitleEncoder, _configuration);
@@ -560,13 +563,13 @@ namespace Jellyfin.Api.Helpers
profileString = state.GetRequestedProfiles(codec).FirstOrDefault() ?? string.Empty;
if (string.Equals(state.ActualOutputVideoCodec, "h264", StringComparison.OrdinalIgnoreCase))
{
- profileString = profileString ?? "high";
+ profileString ??= "high";
}
if (string.Equals(state.ActualOutputVideoCodec, "h265", StringComparison.OrdinalIgnoreCase)
|| string.Equals(state.ActualOutputVideoCodec, "hevc", StringComparison.OrdinalIgnoreCase))
{
- profileString = profileString ?? "main";
+ profileString ??= "main";
}
}
diff --git a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
index cfa2c1229..89d36ab09 100644
--- a/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
+++ b/Jellyfin.Api/Helpers/FileStreamResponseHelpers.cs
@@ -39,7 +39,7 @@ namespace Jellyfin.Api.Helpers
}
// Can't dispose the response as it's required up the call chain.
- var response = await httpClient.GetAsync(new Uri(state.MediaPath)).ConfigureAwait(false);
+ var response = await httpClient.GetAsync(new Uri(state.MediaPath), cancellationToken).ConfigureAwait(false);
var contentType = response.Content.Headers.ContentType?.ToString();
httpContext.Response.Headers[HeaderNames.AcceptRanges] = "none";
diff --git a/Jellyfin.Api/Helpers/MediaInfoHelper.cs b/Jellyfin.Api/Helpers/MediaInfoHelper.cs
index 0d8315dee..ce6740fc9 100644
--- a/Jellyfin.Api/Helpers/MediaInfoHelper.cs
+++ b/Jellyfin.Api/Helpers/MediaInfoHelper.cs
@@ -523,7 +523,7 @@ namespace Jellyfin.Api.Helpers
/// Dlna profile type.
public void NormalizeMediaSourceContainer(MediaSourceInfo mediaSource, DeviceProfile profile, DlnaProfileType type)
{
- mediaSource.Container = StreamBuilder.NormalizeMediaSourceFormatIntoSingleContainer(mediaSource.Container, mediaSource.Path, profile, type);
+ mediaSource.Container = StreamBuilder.NormalizeMediaSourceFormatIntoSingleContainer(mediaSource.Container, profile, type);
}
private void SetDeviceSpecificSubtitleInfo(StreamInfo info, MediaSourceInfo mediaSource, string accessToken)
diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs
index 4957ee8b8..d20a02cf5 100644
--- a/Jellyfin.Api/Helpers/StreamingHelpers.cs
+++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs
@@ -183,7 +183,7 @@ namespace Jellyfin.Api.Helpers
if (string.IsNullOrEmpty(containerInternal))
{
containerInternal = streamingRequest.Static ?
- StreamBuilder.NormalizeMediaSourceFormatIntoSingleContainer(state.InputContainer, state.MediaPath, null, DlnaProfileType.Audio)
+ StreamBuilder.NormalizeMediaSourceFormatIntoSingleContainer(state.InputContainer, null, DlnaProfileType.Audio)
: GetOutputFileExtension(state);
}
@@ -245,7 +245,7 @@ namespace Jellyfin.Api.Helpers
var ext = string.IsNullOrWhiteSpace(state.OutputContainer)
? GetOutputFileExtension(state)
- : ('.' + state.OutputContainer);
+ : ("." + state.OutputContainer);
state.OutputFilePath = GetOutputFilePath(state, ext!, serverConfigurationManager, streamingRequest.DeviceId, streamingRequest.PlaySessionId);
diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj
index c2f4ab522..67d0a3b5a 100644
--- a/Jellyfin.Api/Jellyfin.Api.csproj
+++ b/Jellyfin.Api/Jellyfin.Api.csproj
@@ -17,8 +17,8 @@
-
-
+
+
@@ -38,4 +38,10 @@
../jellyfin.ruleset
+
+
+ <_Parameter1>Jellyfin.Api.Tests
+
+
+
diff --git a/Jellyfin.Api/Models/ConfigurationPageInfo.cs b/Jellyfin.Api/Models/ConfigurationPageInfo.cs
index a7bbe42fe..ec4a0d1a1 100644
--- a/Jellyfin.Api/Models/ConfigurationPageInfo.cs
+++ b/Jellyfin.Api/Models/ConfigurationPageInfo.cs
@@ -1,6 +1,5 @@
using System;
using MediaBrowser.Common.Plugins;
-using MediaBrowser.Controller.Plugins;
using MediaBrowser.Model.Plugins;
namespace Jellyfin.Api.Models
@@ -25,6 +24,14 @@ namespace Jellyfin.Api.Models
PluginId = plugin?.Id;
}
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public ConfigurationPageInfo()
+ {
+ Name = string.Empty;
+ }
+
///
/// Gets or sets the name.
///
diff --git a/Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs b/Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs
index 872a46824..e33e552ed 100644
--- a/Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs
+++ b/Jellyfin.Api/Models/PlaybackDtos/TranscodingThrottler.cs
@@ -98,7 +98,7 @@ namespace Jellyfin.Api.Models.PlaybackDtos
private EncodingOptions GetOptions()
{
- return _config.GetConfiguration("encoding");
+ return _config.GetEncodingOptions();
}
private async void TimerCallback(object? state)
diff --git a/Jellyfin.Server.Implementations/Properties/AssemblyInfo.cs b/Jellyfin.Server.Implementations/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..6528d4fdc
--- /dev/null
+++ b/Jellyfin.Server.Implementations/Properties/AssemblyInfo.cs
@@ -0,0 +1,23 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Jellyfin.Server.Implementations")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Jellyfin Project")]
+[assembly: AssemblyProduct("Jellyfin Server")]
+[assembly: AssemblyCopyright("Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: NeutralResourcesLanguage("en")]
+[assembly: InternalsVisibleTo("Jellyfin.Server.Implementations.Tests")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
diff --git a/Jellyfin.Server.Implementations/Users/UserManager.cs b/Jellyfin.Server.Implementations/Users/UserManager.cs
index d1de5408c..76d1389ca 100644
--- a/Jellyfin.Server.Implementations/Users/UserManager.cs
+++ b/Jellyfin.Server.Implementations/Users/UserManager.cs
@@ -137,17 +137,14 @@ namespace Jellyfin.Server.Implementations.Users
throw new ArgumentNullException(nameof(user));
}
- if (string.IsNullOrWhiteSpace(newName))
- {
- throw new ArgumentException("Invalid username", nameof(newName));
- }
+ ThrowIfInvalidUsername(newName);
if (user.Username.Equals(newName, StringComparison.Ordinal))
{
throw new ArgumentException("The new and old names must be different.");
}
- if (Users.Any(u => u.Id != user.Id && u.Username.Equals(newName, StringComparison.Ordinal)))
+ if (Users.Any(u => u.Id != user.Id && u.Username.Equals(newName, StringComparison.OrdinalIgnoreCase)))
{
throw new ArgumentException(string.Format(
CultureInfo.InvariantCulture,
@@ -201,9 +198,14 @@ namespace Jellyfin.Server.Implementations.Users
///
public async Task CreateUserAsync(string name)
{
- if (!IsValidUsername(name))
+ ThrowIfInvalidUsername(name);
+
+ if (Users.Any(u => u.Username.Equals(name, StringComparison.OrdinalIgnoreCase)))
{
- throw new ArgumentException("Usernames can contain unicode symbols, numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)");
+ throw new ArgumentException(string.Format(
+ CultureInfo.InvariantCulture,
+ "A user with the name '{0}' already exists.",
+ name));
}
await using var dbContext = _dbProvider.CreateContext();
@@ -725,12 +727,22 @@ namespace Jellyfin.Server.Implementations.Users
_users[user.Id] = user;
}
+ internal static void ThrowIfInvalidUsername(string name)
+ {
+ if (!string.IsNullOrWhiteSpace(name) && IsValidUsername(name))
+ {
+ return;
+ }
+
+ throw new ArgumentException("Usernames can contain unicode symbols, numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)", nameof(name));
+ }
+
private static bool IsValidUsername(string name)
{
// This is some regex that matches only on unicode "word" characters, as well as -, _ and @
// In theory this will cut out most if not all 'control' characters which should help minimize any weirdness
// Usernames can contain letters (a-z + whatever else unicode is cool with), numbers (0-9), at-signs (@), dashes (-), underscores (_), apostrophes ('), periods (.) and spaces ( )
- return Regex.IsMatch(name, @"^[\w\ \-'._@]*$");
+ return Regex.IsMatch(name, @"^[\w\ \-'._@]+$");
}
private IAuthenticationProvider GetAuthenticationProvider(User user)
diff --git a/Jellyfin.Server/CoreAppHost.cs b/Jellyfin.Server/CoreAppHost.cs
index b76aa5e14..ae2fb3999 100644
--- a/Jellyfin.Server/CoreAppHost.cs
+++ b/Jellyfin.Server/CoreAppHost.cs
@@ -11,7 +11,6 @@ using Jellyfin.Server.Implementations;
using Jellyfin.Server.Implementations.Activity;
using Jellyfin.Server.Implementations.Events;
using Jellyfin.Server.Implementations.Users;
-using MediaBrowser.Common.Net;
using MediaBrowser.Controller;
using MediaBrowser.Controller.BaseItemManager;
using MediaBrowser.Controller.Drawing;
diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
index 545937207..77f6695bb 100644
--- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
+++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs
@@ -310,6 +310,7 @@ namespace Jellyfin.Server.Extensions
// Allow parameters to properly be nullable.
c.UseAllOfToExtendReferenceSchemas();
+ c.SupportNonNullableReferenceTypes();
// TODO - remove when all types are supported in System.Text.Json
c.AddSwaggerTypeMappings();
diff --git a/Jellyfin.Server/Migrations/Routines/DisableTranscodingThrottling.cs b/Jellyfin.Server/Migrations/Routines/DisableTranscodingThrottling.cs
index 0925a87b5..bf0225e98 100644
--- a/Jellyfin.Server/Migrations/Routines/DisableTranscodingThrottling.cs
+++ b/Jellyfin.Server/Migrations/Routines/DisableTranscodingThrottling.cs
@@ -32,7 +32,7 @@ namespace Jellyfin.Server.Migrations.Routines
public void Perform()
{
// Set EnableThrottling to false since it wasn't used before and may introduce issues
- var encoding = _configManager.GetConfiguration("encoding");
+ var encoding = _configManager.GetEncodingOptions();
if (encoding.EnableThrottling)
{
_logger.LogInformation("Disabling transcoding throttling during migration");
diff --git a/MediaBrowser.sln b/Jellyfin.sln
similarity index 96%
rename from MediaBrowser.sln
rename to Jellyfin.sln
index 4e6687cce..d83013dab 100644
--- a/MediaBrowser.sln
+++ b/Jellyfin.sln
@@ -74,6 +74,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jellyfin.Dlna.Tests", "test
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.XbmcMetadata.Tests", "tests\Jellyfin.XbmcMetadata.Tests\Jellyfin.XbmcMetadata.Tests.csproj", "{30922383-D513-4F4D-B890-A940B57FA353}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Jellyfin.Model.Tests", "tests\Jellyfin.Model.Tests\Jellyfin.Model.Tests.csproj", "{FC1BC0CE-E8D2-4AE9-A6AB-8A02143B335D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -200,6 +202,10 @@ Global
{30922383-D513-4F4D-B890-A940B57FA353}.Debug|Any CPU.Build.0 = Debug|Any CPU
{30922383-D513-4F4D-B890-A940B57FA353}.Release|Any CPU.ActiveCfg = Release|Any CPU
{30922383-D513-4F4D-B890-A940B57FA353}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FC1BC0CE-E8D2-4AE9-A6AB-8A02143B335D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FC1BC0CE-E8D2-4AE9-A6AB-8A02143B335D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FC1BC0CE-E8D2-4AE9-A6AB-8A02143B335D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FC1BC0CE-E8D2-4AE9-A6AB-8A02143B335D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -214,6 +220,7 @@ Global
{42816EA8-4511-4CBF-A9C7-7791D5DDDAE6} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
{B8AE4B9D-E8D3-4B03-A95E-7FD8CECECC50} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
{30922383-D513-4F4D-B890-A940B57FA353} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
+ {FC1BC0CE-E8D2-4AE9-A6AB-8A02143B335D} = {FBBB5129-006E-4AD7-BAD5-8B7CA1D10ED6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3448830C-EBDC-426C-85CD-7BBB9651A7FE}
diff --git a/MediaBrowser.Common/Extensions/StreamExtensions.cs b/MediaBrowser.Common/Extensions/StreamExtensions.cs
new file mode 100644
index 000000000..cd77be7b2
--- /dev/null
+++ b/MediaBrowser.Common/Extensions/StreamExtensions.cs
@@ -0,0 +1,51 @@
+#nullable enable
+
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+
+namespace MediaBrowser.Common.Extensions
+{
+ ///
+ /// Class BaseExtensions.
+ ///
+ public static class StreamExtensions
+ {
+ ///
+ /// Reads all lines in the .
+ ///
+ /// The to read from.
+ /// All lines in the stream.
+ public static string[] ReadAllLines(this Stream stream)
+ => ReadAllLines(stream, Encoding.UTF8);
+
+ ///
+ /// Reads all lines in the .
+ ///
+ /// The to read from.
+ /// The character encoding to use.
+ /// All lines in the stream.
+ public static string[] ReadAllLines(this Stream stream, Encoding encoding)
+ {
+ using (StreamReader reader = new StreamReader(stream, encoding))
+ {
+ return ReadAllLines(reader).ToArray();
+ }
+ }
+
+ ///
+ /// Reads all lines in the .
+ ///
+ /// The to read from.
+ /// All lines in the stream.
+ public static IEnumerable ReadAllLines(this StreamReader reader)
+ {
+ string? line;
+ while ((line = reader.ReadLine()) != null)
+ {
+ yield return line;
+ }
+ }
+ }
+}
diff --git a/MediaBrowser.Common/Extensions/StringExtensions.cs b/MediaBrowser.Common/Extensions/StringExtensions.cs
deleted file mode 100644
index 764301741..000000000
--- a/MediaBrowser.Common/Extensions/StringExtensions.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-#nullable enable
-
-using System;
-
-namespace MediaBrowser.Common.Extensions
-{
- ///
- /// Extensions methods to simplify string operations.
- ///
- public static class StringExtensions
- {
- ///
- /// Returns the part on the left of the needle.
- ///
- /// The string to seek.
- /// The needle to find.
- /// The part left of the .
- public static ReadOnlySpan LeftPart(this ReadOnlySpan haystack, char needle)
- {
- var pos = haystack.IndexOf(needle);
- return pos == -1 ? haystack : haystack[..pos];
- }
-
- ///
- /// Returns the part on the left of the needle.
- ///
- /// The string to seek.
- /// The needle to find.
- /// One of the enumeration values that specifies the rules for the search.
- /// The part left of the needle.
- public static ReadOnlySpan LeftPart(this ReadOnlySpan haystack, ReadOnlySpan needle, StringComparison stringComparison = default)
- {
- var pos = haystack.IndexOf(needle, stringComparison);
- return pos == -1 ? haystack : haystack[..pos];
- }
- }
-}
diff --git a/MediaBrowser.Common/Json/JsonDefaults.cs b/MediaBrowser.Common/Json/JsonDefaults.cs
index 9a2ea6875..2ef24a884 100644
--- a/MediaBrowser.Common/Json/JsonDefaults.cs
+++ b/MediaBrowser.Common/Json/JsonDefaults.cs
@@ -31,7 +31,6 @@ namespace MediaBrowser.Common.Json
WriteIndented = false,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
NumberHandling = JsonNumberHandling.AllowReadingFromString,
- PropertyNameCaseInsensitive = true,
Converters =
{
new JsonGuidConverter(),
diff --git a/MediaBrowser.Common/Net/NetworkExtensions.cs b/MediaBrowser.Common/Net/NetworkExtensions.cs
index d07bba249..9c1a0cf49 100644
--- a/MediaBrowser.Common/Net/NetworkExtensions.cs
+++ b/MediaBrowser.Common/Net/NetworkExtensions.cs
@@ -1,11 +1,6 @@
-#pragma warning disable CA1062 // Validate arguments of public methods
using System;
-using System.Collections;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net;
-using System.Runtime.CompilerServices;
-using System.Text;
namespace MediaBrowser.Common.Net
{
diff --git a/MediaBrowser.Common/Plugins/BasePlugin.cs b/MediaBrowser.Common/Plugins/BasePlugin.cs
index e228ae7ec..7b162c0e1 100644
--- a/MediaBrowser.Common/Plugins/BasePlugin.cs
+++ b/MediaBrowser.Common/Plugins/BasePlugin.cs
@@ -1,10 +1,7 @@
using System;
using System.IO;
using System.Reflection;
-using System.Runtime.InteropServices;
-using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.Plugins;
-using MediaBrowser.Model.Serialization;
namespace MediaBrowser.Common.Plugins
{
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 7598b29e6..53d45261e 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -1243,7 +1243,7 @@ namespace MediaBrowser.Controller.Entities
}
}
- return string.Join("/", terms.ToArray());
+ return string.Join('/', terms.ToArray());
}
///
@@ -2795,7 +2795,7 @@ namespace MediaBrowser.Controller.Entities
{
var list = GetEtagValues(user);
- return string.Join("|", list).GetMD5().ToString("N", CultureInfo.InvariantCulture);
+ return string.Join('|', list).GetMD5().ToString("N", CultureInfo.InvariantCulture);
}
protected virtual List GetEtagValues(User user)
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 1a379074d..a410c1b66 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -107,7 +107,7 @@ namespace MediaBrowser.Controller.Entities.TV
return key;
}
- return key + "-" + string.Join("-", folders);
+ return key + "-" + string.Join('-', folders);
}
private static string GetUniqueSeriesKey(BaseItem series)
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index 07a9f5ba6..e5877a484 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -131,6 +131,12 @@ namespace MediaBrowser.Controller.MediaEncoding
private bool IsVppTonemappingSupported(EncodingJobInfo state, EncodingOptions options)
{
var videoStream = state.VideoStream;
+ if (videoStream == null)
+ {
+ // Remote stream doesn't have media info, disable vpp tonemapping.
+ return false;
+ }
+
var codec = videoStream.Codec;
if (string.Equals(options.HardwareAccelerationType, "vaapi", StringComparison.OrdinalIgnoreCase))
{
@@ -592,7 +598,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if (state.IsVideoRequest
&& ((string.Equals(encodingOptions.HardwareAccelerationType, "nvenc", StringComparison.OrdinalIgnoreCase)
&& (isNvdecDecoder || isCuvidHevcDecoder || isSwDecoder))
- || (string.Equals(encodingOptions.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase)
+ || (string.Equals(encodingOptions.HardwareAccelerationType, "amf", StringComparison.OrdinalIgnoreCase)
&& (isD3d11vaDecoder || isSwDecoder))))
{
if (isTonemappingSupported)
@@ -1381,7 +1387,8 @@ namespace MediaBrowser.Controller.MediaEncoding
var requestedProfile = requestedProfiles[0];
// strip spaces because they may be stripped out on the query string as well
- if (!string.IsNullOrEmpty(videoStream.Profile) && !requestedProfiles.Contains(videoStream.Profile.Replace(" ", ""), StringComparer.OrdinalIgnoreCase))
+ if (!string.IsNullOrEmpty(videoStream.Profile)
+ && !requestedProfiles.Contains(videoStream.Profile.Replace(" ", "", StringComparison.Ordinal), StringComparer.OrdinalIgnoreCase))
{
var currentScore = GetVideoProfileScore(videoStream.Profile);
var requestedScore = GetVideoProfileScore(requestedProfile);
@@ -1710,7 +1717,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if (filters.Count > 0)
{
- return " -af \"" + string.Join(",", filters) + "\"";
+ return " -af \"" + string.Join(',', filters) + "\"";
}
return string.Empty;
@@ -2530,7 +2537,7 @@ namespace MediaBrowser.Controller.MediaEncoding
var hasGraphicalSubs = state.SubtitleStream != null && !state.SubtitleStream.IsTextSubtitleStream && state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode;
// If double rate deinterlacing is enabled and the input framerate is 30fps or below, otherwise the output framerate will be too high for many devices
- var doubleRateDeinterlace = options.DeinterlaceDoubleRate && (videoStream?.RealFrameRate ?? 60) <= 30;
+ var doubleRateDeinterlace = options.DeinterlaceDoubleRate && (videoStream?.AverageFrameRate ?? 60) <= 30;
var isScalingInAdvance = false;
var isCudaDeintInAdvance = false;
@@ -2888,7 +2895,7 @@ namespace MediaBrowser.Controller.MediaEncoding
output += string.Format(
CultureInfo.InvariantCulture,
"{0}",
- string.Join(",", filters));
+ string.Join(',', filters));
}
return output;
@@ -2914,7 +2921,7 @@ namespace MediaBrowser.Controller.MediaEncoding
if (threads <= 0)
{
return 0;
- }
+ }
else if (threads >= Environment.ProcessorCount)
{
return Environment.ProcessorCount;
@@ -3080,7 +3087,7 @@ namespace MediaBrowser.Controller.MediaEncoding
{
inputModifier += " -deint 1";
- if (!encodingOptions.DeinterlaceDoubleRate || (videoStream?.RealFrameRate ?? 60) > 30)
+ if (!encodingOptions.DeinterlaceDoubleRate || (videoStream?.AverageFrameRate ?? 60) > 30)
{
inputModifier += " -drop_second_field 1";
}
@@ -3864,7 +3871,7 @@ namespace MediaBrowser.Controller.MediaEncoding
GetInputArgument(state, encodingOptions),
threads,
" -vn",
- string.Join(" ", audioTranscodeParams),
+ string.Join(' ', audioTranscodeParams),
outputPath,
string.Empty,
string.Empty,
diff --git a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
index 396206658..a337521c6 100644
--- a/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/BaseXmlSaver.cs
@@ -214,7 +214,7 @@ namespace MediaBrowser.LocalMetadata.Savers
if (item.LockedFields.Length > 0)
{
- writer.WriteElementString("LockedFields", string.Join("|", item.LockedFields));
+ writer.WriteElementString("LockedFields", string.Join('|', item.LockedFields));
}
if (item.CriticRating.HasValue)
diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
index c0b6cf28b..45872b5c0 100644
--- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs
@@ -103,7 +103,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
public void SetFFmpegPath()
{
// 1) Custom path stored in config/encoding xml file under tag takes precedence
- if (!ValidatePath(_configurationManager.GetConfiguration("encoding").EncoderAppPath, FFmpegLocation.Custom))
+ if (!ValidatePath(_configurationManager.GetEncodingOptions().EncoderAppPath, FFmpegLocation.Custom))
{
// 2) Check if the --ffmpeg CLI switch has been given
if (!ValidatePath(_startupOptionFFmpegPath, FFmpegLocation.SetByArgument))
@@ -118,7 +118,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
}
// Write the FFmpeg path to the config/encoding.xml file as so it appears in UI
- var config = _configurationManager.GetConfiguration("encoding");
+ var config = _configurationManager.GetEncodingOptions();
config.EncoderAppPathDisplay = _ffmpegPath ?? string.Empty;
_configurationManager.SaveConfiguration("encoding", config);
@@ -177,7 +177,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
// Write the new ffmpeg path to the xml as
// This ensures its not lost on next startup
- var config = _configurationManager.GetConfiguration("encoding");
+ var config = _configurationManager.GetEncodingOptions();
config.EncoderAppPath = newPath;
_configurationManager.SaveConfiguration("encoding", config);
diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
index f8af499e4..61daf50b3 100644
--- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
+++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj
@@ -24,6 +24,7 @@
+
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index bd026bce1..b9cb49cf2 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -681,9 +681,9 @@ namespace MediaBrowser.MediaEncoding.Probing
{
stream.Type = MediaStreamType.Subtitle;
stream.Codec = NormalizeSubtitleCodec(stream.Codec);
- stream.localizedUndefined = _localization.GetLocalizedString("Undefined");
- stream.localizedDefault = _localization.GetLocalizedString("Default");
- stream.localizedForced = _localization.GetLocalizedString("Forced");
+ stream.LocalizedUndefined = _localization.GetLocalizedString("Undefined");
+ stream.LocalizedDefault = _localization.GetLocalizedString("Default");
+ stream.LocalizedForced = _localization.GetLocalizedString("Forced");
}
else if (string.Equals(streamInfo.CodecType, "video", StringComparison.OrdinalIgnoreCase))
{
@@ -1496,7 +1496,7 @@ namespace MediaBrowser.MediaEncoding.Probing
video.IndexNumber = int.Parse(numbers[0].Replace(".", string.Empty, StringComparison.Ordinal).Split('/')[0], CultureInfo.InvariantCulture);
int totalEpisodesInSeason = int.Parse(numbers[0].Replace(".", string.Empty, StringComparison.Ordinal).Split('/')[1], CultureInfo.InvariantCulture);
- description = string.Join(" ", numbers, 1, numbers.Length - 1).Trim(); // Skip the first, concatenate the rest, clean up spaces and save it
+ description = string.Join(' ', numbers, 1, numbers.Length - 1).Trim(); // Skip the first, concatenate the rest, clean up spaces and save it
}
else
{
@@ -1508,7 +1508,7 @@ namespace MediaBrowser.MediaEncoding.Probing
if (subtitle.Contains('.', StringComparison.Ordinal))
{
// skip the comment, keep the subtitle
- description = string.Join(".", subtitle.Split('.'), 1, subtitle.Split('.').Length - 1).Trim(); // skip the first
+ description = string.Join('.', subtitle.Split('.'), 1, subtitle.Split('.').Length - 1).Trim(); // skip the first
}
else
{
diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
index bb48bed27..8219aa7b4 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
@@ -1,130 +1,21 @@
-#pragma warning disable CS1591
+#nullable enable
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text.RegularExpressions;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
+using Microsoft.Extensions.Logging;
+using Nikse.SubtitleEdit.Core.SubtitleFormats;
namespace MediaBrowser.MediaEncoding.Subtitles
{
- public class AssParser : ISubtitleParser
+ ///
+ /// Advanced SubStation Alpha subtitle parser.
+ ///
+ public class AssParser : SubtitleEditParser
{
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
-
- ///
- public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken)
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The logger.
+ public AssParser(ILogger logger) : base(logger)
{
- var trackInfo = new SubtitleTrackInfo();
- var trackEvents = new List();
- var eventIndex = 1;
- using (var reader = new StreamReader(stream))
- {
- string line;
- while (!string.Equals(reader.ReadLine(), "[Events]", StringComparison.Ordinal))
- {
- }
-
- var headers = ParseFieldHeaders(reader.ReadLine());
-
- while ((line = reader.ReadLine()) != null)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- if (string.IsNullOrWhiteSpace(line))
- {
- continue;
- }
-
- if (line[0] == '[')
- {
- break;
- }
-
- var subEvent = new SubtitleTrackEvent { Id = eventIndex.ToString(_usCulture) };
- eventIndex++;
- const string Dialogue = "Dialogue: ";
- var sections = line.Substring(Dialogue.Length).Split(',');
-
- subEvent.StartPositionTicks = GetTicks(sections[headers["Start"]]);
- subEvent.EndPositionTicks = GetTicks(sections[headers["End"]]);
-
- subEvent.Text = string.Join(',', sections[headers["Text"]..]);
- RemoteNativeFormatting(subEvent);
-
- subEvent.Text = subEvent.Text.Replace("\\n", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
-
- subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w0-9]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase);
-
- trackEvents.Add(subEvent);
- }
- }
-
- trackInfo.TrackEvents = trackEvents;
- return trackInfo;
- }
-
- private long GetTicks(ReadOnlySpan time)
- {
- return TimeSpan.TryParseExact(time, @"h\:mm\:ss\.ff", _usCulture, out var span)
- ? span.Ticks : 0;
- }
-
- internal static Dictionary ParseFieldHeaders(string line)
- {
- const string Format = "Format: ";
- var fields = line.Substring(Format.Length).Split(',').Select(x => x.Trim()).ToList();
-
- return new Dictionary
- {
- { "Start", fields.IndexOf("Start") },
- { "End", fields.IndexOf("End") },
- { "Text", fields.IndexOf("Text") }
- };
- }
-
- private void RemoteNativeFormatting(SubtitleTrackEvent p)
- {
- int indexOfBegin = p.Text.IndexOf('{', StringComparison.Ordinal);
- string pre = string.Empty;
- while (indexOfBegin >= 0 && p.Text.IndexOf('}', StringComparison.Ordinal) > indexOfBegin)
- {
- string s = p.Text.Substring(indexOfBegin);
- if (s.StartsWith("{\\an1}", StringComparison.Ordinal) ||
- s.StartsWith("{\\an2}", StringComparison.Ordinal) ||
- s.StartsWith("{\\an3}", StringComparison.Ordinal) ||
- s.StartsWith("{\\an4}", StringComparison.Ordinal) ||
- s.StartsWith("{\\an5}", StringComparison.Ordinal) ||
- s.StartsWith("{\\an6}", StringComparison.Ordinal) ||
- s.StartsWith("{\\an7}", StringComparison.Ordinal) ||
- s.StartsWith("{\\an8}", StringComparison.Ordinal) ||
- s.StartsWith("{\\an9}", StringComparison.Ordinal))
- {
- pre = s.Substring(0, 6);
- }
- else if (s.StartsWith("{\\an1\\", StringComparison.Ordinal) ||
- s.StartsWith("{\\an2\\", StringComparison.Ordinal) ||
- s.StartsWith("{\\an3\\", StringComparison.Ordinal) ||
- s.StartsWith("{\\an4\\", StringComparison.Ordinal) ||
- s.StartsWith("{\\an5\\", StringComparison.Ordinal) ||
- s.StartsWith("{\\an6\\", StringComparison.Ordinal) ||
- s.StartsWith("{\\an7\\", StringComparison.Ordinal) ||
- s.StartsWith("{\\an8\\", StringComparison.Ordinal) ||
- s.StartsWith("{\\an9\\", StringComparison.Ordinal))
- {
- pre = s.Substring(0, 5) + "}";
- }
-
- int indexOfEnd = p.Text.IndexOf('}', StringComparison.Ordinal);
- p.Text = p.Text.Remove(indexOfBegin, (indexOfEnd - indexOfBegin) + 1);
-
- indexOfBegin = p.Text.IndexOf('{', StringComparison.Ordinal);
- }
-
- p.Text = pre + p.Text;
}
}
}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
index ccef7eeea..19fb951dc 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
@@ -1,102 +1,21 @@
-#pragma warning disable CS1591
+#nullable enable
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Text.RegularExpressions;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
using Microsoft.Extensions.Logging;
+using Nikse.SubtitleEdit.Core.SubtitleFormats;
namespace MediaBrowser.MediaEncoding.Subtitles
{
- public class SrtParser : ISubtitleParser
+ ///
+ /// SubRip subtitle parser.
+ ///
+ public class SrtParser : SubtitleEditParser
{
- private readonly ILogger _logger;
-
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
-
- public SrtParser(ILogger logger)
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The logger.
+ public SrtParser(ILogger logger) : base(logger)
{
- _logger = logger;
- }
-
- ///
- public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken)
- {
- var trackInfo = new SubtitleTrackInfo();
- var trackEvents = new List();
- using (var reader = new StreamReader(stream))
- {
- string line;
- while ((line = reader.ReadLine()) != null)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- if (string.IsNullOrWhiteSpace(line))
- {
- continue;
- }
-
- var subEvent = new SubtitleTrackEvent { Id = line };
- line = reader.ReadLine();
-
- if (string.IsNullOrWhiteSpace(line))
- {
- continue;
- }
-
- var time = Regex.Split(line, @"[\t ]*-->[\t ]*");
-
- if (time.Length < 2)
- {
- // This occurs when subtitle text has an empty line as part of the text.
- // Need to adjust the break statement below to resolve this.
- _logger.LogWarning("Unrecognized line in srt: {0}", line);
- continue;
- }
-
- subEvent.StartPositionTicks = GetTicks(time[0]);
- var endTime = time[1].AsSpan();
- var idx = endTime.IndexOf(' ');
- if (idx > 0)
- {
- endTime = endTime.Slice(0, idx);
- }
-
- subEvent.EndPositionTicks = GetTicks(endTime);
- var multiline = new List();
- while ((line = reader.ReadLine()) != null)
- {
- if (line.Length == 0)
- {
- break;
- }
-
- multiline.Add(line);
- }
-
- subEvent.Text = string.Join(ParserValues.NewLine, multiline);
- subEvent.Text = subEvent.Text.Replace(@"\N", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
- subEvent.Text = Regex.Replace(subEvent.Text, @"\{(?:\\[0-9]?[\w.-]+(?:\([^\)]*\)|&H?[0-9A-Fa-f]+&|))+\}", string.Empty, RegexOptions.IgnoreCase);
- subEvent.Text = Regex.Replace(subEvent.Text, "<", "<", RegexOptions.IgnoreCase);
- subEvent.Text = Regex.Replace(subEvent.Text, ">", ">", RegexOptions.IgnoreCase);
- subEvent.Text = Regex.Replace(subEvent.Text, "<(\\/?(font|b|u|i|s))((\\s+(\\w|\\w[\\w\\-]*\\w)(\\s*=\\s*(?:\\\".*?\\\"|'.*?'|[^'\\\">\\s]+))?)+\\s*|\\s*)(\\/?)>", "<$1$3$7>", RegexOptions.IgnoreCase);
- trackEvents.Add(subEvent);
- }
- }
-
- trackInfo.TrackEvents = trackEvents;
- return trackInfo;
- }
-
- private long GetTicks(ReadOnlySpan time)
- {
- return TimeSpan.TryParseExact(time, @"hh\:mm\:ss\.fff", _usCulture, out var span)
- ? span.Ticks
- : (TimeSpan.TryParseExact(time, @"hh\:mm\:ss\,fff", _usCulture, out span)
- ? span.Ticks : 0);
}
}
}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs
index bc84c5074..36dc2e01f 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs
@@ -1,477 +1,21 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Text;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
+#nullable enable
+
+using Microsoft.Extensions.Logging;
+using Nikse.SubtitleEdit.Core.SubtitleFormats;
namespace MediaBrowser.MediaEncoding.Subtitles
{
///
- /// Credit.
+ /// SubStation Alpha subtitle parser.
///
- public class SsaParser : ISubtitleParser
+ public class SsaParser : SubtitleEditParser
{
- ///
- public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken)
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The logger.
+ public SsaParser(ILogger logger) : base(logger)
{
- var trackInfo = new SubtitleTrackInfo();
- var trackEvents = new List();
-
- using (var reader = new StreamReader(stream))
- {
- bool eventsStarted = false;
-
- string[] format = "Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text".Split(',');
- int indexLayer = 0;
- int indexStart = 1;
- int indexEnd = 2;
- int indexStyle = 3;
- int indexName = 4;
- int indexEffect = 8;
- int indexText = 9;
- int lineNumber = 0;
-
- var header = new StringBuilder();
-
- string line;
-
- while ((line = reader.ReadLine()) != null)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- lineNumber++;
- if (!eventsStarted)
- {
- header.AppendLine(line);
- }
-
- if (string.Equals(line.Trim(), "[events]", StringComparison.OrdinalIgnoreCase))
- {
- eventsStarted = true;
- }
- else if (!string.IsNullOrEmpty(line) && line.Trim().StartsWith(';'))
- {
- // skip comment lines
- }
- else if (eventsStarted && line.Trim().Length > 0)
- {
- string s = line.Trim().ToLowerInvariant();
- if (s.StartsWith("format:", StringComparison.Ordinal))
- {
- if (line.Length > 10)
- {
- format = line.ToLowerInvariant().Substring(8).Split(',');
- for (int i = 0; i < format.Length; i++)
- {
- if (string.Equals(format[i].Trim(), "layer", StringComparison.OrdinalIgnoreCase))
- {
- indexLayer = i;
- }
- else if (string.Equals(format[i].Trim(), "start", StringComparison.OrdinalIgnoreCase))
- {
- indexStart = i;
- }
- else if (string.Equals(format[i].Trim(), "end", StringComparison.OrdinalIgnoreCase))
- {
- indexEnd = i;
- }
- else if (string.Equals(format[i].Trim(), "text", StringComparison.OrdinalIgnoreCase))
- {
- indexText = i;
- }
- else if (string.Equals(format[i].Trim(), "effect", StringComparison.OrdinalIgnoreCase))
- {
- indexEffect = i;
- }
- else if (string.Equals(format[i].Trim(), "style", StringComparison.OrdinalIgnoreCase))
- {
- indexStyle = i;
- }
- }
- }
- }
- else if (!string.IsNullOrEmpty(s))
- {
- string text = string.Empty;
- string start = string.Empty;
- string end = string.Empty;
- string style = string.Empty;
- string layer = string.Empty;
- string effect = string.Empty;
- string name = string.Empty;
-
- string[] splittedLine;
-
- if (s.StartsWith("dialogue:", StringComparison.Ordinal))
- {
- splittedLine = line.Substring(10).Split(',');
- }
- else
- {
- splittedLine = line.Split(',');
- }
-
- for (int i = 0; i < splittedLine.Length; i++)
- {
- if (i == indexStart)
- {
- start = splittedLine[i].Trim();
- }
- else if (i == indexEnd)
- {
- end = splittedLine[i].Trim();
- }
- else if (i == indexLayer)
- {
- layer = splittedLine[i];
- }
- else if (i == indexEffect)
- {
- effect = splittedLine[i];
- }
- else if (i == indexText)
- {
- text = splittedLine[i];
- }
- else if (i == indexStyle)
- {
- style = splittedLine[i];
- }
- else if (i == indexName)
- {
- name = splittedLine[i];
- }
- else if (i > indexText)
- {
- text += "," + splittedLine[i];
- }
- }
-
- try
- {
- trackEvents.Add(
- new SubtitleTrackEvent
- {
- StartPositionTicks = GetTimeCodeFromString(start),
- EndPositionTicks = GetTimeCodeFromString(end),
- Text = GetFormattedText(text)
- });
- }
- catch
- {
- }
- }
- }
- }
-
- // if (header.Length > 0)
- // subtitle.Header = header.ToString();
-
- // subtitle.Renumber(1);
- }
-
- trackInfo.TrackEvents = trackEvents.ToArray();
- return trackInfo;
- }
-
- private static long GetTimeCodeFromString(string time)
- {
- // h:mm:ss.cc
- string[] timeCode = time.Split(':', '.');
- return new TimeSpan(
- 0,
- int.Parse(timeCode[0], CultureInfo.InvariantCulture),
- int.Parse(timeCode[1], CultureInfo.InvariantCulture),
- int.Parse(timeCode[2], CultureInfo.InvariantCulture),
- int.Parse(timeCode[3], CultureInfo.InvariantCulture) * 10).Ticks;
- }
-
- private static string GetFormattedText(string text)
- {
- text = text.Replace("\\n", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase);
-
- for (int i = 0; i < 10; i++) // just look ten times...
- {
- if (text.Contains(@"{\fn", StringComparison.Ordinal))
- {
- int start = text.IndexOf(@"{\fn", StringComparison.Ordinal);
- int end = text.IndexOf('}', start);
- if (end > 0 && !text.Substring(start).StartsWith("{\\fn}", StringComparison.Ordinal))
- {
- string fontName = text.Substring(start + 4, end - (start + 4));
- string extraTags = string.Empty;
- CheckAndAddSubTags(ref fontName, ref extraTags, out bool italic);
- text = text.Remove(start, end - start + 1);
- if (italic)
- {
- text = text.Insert(start, "");
- }
- else
- {
- text = text.Insert(start, "");
- }
-
- int indexOfEndTag = text.IndexOf("{\\fn}", start, StringComparison.Ordinal);
- if (indexOfEndTag > 0)
- {
- text = text.Remove(indexOfEndTag, "{\\fn}".Length).Insert(indexOfEndTag, "");
- }
- else
- {
- text += "";
- }
- }
- }
-
- if (text.Contains(@"{\fs", StringComparison.Ordinal))
- {
- int start = text.IndexOf(@"{\fs", StringComparison.Ordinal);
- int end = text.IndexOf('}', start);
- if (end > 0 && !text.Substring(start).StartsWith("{\\fs}", StringComparison.Ordinal))
- {
- string fontSize = text.Substring(start + 4, end - (start + 4));
- string extraTags = string.Empty;
- CheckAndAddSubTags(ref fontSize, ref extraTags, out bool italic);
- if (IsInteger(fontSize))
- {
- text = text.Remove(start, end - start + 1);
- if (italic)
- {
- text = text.Insert(start, "");
- }
- else
- {
- text = text.Insert(start, "");
- }
-
- int indexOfEndTag = text.IndexOf("{\\fs}", start, StringComparison.Ordinal);
- if (indexOfEndTag > 0)
- {
- text = text.Remove(indexOfEndTag, "{\\fs}".Length).Insert(indexOfEndTag, "");
- }
- else
- {
- text += "";
- }
- }
- }
- }
-
- if (text.Contains(@"{\c", StringComparison.Ordinal))
- {
- int start = text.IndexOf(@"{\c", StringComparison.Ordinal);
- int end = text.IndexOf('}', start);
- if (end > 0 && !text.Substring(start).StartsWith("{\\c}", StringComparison.Ordinal))
- {
- string color = text.Substring(start + 4, end - (start + 4));
- string extraTags = string.Empty;
- CheckAndAddSubTags(ref color, ref extraTags, out bool italic);
-
- color = color.Replace("&", string.Empty, StringComparison.Ordinal).TrimStart('H');
- color = color.PadLeft(6, '0');
-
- // switch to rrggbb from bbggrr
- color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2);
- color = color.ToLowerInvariant();
-
- text = text.Remove(start, end - start + 1);
- if (italic)
- {
- text = text.Insert(start, "");
- }
- else
- {
- text = text.Insert(start, "");
- }
-
- int indexOfEndTag = text.IndexOf("{\\c}", start, StringComparison.Ordinal);
- if (indexOfEndTag > 0)
- {
- text = text.Remove(indexOfEndTag, "{\\c}".Length).Insert(indexOfEndTag, "");
- }
- else
- {
- text += "";
- }
- }
- }
-
- if (text.Contains(@"{\1c", StringComparison.Ordinal)) // "1" specifices primary color
- {
- int start = text.IndexOf(@"{\1c", StringComparison.Ordinal);
- int end = text.IndexOf('}', start);
- if (end > 0 && !text.Substring(start).StartsWith("{\\1c}", StringComparison.Ordinal))
- {
- string color = text.Substring(start + 5, end - (start + 5));
- string extraTags = string.Empty;
- CheckAndAddSubTags(ref color, ref extraTags, out bool italic);
-
- color = color.Replace("&", string.Empty, StringComparison.Ordinal).TrimStart('H');
- color = color.PadLeft(6, '0');
-
- // switch to rrggbb from bbggrr
- color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2);
- color = color.ToLowerInvariant();
-
- text = text.Remove(start, end - start + 1);
- if (italic)
- {
- text = text.Insert(start, "");
- }
- else
- {
- text = text.Insert(start, "");
- }
-
- int indexOfEndTag = text.IndexOf("{\\1c}", start, StringComparison.Ordinal);
- if (indexOfEndTag > 0)
- {
- text = text.Remove(indexOfEndTag, "{\\1c}".Length).Insert(indexOfEndTag, "");
- }
- else
- {
- text += "";
- }
- }
- }
- }
-
- text = text.Replace(@"{\i1}", "", StringComparison.Ordinal);
- text = text.Replace(@"{\i0}", "", StringComparison.Ordinal);
- text = text.Replace(@"{\i}", "", StringComparison.Ordinal);
- if (CountTagInText(text, "") > CountTagInText(text, ""))
- {
- text += "";
- }
-
- text = text.Replace(@"{\u1}", "", StringComparison.Ordinal);
- text = text.Replace(@"{\u0}", "", StringComparison.Ordinal);
- text = text.Replace(@"{\u}", "", StringComparison.Ordinal);
- if (CountTagInText(text, "") > CountTagInText(text, ""))
- {
- text += "";
- }
-
- text = text.Replace(@"{\b1}", "", StringComparison.Ordinal);
- text = text.Replace(@"{\b0}", "", StringComparison.Ordinal);
- text = text.Replace(@"{\b}", "", StringComparison.Ordinal);
- if (CountTagInText(text, "") > CountTagInText(text, ""))
- {
- text += "";
- }
-
- return text;
- }
-
- private static bool IsInteger(string s)
- => int.TryParse(s, out _);
-
- private static int CountTagInText(string text, string tag)
- {
- int count = 0;
- int index = text.IndexOf(tag, StringComparison.Ordinal);
- while (index >= 0)
- {
- count++;
- if (index == text.Length)
- {
- return count;
- }
-
- index = text.IndexOf(tag, index + 1, StringComparison.Ordinal);
- }
-
- return count;
- }
-
- private static void CheckAndAddSubTags(ref string tagName, ref string extraTags, out bool italic)
- {
- italic = false;
- int indexOfSPlit = tagName.IndexOf('\\', StringComparison.Ordinal);
- if (indexOfSPlit > 0)
- {
- string rest = tagName.Substring(indexOfSPlit).TrimStart('\\');
- tagName = tagName.Remove(indexOfSPlit);
-
- for (int i = 0; i < 10; i++)
- {
- if (rest.StartsWith("fs", StringComparison.Ordinal) && rest.Length > 2)
- {
- indexOfSPlit = rest.IndexOf('\\', StringComparison.Ordinal);
- string fontSize = rest;
- if (indexOfSPlit > 0)
- {
- fontSize = rest.Substring(0, indexOfSPlit);
- rest = rest.Substring(indexOfSPlit).TrimStart('\\');
- }
- else
- {
- rest = string.Empty;
- }
-
- extraTags += " size=\"" + fontSize.Substring(2) + "\"";
- }
- else if (rest.StartsWith("fn", StringComparison.Ordinal) && rest.Length > 2)
- {
- indexOfSPlit = rest.IndexOf('\\', StringComparison.Ordinal);
- string fontName = rest;
- if (indexOfSPlit > 0)
- {
- fontName = rest.Substring(0, indexOfSPlit);
- rest = rest.Substring(indexOfSPlit).TrimStart('\\');
- }
- else
- {
- rest = string.Empty;
- }
-
- extraTags += " face=\"" + fontName.Substring(2) + "\"";
- }
- else if (rest.StartsWith("c", StringComparison.Ordinal) && rest.Length > 2)
- {
- indexOfSPlit = rest.IndexOf('\\', StringComparison.Ordinal);
- string fontColor = rest;
- if (indexOfSPlit > 0)
- {
- fontColor = rest.Substring(0, indexOfSPlit);
- rest = rest.Substring(indexOfSPlit).TrimStart('\\');
- }
- else
- {
- rest = string.Empty;
- }
-
- string color = fontColor.Substring(2);
- color = color.Replace("&", string.Empty, StringComparison.Ordinal).TrimStart('H');
- color = color.PadLeft(6, '0');
- // switch to rrggbb from bbggrr
- color = "#" + color.Remove(color.Length - 6) + color.Substring(color.Length - 2, 2) + color.Substring(color.Length - 4, 2) + color.Substring(color.Length - 6, 2);
- color = color.ToLowerInvariant();
-
- extraTags += " color=\"" + color + "\"";
- }
- else if (rest.StartsWith("i1", StringComparison.Ordinal) && rest.Length > 1)
- {
- indexOfSPlit = rest.IndexOf('\\', StringComparison.Ordinal);
- italic = true;
- if (indexOfSPlit > 0)
- {
- rest = rest.Substring(indexOfSPlit).TrimStart('\\');
- }
- else
- {
- rest = string.Empty;
- }
- }
- else if (rest.Length > 0 && rest.Contains('\\', StringComparison.Ordinal))
- {
- indexOfSPlit = rest.IndexOf('\\', StringComparison.Ordinal);
- rest = rest.Substring(indexOfSPlit).TrimStart('\\');
- }
- }
- }
}
}
}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs
new file mode 100644
index 000000000..82ec6ca21
--- /dev/null
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs
@@ -0,0 +1,63 @@
+#nullable enable
+
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Threading;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Model.MediaInfo;
+using Microsoft.Extensions.Logging;
+using Nikse.SubtitleEdit.Core;
+using ILogger = Microsoft.Extensions.Logging.ILogger;
+using SubtitleFormat = Nikse.SubtitleEdit.Core.SubtitleFormats.SubtitleFormat;
+
+namespace MediaBrowser.MediaEncoding.Subtitles
+{
+ ///
+ /// SubStation Alpha subtitle parser.
+ ///
+ /// The .
+ public abstract class SubtitleEditParser : ISubtitleParser
+ where T : SubtitleFormat, new()
+ {
+ private readonly ILogger _logger;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The logger.
+ protected SubtitleEditParser(ILogger logger)
+ {
+ _logger = logger;
+ }
+
+ ///
+ public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken)
+ {
+ var subtitle = new Subtitle();
+ var subRip = new T();
+ var lines = stream.ReadAllLines().ToList();
+ subRip.LoadSubtitle(subtitle, lines, "untitled");
+ if (subRip.ErrorCount > 0)
+ {
+ _logger.LogError("{ErrorCount} errors encountered while parsing subtitle.");
+ }
+
+ var trackInfo = new SubtitleTrackInfo();
+ int len = subtitle.Paragraphs.Count;
+ var trackEvents = new SubtitleTrackEvent[len];
+ for (int i = 0; i < len; i++)
+ {
+ var p = subtitle.Paragraphs[i];
+ trackEvents[i] = new SubtitleTrackEvent(p.Number.ToString(CultureInfo.InvariantCulture), p.Text)
+ {
+ StartPositionTicks = p.StartTime.TimeSpan.Ticks,
+ EndPositionTicks = p.EndTime.TimeSpan.Ticks
+ };
+ }
+
+ trackInfo.TrackEvents = trackEvents;
+ return trackInfo;
+ }
+ }
+}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index b92c4ee06..a9d118ef5 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -27,7 +27,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles
{
public class SubtitleEncoder : ISubtitleEncoder
{
- private readonly ILibraryManager _libraryManager;
private readonly ILogger _logger;
private readonly IApplicationPaths _appPaths;
private readonly IFileSystem _fileSystem;
@@ -42,7 +41,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles
new ConcurrentDictionary();
public SubtitleEncoder(
- ILibraryManager libraryManager,
ILogger logger,
IApplicationPaths appPaths,
IFileSystem fileSystem,
@@ -50,7 +48,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles
IHttpClientFactory httpClientFactory,
IMediaSourceManager mediaSourceManager)
{
- _libraryManager = libraryManager;
_logger = logger;
_appPaths = appPaths;
_fileSystem = fileSystem;
@@ -279,12 +276,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles
if (string.Equals(format, SubtitleFormat.SSA, StringComparison.OrdinalIgnoreCase))
{
- return new SsaParser();
+ return new SsaParser(_logger);
}
if (string.Equals(format, SubtitleFormat.ASS, StringComparison.OrdinalIgnoreCase))
{
- return new AssParser();
+ return new AssParser(_logger);
}
if (throwIfMissing)
diff --git a/MediaBrowser.Model/Channels/ChannelFeatures.cs b/MediaBrowser.Model/Channels/ChannelFeatures.cs
index a55754edd..d925b78b6 100644
--- a/MediaBrowser.Model/Channels/ChannelFeatures.cs
+++ b/MediaBrowser.Model/Channels/ChannelFeatures.cs
@@ -7,6 +7,13 @@ namespace MediaBrowser.Model.Channels
{
public class ChannelFeatures
{
+ public ChannelFeatures()
+ {
+ MediaTypes = Array.Empty();
+ ContentTypes = Array.Empty();
+ DefaultSortFields = Array.Empty();
+ }
+
///
/// Gets or sets the name.
///
@@ -38,7 +45,7 @@ namespace MediaBrowser.Model.Channels
public ChannelMediaContentType[] ContentTypes { get; set; }
///
- /// Represents the maximum number of records the channel allows retrieving at a time.
+ /// Gets or sets the maximum number of records the channel allows retrieving at a time.
///
public int? MaxPageSize { get; set; }
@@ -55,7 +62,7 @@ namespace MediaBrowser.Model.Channels
public ChannelItemSortField[] DefaultSortFields { get; set; }
///
- /// Indicates if a sort ascending/descending toggle is supported or not.
+ /// Gets or sets a value indicating whether a sort ascending/descending toggle is supported.
///
public bool SupportsSortOrderToggle { get; set; }
@@ -76,12 +83,5 @@ namespace MediaBrowser.Model.Channels
///
/// true if [supports content downloading]; otherwise, false.
public bool SupportsContentDownloading { get; set; }
-
- public ChannelFeatures()
- {
- MediaTypes = Array.Empty();
- ContentTypes = Array.Empty();
- DefaultSortFields = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/Channels/ChannelQuery.cs b/MediaBrowser.Model/Channels/ChannelQuery.cs
index fd90e7f06..59966127f 100644
--- a/MediaBrowser.Model/Channels/ChannelQuery.cs
+++ b/MediaBrowser.Model/Channels/ChannelQuery.cs
@@ -10,7 +10,7 @@ namespace MediaBrowser.Model.Channels
public class ChannelQuery
{
///
- /// Fields to return within the items, in addition to basic information.
+ /// Gets or sets the fields to return within the items, in addition to basic information.
///
/// The fields.
public ItemFields[] Fields { get; set; }
@@ -28,13 +28,13 @@ namespace MediaBrowser.Model.Channels
public Guid UserId { get; set; }
///
- /// Skips over a given number of items within the results. Use for paging.
+ /// Gets or sets the start index. Use for paging.
///
/// The start index.
public int? StartIndex { get; set; }
///
- /// The maximum number of items to return.
+ /// Gets or sets the maximum number of items to return.
///
/// The limit.
public int? Limit { get; set; }
diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs
index da467e133..a9b280301 100644
--- a/MediaBrowser.Model/Configuration/EncodingOptions.cs
+++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs
@@ -5,6 +5,41 @@ namespace MediaBrowser.Model.Configuration
{
public class EncodingOptions
{
+ public EncodingOptions()
+ {
+ EnableFallbackFont = false;
+ DownMixAudioBoost = 2;
+ MaxMuxingQueueSize = 2048;
+ EnableThrottling = false;
+ ThrottleDelaySeconds = 180;
+ EncodingThreadCount = -1;
+ // This is a DRM device that is almost guaranteed to be there on every intel platform,
+ // plus it's the default one in ffmpeg if you don't specify anything
+ VaapiDevice = "/dev/dri/renderD128";
+ // This is the OpenCL device that is used for tonemapping.
+ // The left side of the dot is the platform number, and the right side is the device number on the platform.
+ OpenclDevice = "0.0";
+ EnableTonemapping = false;
+ EnableVppTonemapping = false;
+ TonemappingAlgorithm = "hable";
+ TonemappingRange = "auto";
+ TonemappingDesat = 0;
+ TonemappingThreshold = 0.8;
+ TonemappingPeak = 100;
+ TonemappingParam = 0;
+ H264Crf = 23;
+ H265Crf = 28;
+ DeinterlaceDoubleRate = false;
+ DeinterlaceMethod = "yadif";
+ EnableDecodingColorDepth10Hevc = true;
+ EnableDecodingColorDepth10Vp9 = true;
+ EnableEnhancedNvdecDecoder = true;
+ EnableHardwareEncoding = true;
+ AllowHevcEncoding = true;
+ EnableSubtitleExtraction = true;
+ HardwareDecodingCodecs = new string[] { "h264", "vc1" };
+ }
+
public int EncodingThreadCount { get; set; }
public string TranscodingTempPath { get; set; }
@@ -24,12 +59,12 @@ namespace MediaBrowser.Model.Configuration
public string HardwareAccelerationType { get; set; }
///
- /// FFmpeg path as set by the user via the UI.
+ /// Gets or sets the FFmpeg path as set by the user via the UI.
///
public string EncoderAppPath { get; set; }
///
- /// The current FFmpeg path being used by the system and displayed on the transcode page.
+ /// Gets or sets the current FFmpeg path being used by the system and displayed on the transcode page.
///
public string EncoderAppPathDisplay { get; set; }
@@ -76,40 +111,5 @@ namespace MediaBrowser.Model.Configuration
public bool EnableSubtitleExtraction { get; set; }
public string[] HardwareDecodingCodecs { get; set; }
-
- public EncodingOptions()
- {
- EnableFallbackFont = false;
- DownMixAudioBoost = 2;
- MaxMuxingQueueSize = 2048;
- EnableThrottling = false;
- ThrottleDelaySeconds = 180;
- EncodingThreadCount = -1;
- // This is a DRM device that is almost guaranteed to be there on every intel platform,
- // plus it's the default one in ffmpeg if you don't specify anything
- VaapiDevice = "/dev/dri/renderD128";
- // This is the OpenCL device that is used for tonemapping.
- // The left side of the dot is the platform number, and the right side is the device number on the platform.
- OpenclDevice = "0.0";
- EnableTonemapping = false;
- EnableVppTonemapping = false;
- TonemappingAlgorithm = "hable";
- TonemappingRange = "auto";
- TonemappingDesat = 0;
- TonemappingThreshold = 0.8;
- TonemappingPeak = 100;
- TonemappingParam = 0;
- H264Crf = 23;
- H265Crf = 28;
- DeinterlaceDoubleRate = false;
- DeinterlaceMethod = "yadif";
- EnableDecodingColorDepth10Hevc = true;
- EnableDecodingColorDepth10Vp9 = true;
- EnableEnhancedNvdecDecoder = true;
- EnableHardwareEncoding = true;
- AllowHevcEncoding = true;
- EnableSubtitleExtraction = true;
- HardwareDecodingCodecs = new string[] { "h264", "vc1" };
- }
}
}
diff --git a/MediaBrowser.Model/Configuration/ImageOption.cs b/MediaBrowser.Model/Configuration/ImageOption.cs
index 2b1268c74..0af7b7e14 100644
--- a/MediaBrowser.Model/Configuration/ImageOption.cs
+++ b/MediaBrowser.Model/Configuration/ImageOption.cs
@@ -6,6 +6,11 @@ namespace MediaBrowser.Model.Configuration
{
public class ImageOption
{
+ public ImageOption()
+ {
+ Limit = 1;
+ }
+
///
/// Gets or sets the type.
///
@@ -23,10 +28,5 @@ namespace MediaBrowser.Model.Configuration
///
/// The minimum width.
public int MinWidth { get; set; }
-
- public ImageOption()
- {
- Limit = 1;
- }
}
}
diff --git a/MediaBrowser.Model/Configuration/LibraryOptions.cs b/MediaBrowser.Model/Configuration/LibraryOptions.cs
index 77ac11d69..24698360e 100644
--- a/MediaBrowser.Model/Configuration/LibraryOptions.cs
+++ b/MediaBrowser.Model/Configuration/LibraryOptions.cs
@@ -2,13 +2,30 @@
#pragma warning disable CS1591
using System;
-using System.Collections.Generic;
-using MediaBrowser.Model.Entities;
namespace MediaBrowser.Model.Configuration
{
public class LibraryOptions
{
+ public LibraryOptions()
+ {
+ TypeOptions = Array.Empty();
+ DisabledSubtitleFetchers = Array.Empty();
+ SubtitleFetcherOrder = Array.Empty();
+ DisabledLocalMetadataReaders = Array.Empty();
+
+ SkipSubtitlesIfAudioTrackMatches = true;
+ RequirePerfectSubtitleMatch = true;
+
+ EnablePhotos = true;
+ SaveSubtitlesWithMedia = true;
+ EnableRealtimeMonitor = true;
+ PathInfos = Array.Empty();
+ EnableInternetProviders = true;
+ EnableAutomaticSeriesGrouping = true;
+ SeasonZeroDisplayName = "Specials";
+ }
+
public bool EnablePhotos { get; set; }
public bool EnableRealtimeMonitor { get; set; }
@@ -79,387 +96,5 @@ namespace MediaBrowser.Model.Configuration
return null;
}
-
- public LibraryOptions()
- {
- TypeOptions = Array.Empty();
- DisabledSubtitleFetchers = Array.Empty();
- SubtitleFetcherOrder = Array.Empty();
- DisabledLocalMetadataReaders = Array.Empty();
-
- SkipSubtitlesIfAudioTrackMatches = true;
- RequirePerfectSubtitleMatch = true;
-
- EnablePhotos = true;
- SaveSubtitlesWithMedia = true;
- EnableRealtimeMonitor = true;
- PathInfos = Array.Empty();
- EnableInternetProviders = true;
- EnableAutomaticSeriesGrouping = true;
- SeasonZeroDisplayName = "Specials";
- }
- }
-
- public class MediaPathInfo
- {
- public string Path { get; set; }
-
- public string NetworkPath { get; set; }
- }
-
- public class TypeOptions
- {
- public string Type { get; set; }
-
- public string[] MetadataFetchers { get; set; }
-
- public string[] MetadataFetcherOrder { get; set; }
-
- public string[] ImageFetchers { get; set; }
-
- public string[] ImageFetcherOrder { get; set; }
-
- public ImageOption[] ImageOptions { get; set; }
-
- public ImageOption GetImageOptions(ImageType type)
- {
- foreach (var i in ImageOptions)
- {
- if (i.Type == type)
- {
- return i;
- }
- }
-
- if (DefaultImageOptions.TryGetValue(Type, out ImageOption[] options))
- {
- foreach (var i in options)
- {
- if (i.Type == type)
- {
- return i;
- }
- }
- }
-
- return DefaultInstance;
- }
-
- public int GetLimit(ImageType type)
- {
- return GetImageOptions(type).Limit;
- }
-
- public int GetMinWidth(ImageType type)
- {
- return GetImageOptions(type).MinWidth;
- }
-
- public bool IsEnabled(ImageType type)
- {
- return GetLimit(type) > 0;
- }
-
- public TypeOptions()
- {
- MetadataFetchers = Array.Empty();
- MetadataFetcherOrder = Array.Empty();
- ImageFetchers = Array.Empty();
- ImageFetcherOrder = Array.Empty();
- ImageOptions = Array.Empty();
- }
-
- public static Dictionary DefaultImageOptions = new Dictionary
- {
- {
- "Movie", new []
- {
- new ImageOption
- {
- Limit = 1,
- MinWidth = 1280,
- Type = ImageType.Backdrop
- },
-
- // Don't download this by default as it's rarely used.
- new ImageOption
- {
- Limit = 0,
- Type = ImageType.Art
- },
-
- // Don't download this by default as it's rarely used.
- new ImageOption
- {
- Limit = 0,
- Type = ImageType.Disc
- },
-
- new ImageOption
- {
- Limit = 1,
- Type = ImageType.Primary
- },
-
- new ImageOption
- {
- Limit = 0,
- Type = ImageType.Banner
- },
-
- new ImageOption
- {
- Limit = 1,
- Type = ImageType.Thumb
- },
-
- new ImageOption
- {
- Limit = 1,
- Type = ImageType.Logo
- }
- }
- },
- {
- "MusicVideo", new []
- {
- new ImageOption
- {
- Limit = 1,
- MinWidth = 1280,
- Type = ImageType.Backdrop
- },
-
- // Don't download this by default as it's rarely used.
- new ImageOption
- {
- Limit = 0,
- Type = ImageType.Art
- },
-
- // Don't download this by default as it's rarely used.
- new ImageOption
- {
- Limit = 0,
- Type = ImageType.Disc
- },
-
- new ImageOption
- {
- Limit = 1,
- Type = ImageType.Primary
- },
-
- new ImageOption
- {
- Limit = 0,
- Type = ImageType.Banner
- },
-
- new ImageOption
- {
- Limit = 1,
- Type = ImageType.Thumb
- },
-
- new ImageOption
- {
- Limit = 1,
- Type = ImageType.Logo
- }
- }
- },
- {
- "Series", new []
- {
- new ImageOption
- {
- Limit = 1,
- MinWidth = 1280,
- Type = ImageType.Backdrop
- },
-
- // Don't download this by default as it's rarely used.
- new ImageOption
- {
- Limit = 0,
- Type = ImageType.Art
- },
-
- new ImageOption
- {
- Limit = 1,
- Type = ImageType.Primary
- },
-
- new ImageOption
- {
- Limit = 1,
- Type = ImageType.Banner
- },
-
- new ImageOption
- {
- Limit = 1,
- Type = ImageType.Thumb
- },
-
- new ImageOption
- {
- Limit = 1,
- Type = ImageType.Logo
- }
- }
- },
- {
- "MusicAlbum", new []
- {
- new ImageOption
- {
- Limit = 0,
- MinWidth = 1280,
- Type = ImageType.Backdrop
- },
-
- // Don't download this by default as it's rarely used.
- new ImageOption
- {
- Limit = 0,
- Type = ImageType.Disc
- }
- }
- },
- {
- "MusicArtist", new []
- {
- new ImageOption
- {
- Limit = 1,
- MinWidth = 1280,
- Type = ImageType.Backdrop
- },
-
- // Don't download this by default
- // They do look great, but most artists won't have them, which means a banner view isn't really possible
- new ImageOption
- {
- Limit = 0,
- Type = ImageType.Banner
- },
-
- // Don't download this by default
- // Generally not used
- new ImageOption
- {
- Limit = 0,
- Type = ImageType.Art
- },
-
- new ImageOption
- {
- Limit = 1,
- Type = ImageType.Logo
- }
- }
- },
- {
- "BoxSet", new []
- {
- new ImageOption
- {
- Limit = 1,
- MinWidth = 1280,
- Type = ImageType.Backdrop
- },
-
- new ImageOption
- {
- Limit = 1,
- Type = ImageType.Primary
- },
-
- new ImageOption
- {
- Limit = 1,
- Type = ImageType.Thumb
- },
-
- new ImageOption
- {
- Limit = 1,
- Type = ImageType.Logo
- },
-
- // Don't download this by default as it's rarely used.
- new ImageOption
- {
- Limit = 0,
- Type = ImageType.Art
- },
-
- // Don't download this by default as it's rarely used.
- new ImageOption
- {
- Limit = 0,
- Type = ImageType.Disc
- },
-
- // Don't download this by default as it's rarely used.
- new ImageOption
- {
- Limit = 0,
- Type = ImageType.Banner
- }
- }
- },
- {
- "Season", new []
- {
- new ImageOption
- {
- Limit = 0,
- MinWidth = 1280,
- Type = ImageType.Backdrop
- },
-
- new ImageOption
- {
- Limit = 1,
- Type = ImageType.Primary
- },
-
- new ImageOption
- {
- Limit = 0,
- Type = ImageType.Banner
- },
-
- new ImageOption
- {
- Limit = 0,
- Type = ImageType.Thumb
- }
- }
- },
- {
- "Episode", new []
- {
- new ImageOption
- {
- Limit = 0,
- MinWidth = 1280,
- Type = ImageType.Backdrop
- },
-
- new ImageOption
- {
- Limit = 1,
- Type = ImageType.Primary
- }
- }
- }
- };
-
- public static ImageOption DefaultInstance = new ImageOption();
}
}
diff --git a/MediaBrowser.Model/Configuration/MediaPathInfo.cs b/MediaBrowser.Model/Configuration/MediaPathInfo.cs
new file mode 100644
index 000000000..4f311c58f
--- /dev/null
+++ b/MediaBrowser.Model/Configuration/MediaPathInfo.cs
@@ -0,0 +1,12 @@
+#nullable disable
+#pragma warning disable CS1591
+
+namespace MediaBrowser.Model.Configuration
+{
+ public class MediaPathInfo
+ {
+ public string Path { get; set; }
+
+ public string NetworkPath { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Configuration/MetadataConfiguration.cs b/MediaBrowser.Model/Configuration/MetadataConfiguration.cs
index 706831bdd..be044243d 100644
--- a/MediaBrowser.Model/Configuration/MetadataConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/MetadataConfiguration.cs
@@ -4,11 +4,11 @@ namespace MediaBrowser.Model.Configuration
{
public class MetadataConfiguration
{
- public bool UseFileCreationTimeForDateAdded { get; set; }
-
public MetadataConfiguration()
{
UseFileCreationTimeForDateAdded = true;
}
+
+ public bool UseFileCreationTimeForDateAdded { get; set; }
}
}
diff --git a/MediaBrowser.Model/Configuration/MetadataOptions.cs b/MediaBrowser.Model/Configuration/MetadataOptions.cs
index e7dc3da3c..76b72bd08 100644
--- a/MediaBrowser.Model/Configuration/MetadataOptions.cs
+++ b/MediaBrowser.Model/Configuration/MetadataOptions.cs
@@ -10,6 +10,16 @@ namespace MediaBrowser.Model.Configuration
///
public class MetadataOptions
{
+ public MetadataOptions()
+ {
+ DisabledMetadataSavers = Array.Empty();
+ LocalMetadataReaderOrder = Array.Empty();
+ DisabledMetadataFetchers = Array.Empty();
+ MetadataFetcherOrder = Array.Empty();
+ DisabledImageFetchers = Array.Empty();
+ ImageFetcherOrder = Array.Empty();
+ }
+
public string ItemType { get; set; }
public string[] DisabledMetadataSavers { get; set; }
@@ -23,15 +33,5 @@ namespace MediaBrowser.Model.Configuration
public string[] DisabledImageFetchers { get; set; }
public string[] ImageFetcherOrder { get; set; }
-
- public MetadataOptions()
- {
- DisabledMetadataSavers = Array.Empty();
- LocalMetadataReaderOrder = Array.Empty();
- DisabledMetadataFetchers = Array.Empty();
- MetadataFetcherOrder = Array.Empty();
- DisabledImageFetchers = Array.Empty();
- ImageFetcherOrder = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/Configuration/MetadataPluginSummary.cs b/MediaBrowser.Model/Configuration/MetadataPluginSummary.cs
index 0c197ee02..aa07d6623 100644
--- a/MediaBrowser.Model/Configuration/MetadataPluginSummary.cs
+++ b/MediaBrowser.Model/Configuration/MetadataPluginSummary.cs
@@ -8,6 +8,12 @@ namespace MediaBrowser.Model.Configuration
{
public class MetadataPluginSummary
{
+ public MetadataPluginSummary()
+ {
+ SupportedImageTypes = Array.Empty();
+ Plugins = Array.Empty();
+ }
+
///
/// Gets or sets the type of the item.
///
@@ -25,11 +31,5 @@ namespace MediaBrowser.Model.Configuration
///
/// The supported image types.
public ImageType[] SupportedImageTypes { get; set; }
-
- public MetadataPluginSummary()
- {
- SupportedImageTypes = Array.Empty();
- Plugins = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index 0f0ad0f9a..d1e999666 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -254,7 +254,7 @@ namespace MediaBrowser.Model.Configuration
/// Gets or sets the preferred metadata language.
///
/// The preferred metadata language.
- public string PreferredMetadataLanguage { get; set; } = string.Empty;
+ public string PreferredMetadataLanguage { get; set; } = "en";
///
/// Gets or sets the metadata country code.
@@ -418,8 +418,6 @@ namespace MediaBrowser.Model.Configuration
public PathSubstitution[] PathSubstitutions { get; set; } = Array.Empty();
- public bool EnableSimpleArtistDetection { get; set; } = false;
-
public string[] UninstalledPlugins { get; set; } = Array.Empty();
///
@@ -461,10 +459,5 @@ namespace MediaBrowser.Model.Configuration
/// Gets or sets a value indicating whether older plugins should automatically be deleted from the plugin folder.
///
public bool RemoveOldPlugins { get; set; }
-
- ///
- /// Gets or sets a value indicating whether plugin image should be disabled.
- ///
- public bool DisablePluginImages { get; set; }
}
}
diff --git a/MediaBrowser.Model/Configuration/TypeOptions.cs b/MediaBrowser.Model/Configuration/TypeOptions.cs
new file mode 100644
index 000000000..d0179e5aa
--- /dev/null
+++ b/MediaBrowser.Model/Configuration/TypeOptions.cs
@@ -0,0 +1,365 @@
+#nullable disable
+#pragma warning disable CS1591
+
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Model.Entities;
+
+namespace MediaBrowser.Model.Configuration
+{
+ public class TypeOptions
+ {
+ public static readonly ImageOption DefaultInstance = new ImageOption();
+
+ public static readonly Dictionary DefaultImageOptions = new Dictionary
+ {
+ {
+ "Movie", new[]
+ {
+ new ImageOption
+ {
+ Limit = 1,
+ MinWidth = 1280,
+ Type = ImageType.Backdrop
+ },
+
+ // Don't download this by default as it's rarely used.
+ new ImageOption
+ {
+ Limit = 0,
+ Type = ImageType.Art
+ },
+
+ // Don't download this by default as it's rarely used.
+ new ImageOption
+ {
+ Limit = 0,
+ Type = ImageType.Disc
+ },
+
+ new ImageOption
+ {
+ Limit = 1,
+ Type = ImageType.Primary
+ },
+
+ new ImageOption
+ {
+ Limit = 0,
+ Type = ImageType.Banner
+ },
+
+ new ImageOption
+ {
+ Limit = 1,
+ Type = ImageType.Thumb
+ },
+
+ new ImageOption
+ {
+ Limit = 1,
+ Type = ImageType.Logo
+ }
+ }
+ },
+ {
+ "MusicVideo", new[]
+ {
+ new ImageOption
+ {
+ Limit = 1,
+ MinWidth = 1280,
+ Type = ImageType.Backdrop
+ },
+
+ // Don't download this by default as it's rarely used.
+ new ImageOption
+ {
+ Limit = 0,
+ Type = ImageType.Art
+ },
+
+ // Don't download this by default as it's rarely used.
+ new ImageOption
+ {
+ Limit = 0,
+ Type = ImageType.Disc
+ },
+
+ new ImageOption
+ {
+ Limit = 1,
+ Type = ImageType.Primary
+ },
+
+ new ImageOption
+ {
+ Limit = 0,
+ Type = ImageType.Banner
+ },
+
+ new ImageOption
+ {
+ Limit = 1,
+ Type = ImageType.Thumb
+ },
+
+ new ImageOption
+ {
+ Limit = 1,
+ Type = ImageType.Logo
+ }
+ }
+ },
+ {
+ "Series", new[]
+ {
+ new ImageOption
+ {
+ Limit = 1,
+ MinWidth = 1280,
+ Type = ImageType.Backdrop
+ },
+
+ // Don't download this by default as it's rarely used.
+ new ImageOption
+ {
+ Limit = 0,
+ Type = ImageType.Art
+ },
+
+ new ImageOption
+ {
+ Limit = 1,
+ Type = ImageType.Primary
+ },
+
+ new ImageOption
+ {
+ Limit = 1,
+ Type = ImageType.Banner
+ },
+
+ new ImageOption
+ {
+ Limit = 1,
+ Type = ImageType.Thumb
+ },
+
+ new ImageOption
+ {
+ Limit = 1,
+ Type = ImageType.Logo
+ }
+ }
+ },
+ {
+ "MusicAlbum", new[]
+ {
+ new ImageOption
+ {
+ Limit = 0,
+ MinWidth = 1280,
+ Type = ImageType.Backdrop
+ },
+
+ // Don't download this by default as it's rarely used.
+ new ImageOption
+ {
+ Limit = 0,
+ Type = ImageType.Disc
+ }
+ }
+ },
+ {
+ "MusicArtist", new[]
+ {
+ new ImageOption
+ {
+ Limit = 1,
+ MinWidth = 1280,
+ Type = ImageType.Backdrop
+ },
+
+ // Don't download this by default
+ // They do look great, but most artists won't have them, which means a banner view isn't really possible
+ new ImageOption
+ {
+ Limit = 0,
+ Type = ImageType.Banner
+ },
+
+ // Don't download this by default
+ // Generally not used
+ new ImageOption
+ {
+ Limit = 0,
+ Type = ImageType.Art
+ },
+
+ new ImageOption
+ {
+ Limit = 1,
+ Type = ImageType.Logo
+ }
+ }
+ },
+ {
+ "BoxSet", new[]
+ {
+ new ImageOption
+ {
+ Limit = 1,
+ MinWidth = 1280,
+ Type = ImageType.Backdrop
+ },
+
+ new ImageOption
+ {
+ Limit = 1,
+ Type = ImageType.Primary
+ },
+
+ new ImageOption
+ {
+ Limit = 1,
+ Type = ImageType.Thumb
+ },
+
+ new ImageOption
+ {
+ Limit = 1,
+ Type = ImageType.Logo
+ },
+
+ // Don't download this by default as it's rarely used.
+ new ImageOption
+ {
+ Limit = 0,
+ Type = ImageType.Art
+ },
+
+ // Don't download this by default as it's rarely used.
+ new ImageOption
+ {
+ Limit = 0,
+ Type = ImageType.Disc
+ },
+
+ // Don't download this by default as it's rarely used.
+ new ImageOption
+ {
+ Limit = 0,
+ Type = ImageType.Banner
+ }
+ }
+ },
+ {
+ "Season", new[]
+ {
+ new ImageOption
+ {
+ Limit = 0,
+ MinWidth = 1280,
+ Type = ImageType.Backdrop
+ },
+
+ new ImageOption
+ {
+ Limit = 1,
+ Type = ImageType.Primary
+ },
+
+ new ImageOption
+ {
+ Limit = 0,
+ Type = ImageType.Banner
+ },
+
+ new ImageOption
+ {
+ Limit = 0,
+ Type = ImageType.Thumb
+ }
+ }
+ },
+ {
+ "Episode", new[]
+ {
+ new ImageOption
+ {
+ Limit = 0,
+ MinWidth = 1280,
+ Type = ImageType.Backdrop
+ },
+
+ new ImageOption
+ {
+ Limit = 1,
+ Type = ImageType.Primary
+ }
+ }
+ }
+ };
+
+ public TypeOptions()
+ {
+ MetadataFetchers = Array.Empty();
+ MetadataFetcherOrder = Array.Empty();
+ ImageFetchers = Array.Empty();
+ ImageFetcherOrder = Array.Empty();
+ ImageOptions = Array.Empty();
+ }
+
+ public string Type { get; set; }
+
+ public string[] MetadataFetchers { get; set; }
+
+ public string[] MetadataFetcherOrder { get; set; }
+
+ public string[] ImageFetchers { get; set; }
+
+ public string[] ImageFetcherOrder { get; set; }
+
+ public ImageOption[] ImageOptions { get; set; }
+
+ public ImageOption GetImageOptions(ImageType type)
+ {
+ foreach (var i in ImageOptions)
+ {
+ if (i.Type == type)
+ {
+ return i;
+ }
+ }
+
+ if (DefaultImageOptions.TryGetValue(Type, out ImageOption[] options))
+ {
+ foreach (var i in options)
+ {
+ if (i.Type == type)
+ {
+ return i;
+ }
+ }
+ }
+
+ return DefaultInstance;
+ }
+
+ public int GetLimit(ImageType type)
+ {
+ return GetImageOptions(type).Limit;
+ }
+
+ public int GetMinWidth(ImageType type)
+ {
+ return GetImageOptions(type).MinWidth;
+ }
+
+ public bool IsEnabled(ImageType type)
+ {
+ return GetLimit(type) > 0;
+ }
+ }
+}
diff --git a/MediaBrowser.Model/Configuration/UserConfiguration.cs b/MediaBrowser.Model/Configuration/UserConfiguration.cs
index cc0e0c468..935e6cbe1 100644
--- a/MediaBrowser.Model/Configuration/UserConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/UserConfiguration.cs
@@ -11,6 +11,24 @@ namespace MediaBrowser.Model.Configuration
///
public class UserConfiguration
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public UserConfiguration()
+ {
+ EnableNextEpisodeAutoPlay = true;
+ RememberAudioSelections = true;
+ RememberSubtitleSelections = true;
+
+ HidePlayedInLatest = true;
+ PlayDefaultAudioTrack = true;
+
+ LatestItemsExcludes = Array.Empty();
+ OrderedViews = Array.Empty();
+ MyMediaExcludes = Array.Empty();
+ GroupedFolders = Array.Empty();
+ }
+
///
/// Gets or sets the audio language preference.
///
@@ -52,23 +70,5 @@ namespace MediaBrowser.Model.Configuration
public bool RememberSubtitleSelections { get; set; }
public bool EnableNextEpisodeAutoPlay { get; set; }
-
- ///
- /// Initializes a new instance of the class.
- ///
- public UserConfiguration()
- {
- EnableNextEpisodeAutoPlay = true;
- RememberAudioSelections = true;
- RememberSubtitleSelections = true;
-
- HidePlayedInLatest = true;
- PlayDefaultAudioTrack = true;
-
- LatestItemsExcludes = Array.Empty();
- OrderedViews = Array.Empty();
- MyMediaExcludes = Array.Empty();
- GroupedFolders = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs b/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs
index 4d5f996f8..8ad070dcb 100644
--- a/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs
+++ b/MediaBrowser.Model/Configuration/XbmcMetadataOptions.cs
@@ -5,6 +5,14 @@ namespace MediaBrowser.Model.Configuration
{
public class XbmcMetadataOptions
{
+ public XbmcMetadataOptions()
+ {
+ ReleaseDateFormat = "yyyy-MM-dd";
+
+ SaveImagePathsInNfo = true;
+ EnablePathSubstitution = true;
+ }
+
public string UserId { get; set; }
public string ReleaseDateFormat { get; set; }
@@ -14,13 +22,5 @@ namespace MediaBrowser.Model.Configuration
public bool EnablePathSubstitution { get; set; }
public bool EnableExtraThumbsDuplication { get; set; }
-
- public XbmcMetadataOptions()
- {
- ReleaseDateFormat = "yyyy-MM-dd";
-
- SaveImagePathsInNfo = true;
- EnablePathSubstitution = true;
- }
}
}
diff --git a/MediaBrowser.Model/Dlna/AudioOptions.cs b/MediaBrowser.Model/Dlna/AudioOptions.cs
index bbb8bf426..4d4d8d78c 100644
--- a/MediaBrowser.Model/Dlna/AudioOptions.cs
+++ b/MediaBrowser.Model/Dlna/AudioOptions.cs
@@ -34,20 +34,20 @@ namespace MediaBrowser.Model.Dlna
public DeviceProfile Profile { get; set; }
///
- /// Optional. Only needed if a specific AudioStreamIndex or SubtitleStreamIndex are requested.
+ /// Gets or sets a media source id. Optional. Only needed if a specific AudioStreamIndex or SubtitleStreamIndex are requested.
///
public string MediaSourceId { get; set; }
public string DeviceId { get; set; }
///
- /// Allows an override of supported number of audio channels
- /// Example: DeviceProfile supports five channel, but user only has stereo speakers
+ /// Gets or sets an override of supported number of audio channels
+ /// Example: DeviceProfile supports five channel, but user only has stereo speakers.
///
public int? MaxAudioChannels { get; set; }
///
- /// The application's configured quality setting.
+ /// Gets or sets the application's configured quality setting.
///
public int? MaxBitrate { get; set; }
@@ -66,6 +66,7 @@ namespace MediaBrowser.Model.Dlna
///
/// Gets the maximum bitrate.
///
+ /// Whether or not this is audio.
/// System.Nullable<System.Int32>.
public int? GetMaxBitrate(bool isAudio)
{
diff --git a/MediaBrowser.Model/Dlna/CodecProfile.cs b/MediaBrowser.Model/Dlna/CodecProfile.cs
index d4fd3e673..8343cf028 100644
--- a/MediaBrowser.Model/Dlna/CodecProfile.cs
+++ b/MediaBrowser.Model/Dlna/CodecProfile.cs
@@ -9,6 +9,12 @@ namespace MediaBrowser.Model.Dlna
{
public class CodecProfile
{
+ public CodecProfile()
+ {
+ Conditions = Array.Empty();
+ ApplyConditions = Array.Empty();
+ }
+
[XmlAttribute("type")]
public CodecType Type { get; set; }
@@ -22,12 +28,6 @@ namespace MediaBrowser.Model.Dlna
[XmlAttribute("container")]
public string Container { get; set; }
- public CodecProfile()
- {
- Conditions = Array.Empty();
- ApplyConditions = Array.Empty();
- }
-
public string[] GetCodecs()
{
return ContainerProfile.SplitValue(Codec);
diff --git a/MediaBrowser.Model/Dlna/ConditionProcessor.cs b/MediaBrowser.Model/Dlna/ConditionProcessor.cs
index faf1ee41b..55c4dd074 100644
--- a/MediaBrowser.Model/Dlna/ConditionProcessor.cs
+++ b/MediaBrowser.Model/Dlna/ConditionProcessor.cs
@@ -1,8 +1,8 @@
#pragma warning disable CS1591
using System;
-using System.Linq;
using System.Globalization;
+using System.Linq;
using MediaBrowser.Model.MediaInfo;
namespace MediaBrowser.Model.Dlna
diff --git a/MediaBrowser.Model/Dlna/ContainerProfile.cs b/MediaBrowser.Model/Dlna/ContainerProfile.cs
index 56c89d854..d83c8f2f3 100644
--- a/MediaBrowser.Model/Dlna/ContainerProfile.cs
+++ b/MediaBrowser.Model/Dlna/ContainerProfile.cs
@@ -9,6 +9,11 @@ namespace MediaBrowser.Model.Dlna
{
public class ContainerProfile
{
+ public ContainerProfile()
+ {
+ Conditions = Array.Empty();
+ }
+
[XmlAttribute("type")]
public DlnaProfileType Type { get; set; }
@@ -17,11 +22,6 @@ namespace MediaBrowser.Model.Dlna
[XmlAttribute("container")]
public string Container { get; set; }
- public ContainerProfile()
- {
- Conditions = Array.Empty();
- }
-
public string[] GetContainers()
{
return SplitValue(Container);
diff --git a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
index 50e3374f7..ec106f105 100644
--- a/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
+++ b/MediaBrowser.Model/Dlna/ContentFeatureBuilder.cs
@@ -81,13 +81,13 @@ namespace MediaBrowser.Model.Dlna
DlnaFlags.DlnaV15;
// if (isDirectStream)
- //{
- // flagValue = flagValue | DlnaFlags.ByteBasedSeek;
- //}
- // else if (runtimeTicks.HasValue)
- //{
- // flagValue = flagValue | DlnaFlags.TimeBasedSeek;
- //}
+ // {
+ // flagValue = flagValue | DlnaFlags.ByteBasedSeek;
+ // }
+ // else if (runtimeTicks.HasValue)
+ // {
+ // flagValue = flagValue | DlnaFlags.TimeBasedSeek;
+ // }
string dlnaflags = string.Format(
CultureInfo.InvariantCulture,
@@ -150,16 +150,18 @@ namespace MediaBrowser.Model.Dlna
DlnaFlags.DlnaV15;
// if (isDirectStream)
- //{
- // flagValue = flagValue | DlnaFlags.ByteBasedSeek;
- //}
- // else if (runtimeTicks.HasValue)
- //{
- // flagValue = flagValue | DlnaFlags.TimeBasedSeek;
- //}
+ // {
+ // flagValue = flagValue | DlnaFlags.ByteBasedSeek;
+ // }
+ // else if (runtimeTicks.HasValue)
+ // {
+ // flagValue = flagValue | DlnaFlags.TimeBasedSeek;
+ // }
- string dlnaflags = string.Format(CultureInfo.InvariantCulture, ";DLNA.ORG_FLAGS={0}",
- DlnaMaps.FlagsToString(flagValue));
+ string dlnaflags = string.Format(
+ CultureInfo.InvariantCulture,
+ ";DLNA.ORG_FLAGS={0}",
+ DlnaMaps.FlagsToString(flagValue));
ResponseProfile mediaProfile = _profile.GetVideoMediaProfile(
container,
diff --git a/MediaBrowser.Model/Dlna/IDeviceDiscovery.cs b/MediaBrowser.Model/Dlna/IDeviceDiscovery.cs
index 05209e53d..086088dea 100644
--- a/MediaBrowser.Model/Dlna/IDeviceDiscovery.cs
+++ b/MediaBrowser.Model/Dlna/IDeviceDiscovery.cs
@@ -8,6 +8,7 @@ namespace MediaBrowser.Model.Dlna
public interface IDeviceDiscovery
{
event EventHandler> DeviceDiscovered;
+
event EventHandler> DeviceLeft;
}
}
diff --git a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs
index 3c955989a..f61b8d59e 100644
--- a/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs
+++ b/MediaBrowser.Model/Dlna/MediaFormatProfileResolver.cs
@@ -57,7 +57,6 @@ namespace MediaBrowser.Model.Dlna
string.Equals(container, "mpegts", StringComparison.OrdinalIgnoreCase) ||
string.Equals(container, "m2ts", StringComparison.OrdinalIgnoreCase))
{
-
return ResolveVideoMPEG2TSFormat(videoCodec, audioCodec, width, height, timestampType);
}
@@ -323,7 +322,6 @@ namespace MediaBrowser.Model.Dlna
if (string.Equals(videoCodec, "wmv", StringComparison.OrdinalIgnoreCase) &&
(string.IsNullOrEmpty(audioCodec) || string.Equals(audioCodec, "wma", StringComparison.OrdinalIgnoreCase) || string.Equals(videoCodec, "wmapro", StringComparison.OrdinalIgnoreCase)))
{
-
if (width.HasValue && height.HasValue)
{
if ((width.Value <= 720) && (height.Value <= 576))
@@ -479,7 +477,9 @@ namespace MediaBrowser.Model.Dlna
{
if (string.Equals(container, "jpeg", StringComparison.OrdinalIgnoreCase) ||
string.Equals(container, "jpg", StringComparison.OrdinalIgnoreCase))
+ {
return ResolveImageJPGFormat(width, height);
+ }
if (string.Equals(container, "png", StringComparison.OrdinalIgnoreCase))
{
diff --git a/MediaBrowser.Model/Dlna/ResolutionConfiguration.cs b/MediaBrowser.Model/Dlna/ResolutionConfiguration.cs
index 30c44fbe0..f8f76c69d 100644
--- a/MediaBrowser.Model/Dlna/ResolutionConfiguration.cs
+++ b/MediaBrowser.Model/Dlna/ResolutionConfiguration.cs
@@ -4,14 +4,14 @@ namespace MediaBrowser.Model.Dlna
{
public class ResolutionConfiguration
{
- public int MaxWidth { get; set; }
-
- public int MaxBitrate { get; set; }
-
public ResolutionConfiguration(int maxWidth, int maxBitrate)
{
MaxWidth = maxWidth;
MaxBitrate = maxBitrate;
}
+
+ public int MaxWidth { get; set; }
+
+ public int MaxBitrate { get; set; }
}
}
diff --git a/MediaBrowser.Model/Dlna/ResponseProfile.cs b/MediaBrowser.Model/Dlna/ResponseProfile.cs
index 48f53f06c..bf9661f7f 100644
--- a/MediaBrowser.Model/Dlna/ResponseProfile.cs
+++ b/MediaBrowser.Model/Dlna/ResponseProfile.cs
@@ -8,6 +8,11 @@ namespace MediaBrowser.Model.Dlna
{
public class ResponseProfile
{
+ public ResponseProfile()
+ {
+ Conditions = Array.Empty();
+ }
+
[XmlAttribute("container")]
public string Container { get; set; }
@@ -28,11 +33,6 @@ namespace MediaBrowser.Model.Dlna
public ProfileCondition[] Conditions { get; set; }
- public ResponseProfile()
- {
- Conditions = Array.Empty();
- }
-
public string[] GetContainers()
{
return ContainerProfile.SplitValue(Container);
diff --git a/MediaBrowser.Model/Dlna/SearchCriteria.cs b/MediaBrowser.Model/Dlna/SearchCriteria.cs
index 94f5bd3db..b1fc48c08 100644
--- a/MediaBrowser.Model/Dlna/SearchCriteria.cs
+++ b/MediaBrowser.Model/Dlna/SearchCriteria.cs
@@ -7,6 +7,46 @@ namespace MediaBrowser.Model.Dlna
{
public class SearchCriteria
{
+ public SearchCriteria(string search)
+ {
+ if (search.Length == 0)
+ {
+ throw new ArgumentException("String can't be empty.", nameof(search));
+ }
+
+ SearchType = SearchType.Unknown;
+
+ string[] factors = RegexSplit(search, "(and|or)");
+ foreach (string factor in factors)
+ {
+ string[] subFactors = RegexSplit(factor.Trim().Trim('(').Trim(')').Trim(), "\\s", 3);
+
+ if (subFactors.Length == 3)
+ {
+ if (string.Equals("upnp:class", subFactors[0], StringComparison.OrdinalIgnoreCase)
+ && (string.Equals("=", subFactors[1], StringComparison.Ordinal) || string.Equals("derivedfrom", subFactors[1], StringComparison.OrdinalIgnoreCase)))
+ {
+ if (string.Equals("\"object.item.imageItem\"", subFactors[2], StringComparison.Ordinal) || string.Equals("\"object.item.imageItem.photo\"", subFactors[2], StringComparison.OrdinalIgnoreCase))
+ {
+ SearchType = SearchType.Image;
+ }
+ else if (string.Equals("\"object.item.videoItem\"", subFactors[2], StringComparison.OrdinalIgnoreCase))
+ {
+ SearchType = SearchType.Video;
+ }
+ else if (string.Equals("\"object.container.playlistContainer\"", subFactors[2], StringComparison.OrdinalIgnoreCase))
+ {
+ SearchType = SearchType.Playlist;
+ }
+ else if (string.Equals("\"object.container.album.musicAlbum\"", subFactors[2], StringComparison.OrdinalIgnoreCase))
+ {
+ SearchType = SearchType.MusicAlbum;
+ }
+ }
+ }
+ }
+ }
+
public SearchType SearchType { get; set; }
///
@@ -31,45 +71,5 @@ namespace MediaBrowser.Model.Dlna
{
return Regex.Split(str, term, RegexOptions.IgnoreCase);
}
-
- public SearchCriteria(string search)
- {
- if (search.Length == 0)
- {
- throw new ArgumentException("String can't be empty.", nameof(search));
- }
-
- SearchType = SearchType.Unknown;
-
- string[] factors = RegexSplit(search, "(and|or)");
- foreach (string factor in factors)
- {
- string[] subFactors = RegexSplit(factor.Trim().Trim('(').Trim(')').Trim(), "\\s", 3);
-
- if (subFactors.Length == 3)
- {
- if (string.Equals("upnp:class", subFactors[0], StringComparison.OrdinalIgnoreCase) &&
- (string.Equals("=", subFactors[1], StringComparison.Ordinal) || string.Equals("derivedfrom", subFactors[1], StringComparison.OrdinalIgnoreCase)))
- {
- if (string.Equals("\"object.item.imageItem\"", subFactors[2], StringComparison.Ordinal) || string.Equals("\"object.item.imageItem.photo\"", subFactors[2], StringComparison.OrdinalIgnoreCase))
- {
- SearchType = SearchType.Image;
- }
- else if (string.Equals("\"object.item.videoItem\"", subFactors[2], StringComparison.OrdinalIgnoreCase))
- {
- SearchType = SearchType.Video;
- }
- else if (string.Equals("\"object.container.playlistContainer\"", subFactors[2], StringComparison.OrdinalIgnoreCase))
- {
- SearchType = SearchType.Playlist;
- }
- else if (string.Equals("\"object.container.album.musicAlbum\"", subFactors[2], StringComparison.OrdinalIgnoreCase))
- {
- SearchType = SearchType.MusicAlbum;
- }
- }
- }
- }
- }
}
}
diff --git a/MediaBrowser.Model/Dlna/SortCriteria.cs b/MediaBrowser.Model/Dlna/SortCriteria.cs
index 53e4540cb..7769d0bd3 100644
--- a/MediaBrowser.Model/Dlna/SortCriteria.cs
+++ b/MediaBrowser.Model/Dlna/SortCriteria.cs
@@ -6,10 +6,10 @@ namespace MediaBrowser.Model.Dlna
{
public class SortCriteria
{
- public SortOrder SortOrder => SortOrder.Ascending;
-
public SortCriteria(string value)
{
}
+
+ public SortOrder SortOrder => SortOrder.Ascending;
}
}
diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs
index 431cf0baf..bf33691c7 100644
--- a/MediaBrowser.Model/Dlna/StreamBuilder.cs
+++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs
@@ -227,7 +227,7 @@ namespace MediaBrowser.Model.Dlna
}
}
- public static string NormalizeMediaSourceFormatIntoSingleContainer(string inputContainer, string _, DeviceProfile profile, DlnaProfileType type)
+ public static string NormalizeMediaSourceFormatIntoSingleContainer(string inputContainer, DeviceProfile profile, DlnaProfileType type)
{
if (string.IsNullOrEmpty(inputContainer))
{
@@ -274,14 +274,14 @@ namespace MediaBrowser.Model.Dlna
if (options.ForceDirectPlay)
{
playlistItem.PlayMethod = PlayMethod.DirectPlay;
- playlistItem.Container = NormalizeMediaSourceFormatIntoSingleContainer(item.Container, item.Path, options.Profile, DlnaProfileType.Audio);
+ playlistItem.Container = NormalizeMediaSourceFormatIntoSingleContainer(item.Container, options.Profile, DlnaProfileType.Audio);
return playlistItem;
}
if (options.ForceDirectStream)
{
playlistItem.PlayMethod = PlayMethod.DirectStream;
- playlistItem.Container = NormalizeMediaSourceFormatIntoSingleContainer(item.Container, item.Path, options.Profile, DlnaProfileType.Audio);
+ playlistItem.Container = NormalizeMediaSourceFormatIntoSingleContainer(item.Container, options.Profile, DlnaProfileType.Audio);
return playlistItem;
}
@@ -349,7 +349,7 @@ namespace MediaBrowser.Model.Dlna
playlistItem.PlayMethod = PlayMethod.DirectStream;
}
- playlistItem.Container = NormalizeMediaSourceFormatIntoSingleContainer(item.Container, item.Path, options.Profile, DlnaProfileType.Audio);
+ playlistItem.Container = NormalizeMediaSourceFormatIntoSingleContainer(item.Container, options.Profile, DlnaProfileType.Audio);
return playlistItem;
}
@@ -698,7 +698,7 @@ namespace MediaBrowser.Model.Dlna
if (directPlay != null)
{
playlistItem.PlayMethod = directPlay.Value;
- playlistItem.Container = NormalizeMediaSourceFormatIntoSingleContainer(item.Container, item.Path, options.Profile, DlnaProfileType.Video);
+ playlistItem.Container = NormalizeMediaSourceFormatIntoSingleContainer(item.Container, options.Profile, DlnaProfileType.Video);
if (subtitleStream != null)
{
@@ -1404,7 +1404,9 @@ namespace MediaBrowser.Model.Dlna
{
_logger.LogInformation(
"Bitrate exceeds {PlayBackMethod} limit: media bitrate: {MediaBitrate}, max bitrate: {MaxBitrate}",
- playMethod, itemBitrate, requestedMaxBitrate);
+ playMethod,
+ itemBitrate,
+ requestedMaxBitrate);
return false;
}
@@ -1733,7 +1735,7 @@ namespace MediaBrowser.Model.Dlna
if (condition.Condition == ProfileConditionType.Equals || condition.Condition == ProfileConditionType.EqualsAny)
{
- item.SetOption(qualifier, "profile", string.Join(",", values));
+ item.SetOption(qualifier, "profile", string.Join(',', values));
}
}
diff --git a/MediaBrowser.Model/Dlna/StreamInfo.cs b/MediaBrowser.Model/Dlna/StreamInfo.cs
index 55b12ae81..29da5d9e7 100644
--- a/MediaBrowser.Model/Dlna/StreamInfo.cs
+++ b/MediaBrowser.Model/Dlna/StreamInfo.cs
@@ -27,45 +27,6 @@ namespace MediaBrowser.Model.Dlna
StreamOptions = new Dictionary(StringComparer.OrdinalIgnoreCase);
}
- public void SetOption(string qualifier, string name, string value)
- {
- if (string.IsNullOrEmpty(qualifier))
- {
- SetOption(name, value);
- }
- else
- {
- SetOption(qualifier + "-" + name, value);
- }
- }
-
- public void SetOption(string name, string value)
- {
- StreamOptions[name] = value;
- }
-
- public string GetOption(string qualifier, string name)
- {
- var value = GetOption(qualifier + "-" + name);
-
- if (string.IsNullOrEmpty(value))
- {
- value = GetOption(name);
- }
-
- return value;
- }
-
- public string GetOption(string name)
- {
- if (StreamOptions.TryGetValue(name, out var value))
- {
- return value;
- }
-
- return null;
- }
-
public Guid ItemId { get; set; }
public PlayMethod PlayMethod { get; set; }
@@ -152,6 +113,490 @@ namespace MediaBrowser.Model.Dlna
PlayMethod == PlayMethod.DirectStream ||
PlayMethod == PlayMethod.DirectPlay;
+ ///
+ /// Gets the audio stream that will be used.
+ ///
+ public MediaStream TargetAudioStream => MediaSource?.GetDefaultAudioStream(AudioStreamIndex);
+
+ ///
+ /// Gets the video stream that will be used.
+ ///
+ public MediaStream TargetVideoStream => MediaSource?.VideoStream;
+
+ ///
+ /// Gets the audio sample rate that will be in the output stream.
+ ///
+ public int? TargetAudioSampleRate
+ {
+ get
+ {
+ var stream = TargetAudioStream;
+ return AudioSampleRate.HasValue && !IsDirectStream
+ ? AudioSampleRate
+ : stream == null ? null : stream.SampleRate;
+ }
+ }
+
+ ///
+ /// Gets the audio sample rate that will be in the output stream.
+ ///
+ public int? TargetAudioBitDepth
+ {
+ get
+ {
+ if (IsDirectStream)
+ {
+ return TargetAudioStream == null ? (int?)null : TargetAudioStream.BitDepth;
+ }
+
+ var targetAudioCodecs = TargetAudioCodec;
+ var audioCodec = targetAudioCodecs.Length == 0 ? null : targetAudioCodecs[0];
+ if (!string.IsNullOrEmpty(audioCodec))
+ {
+ return GetTargetAudioBitDepth(audioCodec);
+ }
+
+ return TargetAudioStream == null ? (int?)null : TargetAudioStream.BitDepth;
+ }
+ }
+
+ ///
+ /// Gets the audio sample rate that will be in the output stream.
+ ///
+ public int? TargetVideoBitDepth
+ {
+ get
+ {
+ if (IsDirectStream)
+ {
+ return TargetVideoStream == null ? (int?)null : TargetVideoStream.BitDepth;
+ }
+
+ var targetVideoCodecs = TargetVideoCodec;
+ var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
+ if (!string.IsNullOrEmpty(videoCodec))
+ {
+ return GetTargetVideoBitDepth(videoCodec);
+ }
+
+ return TargetVideoStream == null ? (int?)null : TargetVideoStream.BitDepth;
+ }
+ }
+
+ ///
+ /// Gets the target reference frames.
+ ///
+ /// The target reference frames.
+ public int? TargetRefFrames
+ {
+ get
+ {
+ if (IsDirectStream)
+ {
+ return TargetVideoStream == null ? (int?)null : TargetVideoStream.RefFrames;
+ }
+
+ var targetVideoCodecs = TargetVideoCodec;
+ var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
+ if (!string.IsNullOrEmpty(videoCodec))
+ {
+ return GetTargetRefFrames(videoCodec);
+ }
+
+ return TargetVideoStream == null ? (int?)null : TargetVideoStream.RefFrames;
+ }
+ }
+
+ ///
+ /// Gets the audio sample rate that will be in the output stream.
+ ///
+ public float? TargetFramerate
+ {
+ get
+ {
+ var stream = TargetVideoStream;
+ return MaxFramerate.HasValue && !IsDirectStream
+ ? MaxFramerate
+ : stream == null ? null : stream.AverageFrameRate ?? stream.RealFrameRate;
+ }
+ }
+
+ ///
+ /// Gets the audio sample rate that will be in the output stream.
+ ///
+ public double? TargetVideoLevel
+ {
+ get
+ {
+ if (IsDirectStream)
+ {
+ return TargetVideoStream == null ? (double?)null : TargetVideoStream.Level;
+ }
+
+ var targetVideoCodecs = TargetVideoCodec;
+ var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
+ if (!string.IsNullOrEmpty(videoCodec))
+ {
+ return GetTargetVideoLevel(videoCodec);
+ }
+
+ return TargetVideoStream == null ? (double?)null : TargetVideoStream.Level;
+ }
+ }
+
+ ///
+ /// Gets the audio sample rate that will be in the output stream.
+ ///
+ public int? TargetPacketLength
+ {
+ get
+ {
+ var stream = TargetVideoStream;
+ return !IsDirectStream
+ ? null
+ : stream == null ? null : stream.PacketLength;
+ }
+ }
+
+ ///
+ /// Gets the audio sample rate that will be in the output stream.
+ ///
+ public string TargetVideoProfile
+ {
+ get
+ {
+ if (IsDirectStream)
+ {
+ return TargetVideoStream == null ? null : TargetVideoStream.Profile;
+ }
+
+ var targetVideoCodecs = TargetVideoCodec;
+ var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
+ if (!string.IsNullOrEmpty(videoCodec))
+ {
+ return GetOption(videoCodec, "profile");
+ }
+
+ return TargetVideoStream == null ? null : TargetVideoStream.Profile;
+ }
+ }
+
+ ///
+ /// Gets the target video codec tag.
+ ///
+ /// The target video codec tag.
+ public string TargetVideoCodecTag
+ {
+ get
+ {
+ var stream = TargetVideoStream;
+ return !IsDirectStream
+ ? null
+ : stream == null ? null : stream.CodecTag;
+ }
+ }
+
+ ///
+ /// Gets the audio bitrate that will be in the output stream.
+ ///
+ public int? TargetAudioBitrate
+ {
+ get
+ {
+ var stream = TargetAudioStream;
+ return AudioBitrate.HasValue && !IsDirectStream
+ ? AudioBitrate
+ : stream == null ? null : stream.BitRate;
+ }
+ }
+
+ ///
+ /// Gets the audio channels that will be in the output stream.
+ ///
+ public int? TargetAudioChannels
+ {
+ get
+ {
+ if (IsDirectStream)
+ {
+ return TargetAudioStream == null ? (int?)null : TargetAudioStream.Channels;
+ }
+
+ var targetAudioCodecs = TargetAudioCodec;
+ var codec = targetAudioCodecs.Length == 0 ? null : targetAudioCodecs[0];
+ if (!string.IsNullOrEmpty(codec))
+ {
+ return GetTargetRefFrames(codec);
+ }
+
+ return TargetAudioStream == null ? (int?)null : TargetAudioStream.Channels;
+ }
+ }
+
+ ///
+ /// Gets the audio codec that will be in the output stream.
+ ///
+ public string[] TargetAudioCodec
+ {
+ get
+ {
+ var stream = TargetAudioStream;
+
+ string inputCodec = stream?.Codec;
+
+ if (IsDirectStream)
+ {
+ return string.IsNullOrEmpty(inputCodec) ? Array.Empty() : new[] { inputCodec };
+ }
+
+ foreach (string codec in AudioCodecs)
+ {
+ if (string.Equals(codec, inputCodec, StringComparison.OrdinalIgnoreCase))
+ {
+ return string.IsNullOrEmpty(codec) ? Array.Empty() : new[] { codec };
+ }
+ }
+
+ return AudioCodecs;
+ }
+ }
+
+ public string[] TargetVideoCodec
+ {
+ get
+ {
+ var stream = TargetVideoStream;
+
+ string inputCodec = stream?.Codec;
+
+ if (IsDirectStream)
+ {
+ return string.IsNullOrEmpty(inputCodec) ? Array.Empty() : new[] { inputCodec };
+ }
+
+ foreach (string codec in VideoCodecs)
+ {
+ if (string.Equals(codec, inputCodec, StringComparison.OrdinalIgnoreCase))
+ {
+ return string.IsNullOrEmpty(codec) ? Array.Empty() : new[] { codec };
+ }
+ }
+
+ return VideoCodecs;
+ }
+ }
+
+ ///
+ /// Gets the audio channels that will be in the output stream.
+ ///
+ public long? TargetSize
+ {
+ get
+ {
+ if (IsDirectStream)
+ {
+ return MediaSource.Size;
+ }
+
+ if (RunTimeTicks.HasValue)
+ {
+ int? totalBitrate = TargetTotalBitrate;
+
+ double totalSeconds = RunTimeTicks.Value;
+ // Convert to ms
+ totalSeconds /= 10000;
+ // Convert to seconds
+ totalSeconds /= 1000;
+
+ return totalBitrate.HasValue ?
+ Convert.ToInt64(totalBitrate.Value * totalSeconds) :
+ (long?)null;
+ }
+
+ return null;
+ }
+ }
+
+ public int? TargetVideoBitrate
+ {
+ get
+ {
+ var stream = TargetVideoStream;
+
+ return VideoBitrate.HasValue && !IsDirectStream
+ ? VideoBitrate
+ : stream == null ? null : stream.BitRate;
+ }
+ }
+
+ public TransportStreamTimestamp TargetTimestamp
+ {
+ get
+ {
+ var defaultValue = string.Equals(Container, "m2ts", StringComparison.OrdinalIgnoreCase)
+ ? TransportStreamTimestamp.Valid
+ : TransportStreamTimestamp.None;
+
+ return !IsDirectStream
+ ? defaultValue
+ : MediaSource == null ? defaultValue : MediaSource.Timestamp ?? TransportStreamTimestamp.None;
+ }
+ }
+
+ public int? TargetTotalBitrate => (TargetAudioBitrate ?? 0) + (TargetVideoBitrate ?? 0);
+
+ public bool? IsTargetAnamorphic
+ {
+ get
+ {
+ if (IsDirectStream)
+ {
+ return TargetVideoStream == null ? null : TargetVideoStream.IsAnamorphic;
+ }
+
+ return false;
+ }
+ }
+
+ public bool? IsTargetInterlaced
+ {
+ get
+ {
+ if (IsDirectStream)
+ {
+ return TargetVideoStream == null ? (bool?)null : TargetVideoStream.IsInterlaced;
+ }
+
+ var targetVideoCodecs = TargetVideoCodec;
+ var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
+ if (!string.IsNullOrEmpty(videoCodec))
+ {
+ if (string.Equals(GetOption(videoCodec, "deinterlace"), "true", StringComparison.OrdinalIgnoreCase))
+ {
+ return false;
+ }
+ }
+
+ return TargetVideoStream == null ? (bool?)null : TargetVideoStream.IsInterlaced;
+ }
+ }
+
+ public bool? IsTargetAVC
+ {
+ get
+ {
+ if (IsDirectStream)
+ {
+ return TargetVideoStream == null ? null : TargetVideoStream.IsAVC;
+ }
+
+ return true;
+ }
+ }
+
+ public int? TargetWidth
+ {
+ get
+ {
+ var videoStream = TargetVideoStream;
+
+ if (videoStream != null && videoStream.Width.HasValue && videoStream.Height.HasValue)
+ {
+ ImageDimensions size = new ImageDimensions(videoStream.Width.Value, videoStream.Height.Value);
+
+ size = DrawingUtils.Resize(size, 0, 0, MaxWidth ?? 0, MaxHeight ?? 0);
+
+ return size.Width;
+ }
+
+ return MaxWidth;
+ }
+ }
+
+ public int? TargetHeight
+ {
+ get
+ {
+ var videoStream = TargetVideoStream;
+
+ if (videoStream != null && videoStream.Width.HasValue && videoStream.Height.HasValue)
+ {
+ ImageDimensions size = new ImageDimensions(videoStream.Width.Value, videoStream.Height.Value);
+
+ size = DrawingUtils.Resize(size, 0, 0, MaxWidth ?? 0, MaxHeight ?? 0);
+
+ return size.Height;
+ }
+
+ return MaxHeight;
+ }
+ }
+
+ public int? TargetVideoStreamCount
+ {
+ get
+ {
+ if (IsDirectStream)
+ {
+ return GetMediaStreamCount(MediaStreamType.Video, int.MaxValue);
+ }
+
+ return GetMediaStreamCount(MediaStreamType.Video, 1);
+ }
+ }
+
+ public int? TargetAudioStreamCount
+ {
+ get
+ {
+ if (IsDirectStream)
+ {
+ return GetMediaStreamCount(MediaStreamType.Audio, int.MaxValue);
+ }
+
+ return GetMediaStreamCount(MediaStreamType.Audio, 1);
+ }
+ }
+
+ public void SetOption(string qualifier, string name, string value)
+ {
+ if (string.IsNullOrEmpty(qualifier))
+ {
+ SetOption(name, value);
+ }
+ else
+ {
+ SetOption(qualifier + "-" + name, value);
+ }
+ }
+
+ public void SetOption(string name, string value)
+ {
+ StreamOptions[name] = value;
+ }
+
+ public string GetOption(string qualifier, string name)
+ {
+ var value = GetOption(qualifier + "-" + name);
+
+ if (string.IsNullOrEmpty(value))
+ {
+ value = GetOption(name);
+ }
+
+ return value;
+ }
+
+ public string GetOption(string name)
+ {
+ if (StreamOptions.TryGetValue(name, out var value))
+ {
+ return value;
+ }
+
+ return null;
+ }
+
public string ToUrl(string baseUrl, string accessToken)
{
if (PlayMethod == PlayMethod.DirectPlay)
@@ -351,12 +796,12 @@ namespace MediaBrowser.Model.Dlna
}
// strip spaces to avoid having to encode h264 profile names
- list.Add(new NameValuePair(pair.Key, pair.Value.Replace(" ", "")));
+ list.Add(new NameValuePair(pair.Key, pair.Value.Replace(" ", string.Empty)));
}
if (!item.IsDirectStream)
{
- list.Add(new NameValuePair("TranscodeReasons", string.Join(",", item.TranscodeReasons.Distinct().Select(i => i.ToString()))));
+ list.Add(new NameValuePair("TranscodeReasons", string.Join(',', item.TranscodeReasons.Distinct())));
}
return list;
@@ -461,7 +906,9 @@ namespace MediaBrowser.Model.Dlna
{
if (MediaSource.Protocol == MediaProtocol.File || !string.Equals(stream.Codec, subtitleProfile.Format, StringComparison.OrdinalIgnoreCase) || !stream.IsExternal)
{
- info.Url = string.Format(CultureInfo.InvariantCulture, "{0}/Videos/{1}/{2}/Subtitles/{3}/{4}/Stream.{5}",
+ info.Url = string.Format(
+ CultureInfo.InvariantCulture,
+ "{0}/Videos/{1}/{2}/Subtitles/{3}/{4}/Stream.{5}",
baseUrl,
ItemId,
MediaSourceId,
@@ -486,159 +933,6 @@ namespace MediaBrowser.Model.Dlna
return info;
}
- ///
- /// Returns the audio stream that will be used.
- ///
- public MediaStream TargetAudioStream
- {
- get
- {
- if (MediaSource != null)
- {
- return MediaSource.GetDefaultAudioStream(AudioStreamIndex);
- }
-
- return null;
- }
- }
-
- ///
- /// Returns the video stream that will be used.
- ///
- public MediaStream TargetVideoStream
- {
- get
- {
- if (MediaSource != null)
- {
- return MediaSource.VideoStream;
- }
-
- return null;
- }
- }
-
- ///
- /// Predicts the audio sample rate that will be in the output stream.
- ///
- public int? TargetAudioSampleRate
- {
- get
- {
- var stream = TargetAudioStream;
- return AudioSampleRate.HasValue && !IsDirectStream
- ? AudioSampleRate
- : stream == null ? null : stream.SampleRate;
- }
- }
-
- ///
- /// Predicts the audio sample rate that will be in the output stream.
- ///
- public int? TargetAudioBitDepth
- {
- get
- {
- if (IsDirectStream)
- {
- return TargetAudioStream == null ? (int?)null : TargetAudioStream.BitDepth;
- }
-
- var targetAudioCodecs = TargetAudioCodec;
- var audioCodec = targetAudioCodecs.Length == 0 ? null : targetAudioCodecs[0];
- if (!string.IsNullOrEmpty(audioCodec))
- {
- return GetTargetAudioBitDepth(audioCodec);
- }
-
- return TargetAudioStream == null ? (int?)null : TargetAudioStream.BitDepth;
- }
- }
-
- ///
- /// Predicts the audio sample rate that will be in the output stream.
- ///
- public int? TargetVideoBitDepth
- {
- get
- {
- if (IsDirectStream)
- {
- return TargetVideoStream == null ? (int?)null : TargetVideoStream.BitDepth;
- }
-
- var targetVideoCodecs = TargetVideoCodec;
- var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
- if (!string.IsNullOrEmpty(videoCodec))
- {
- return GetTargetVideoBitDepth(videoCodec);
- }
-
- return TargetVideoStream == null ? (int?)null : TargetVideoStream.BitDepth;
- }
- }
-
- ///
- /// Gets the target reference frames.
- ///
- /// The target reference frames.
- public int? TargetRefFrames
- {
- get
- {
- if (IsDirectStream)
- {
- return TargetVideoStream == null ? (int?)null : TargetVideoStream.RefFrames;
- }
-
- var targetVideoCodecs = TargetVideoCodec;
- var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
- if (!string.IsNullOrEmpty(videoCodec))
- {
- return GetTargetRefFrames(videoCodec);
- }
-
- return TargetVideoStream == null ? (int?)null : TargetVideoStream.RefFrames;
- }
- }
-
- ///
- /// Predicts the audio sample rate that will be in the output stream.
- ///
- public float? TargetFramerate
- {
- get
- {
- var stream = TargetVideoStream;
- return MaxFramerate.HasValue && !IsDirectStream
- ? MaxFramerate
- : stream == null ? null : stream.AverageFrameRate ?? stream.RealFrameRate;
- }
- }
-
- ///
- /// Predicts the audio sample rate that will be in the output stream.
- ///
- public double? TargetVideoLevel
- {
- get
- {
- if (IsDirectStream)
- {
- return TargetVideoStream == null ? (double?)null : TargetVideoStream.Level;
- }
-
- var targetVideoCodecs = TargetVideoCodec;
- var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
- if (!string.IsNullOrEmpty(videoCodec))
- {
- return GetTargetVideoLevel(videoCodec);
- }
-
- return TargetVideoStream == null ? (double?)null : TargetVideoStream.Level;
- }
- }
-
public int? GetTargetVideoBitDepth(string codec)
{
var value = GetOption(codec, "videobitdepth");
@@ -703,95 +997,6 @@ namespace MediaBrowser.Model.Dlna
return null;
}
- ///
- /// Predicts the audio sample rate that will be in the output stream.
- ///
- public int? TargetPacketLength
- {
- get
- {
- var stream = TargetVideoStream;
- return !IsDirectStream
- ? null
- : stream == null ? null : stream.PacketLength;
- }
- }
-
- ///
- /// Predicts the audio sample rate that will be in the output stream.
- ///
- public string TargetVideoProfile
- {
- get
- {
- if (IsDirectStream)
- {
- return TargetVideoStream == null ? null : TargetVideoStream.Profile;
- }
-
- var targetVideoCodecs = TargetVideoCodec;
- var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
- if (!string.IsNullOrEmpty(videoCodec))
- {
- return GetOption(videoCodec, "profile");
- }
-
- return TargetVideoStream == null ? null : TargetVideoStream.Profile;
- }
- }
-
- ///
- /// Gets the target video codec tag.
- ///
- /// The target video codec tag.
- public string TargetVideoCodecTag
- {
- get
- {
- var stream = TargetVideoStream;
- return !IsDirectStream
- ? null
- : stream == null ? null : stream.CodecTag;
- }
- }
-
- ///
- /// Predicts the audio bitrate that will be in the output stream.
- ///
- public int? TargetAudioBitrate
- {
- get
- {
- var stream = TargetAudioStream;
- return AudioBitrate.HasValue && !IsDirectStream
- ? AudioBitrate
- : stream == null ? null : stream.BitRate;
- }
- }
-
- ///
- /// Predicts the audio channels that will be in the output stream.
- ///
- public int? TargetAudioChannels
- {
- get
- {
- if (IsDirectStream)
- {
- return TargetAudioStream == null ? (int?)null : TargetAudioStream.Channels;
- }
-
- var targetAudioCodecs = TargetAudioCodec;
- var codec = targetAudioCodecs.Length == 0 ? null : targetAudioCodecs[0];
- if (!string.IsNullOrEmpty(codec))
- {
- return GetTargetRefFrames(codec);
- }
-
- return TargetAudioStream == null ? (int?)null : TargetAudioStream.Channels;
- }
- }
-
public int? GetTargetAudioChannels(string codec)
{
var defaultValue = GlobalMaxAudioChannels ?? TranscodingMaxAudioChannels;
@@ -810,231 +1015,6 @@ namespace MediaBrowser.Model.Dlna
return defaultValue;
}
- ///
- /// Predicts the audio codec that will be in the output stream.
- ///
- public string[] TargetAudioCodec
- {
- get
- {
- var stream = TargetAudioStream;
-
- string inputCodec = stream?.Codec;
-
- if (IsDirectStream)
- {
- return string.IsNullOrEmpty(inputCodec) ? Array.Empty() : new[] { inputCodec };
- }
-
- foreach (string codec in AudioCodecs)
- {
- if (string.Equals(codec, inputCodec, StringComparison.OrdinalIgnoreCase))
- {
- return string.IsNullOrEmpty(codec) ? Array.Empty() : new[] { codec };
- }
- }
-
- return AudioCodecs;
- }
- }
-
- public string[] TargetVideoCodec
- {
- get
- {
- var stream = TargetVideoStream;
-
- string inputCodec = stream?.Codec;
-
- if (IsDirectStream)
- {
- return string.IsNullOrEmpty(inputCodec) ? Array.Empty() : new[] { inputCodec };
- }
-
- foreach (string codec in VideoCodecs)
- {
- if (string.Equals(codec, inputCodec, StringComparison.OrdinalIgnoreCase))
- {
- return string.IsNullOrEmpty(codec) ? Array.Empty() : new[] { codec };
- }
- }
-
- return VideoCodecs;
- }
- }
-
- ///
- /// Predicts the audio channels that will be in the output stream.
- ///
- public long? TargetSize
- {
- get
- {
- if (IsDirectStream)
- {
- return MediaSource.Size;
- }
-
- if (RunTimeTicks.HasValue)
- {
- int? totalBitrate = TargetTotalBitrate;
-
- double totalSeconds = RunTimeTicks.Value;
- // Convert to ms
- totalSeconds /= 10000;
- // Convert to seconds
- totalSeconds /= 1000;
-
- return totalBitrate.HasValue ?
- Convert.ToInt64(totalBitrate.Value * totalSeconds) :
- (long?)null;
- }
-
- return null;
- }
- }
-
- public int? TargetVideoBitrate
- {
- get
- {
- var stream = TargetVideoStream;
-
- return VideoBitrate.HasValue && !IsDirectStream
- ? VideoBitrate
- : stream == null ? null : stream.BitRate;
- }
- }
-
- public TransportStreamTimestamp TargetTimestamp
- {
- get
- {
- var defaultValue = string.Equals(Container, "m2ts", StringComparison.OrdinalIgnoreCase)
- ? TransportStreamTimestamp.Valid
- : TransportStreamTimestamp.None;
-
- return !IsDirectStream
- ? defaultValue
- : MediaSource == null ? defaultValue : MediaSource.Timestamp ?? TransportStreamTimestamp.None;
- }
- }
-
- public int? TargetTotalBitrate => (TargetAudioBitrate ?? 0) + (TargetVideoBitrate ?? 0);
-
- public bool? IsTargetAnamorphic
- {
- get
- {
- if (IsDirectStream)
- {
- return TargetVideoStream == null ? null : TargetVideoStream.IsAnamorphic;
- }
-
- return false;
- }
- }
-
- public bool? IsTargetInterlaced
- {
- get
- {
- if (IsDirectStream)
- {
- return TargetVideoStream == null ? (bool?)null : TargetVideoStream.IsInterlaced;
- }
-
- var targetVideoCodecs = TargetVideoCodec;
- var videoCodec = targetVideoCodecs.Length == 0 ? null : targetVideoCodecs[0];
- if (!string.IsNullOrEmpty(videoCodec))
- {
- if (string.Equals(GetOption(videoCodec, "deinterlace"), "true", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
- }
-
- return TargetVideoStream == null ? (bool?)null : TargetVideoStream.IsInterlaced;
- }
- }
-
- public bool? IsTargetAVC
- {
- get
- {
- if (IsDirectStream)
- {
- return TargetVideoStream == null ? null : TargetVideoStream.IsAVC;
- }
-
- return true;
- }
- }
-
- public int? TargetWidth
- {
- get
- {
- var videoStream = TargetVideoStream;
-
- if (videoStream != null && videoStream.Width.HasValue && videoStream.Height.HasValue)
- {
- ImageDimensions size = new ImageDimensions(videoStream.Width.Value, videoStream.Height.Value);
-
- size = DrawingUtils.Resize(size, 0, 0, MaxWidth ?? 0, MaxHeight ?? 0);
-
- return size.Width;
- }
-
- return MaxWidth;
- }
- }
-
- public int? TargetHeight
- {
- get
- {
- var videoStream = TargetVideoStream;
-
- if (videoStream != null && videoStream.Width.HasValue && videoStream.Height.HasValue)
- {
- ImageDimensions size = new ImageDimensions(videoStream.Width.Value, videoStream.Height.Value);
-
- size = DrawingUtils.Resize(size, 0, 0, MaxWidth ?? 0, MaxHeight ?? 0);
-
- return size.Height;
- }
-
- return MaxHeight;
- }
- }
-
- public int? TargetVideoStreamCount
- {
- get
- {
- if (IsDirectStream)
- {
- return GetMediaStreamCount(MediaStreamType.Video, int.MaxValue);
- }
-
- return GetMediaStreamCount(MediaStreamType.Video, 1);
- }
- }
-
- public int? TargetAudioStreamCount
- {
- get
- {
- if (IsDirectStream)
- {
- return GetMediaStreamCount(MediaStreamType.Audio, int.MaxValue);
- }
-
- return GetMediaStreamCount(MediaStreamType.Audio, 1);
- }
- }
-
private int? GetMediaStreamCount(MediaStreamType type, int limit)
{
var count = MediaSource.GetStreamCount(type);
diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs
index 2f9f9d3cd..a784025e3 100644
--- a/MediaBrowser.Model/Dto/BaseItemDto.cs
+++ b/MediaBrowser.Model/Dto/BaseItemDto.cs
@@ -294,13 +294,13 @@ namespace MediaBrowser.Model.Dto
public NameGuidPair[] GenreItems { get; set; }
///
- /// If the item does not have a logo, this will hold the Id of the Parent that has one.
+ /// Gets or sets wether the item has a logo, this will hold the Id of the Parent that has one.
///
/// The parent logo item id.
public string ParentLogoItemId { get; set; }
///
- /// If the item does not have any backdrops, this will hold the Id of the Parent that has one.
+ /// Gets or sets wether the item has any backdrops, this will hold the Id of the Parent that has one.
///
/// The parent backdrop item id.
public string ParentBackdropItemId { get; set; }
@@ -318,7 +318,7 @@ namespace MediaBrowser.Model.Dto
public int? LocalTrailerCount { get; set; }
///
- /// User data for this item based on the user it's being requested for.
+ /// Gets or sets the user data for this item based on the user it's being requested for.
///
/// The user data.
public UserItemDataDto UserData { get; set; }
@@ -506,7 +506,7 @@ namespace MediaBrowser.Model.Dto
public string ParentLogoImageTag { get; set; }
///
- /// If the item does not have a art, this will hold the Id of the Parent that has one.
+ /// Gets or sets wether the item has fan art, this will hold the Id of the Parent that has one.
///
/// The parent art item id.
public string ParentArtItemId { get; set; }
@@ -695,7 +695,7 @@ namespace MediaBrowser.Model.Dto
public string ChannelPrimaryImageTag { get; set; }
///
- /// The start date of the recording, in UTC.
+ /// Gets or sets the start date of the recording, in UTC.
///
public DateTime? StartDate { get; set; }
diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
index be682be23..ec3b37efa 100644
--- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs
+++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs
@@ -12,6 +12,18 @@ namespace MediaBrowser.Model.Dto
{
public class MediaSourceInfo
{
+ public MediaSourceInfo()
+ {
+ Formats = Array.Empty();
+ MediaStreams = new List();
+ MediaAttachments = Array.Empty();
+ RequiredHttpHeaders = new Dictionary();
+ SupportsTranscoding = true;
+ SupportsDirectStream = true;
+ SupportsDirectPlay = true;
+ SupportsProbing = true;
+ }
+
public MediaProtocol Protocol { get; set; }
public string Id { get; set; }
@@ -31,6 +43,7 @@ namespace MediaBrowser.Model.Dto
public string Name { get; set; }
///
+ /// Gets or sets a value indicating whether the media is remote.
/// Differentiate internet url vs local network.
///
public bool IsRemote { get; set; }
@@ -95,16 +108,28 @@ namespace MediaBrowser.Model.Dto
public int? AnalyzeDurationMs { get; set; }
- public MediaSourceInfo()
+ [JsonIgnore]
+ public TranscodeReason[] TranscodeReasons { get; set; }
+
+ public int? DefaultAudioStreamIndex { get; set; }
+
+ public int? DefaultSubtitleStreamIndex { get; set; }
+
+ [JsonIgnore]
+ public MediaStream VideoStream
{
- Formats = Array.Empty();
- MediaStreams = new List();
- MediaAttachments = Array.Empty();
- RequiredHttpHeaders = new Dictionary();
- SupportsTranscoding = true;
- SupportsDirectStream = true;
- SupportsDirectPlay = true;
- SupportsProbing = true;
+ get
+ {
+ foreach (var i in MediaStreams)
+ {
+ if (i.Type == MediaStreamType.Video)
+ {
+ return i;
+ }
+ }
+
+ return null;
+ }
}
public void InferTotalBitrate(bool force = false)
@@ -134,13 +159,6 @@ namespace MediaBrowser.Model.Dto
}
}
- [JsonIgnore]
- public TranscodeReason[] TranscodeReasons { get; set; }
-
- public int? DefaultAudioStreamIndex { get; set; }
-
- public int? DefaultSubtitleStreamIndex { get; set; }
-
public MediaStream GetDefaultAudioStream(int? defaultIndex)
{
if (defaultIndex.HasValue)
@@ -175,23 +193,6 @@ namespace MediaBrowser.Model.Dto
return null;
}
- [JsonIgnore]
- public MediaStream VideoStream
- {
- get
- {
- foreach (var i in MediaStreams)
- {
- if (i.Type == MediaStreamType.Video)
- {
- return i;
- }
- }
-
- return null;
- }
- }
-
public MediaStream GetMediaStream(MediaStreamType type, int index)
{
foreach (var i in MediaStreams)
diff --git a/MediaBrowser.Model/Dto/MetadataEditorInfo.cs b/MediaBrowser.Model/Dto/MetadataEditorInfo.cs
index e4f38d6af..e0e889f7d 100644
--- a/MediaBrowser.Model/Dto/MetadataEditorInfo.cs
+++ b/MediaBrowser.Model/Dto/MetadataEditorInfo.cs
@@ -10,6 +10,15 @@ namespace MediaBrowser.Model.Dto
{
public class MetadataEditorInfo
{
+ public MetadataEditorInfo()
+ {
+ ParentalRatingOptions = Array.Empty();
+ Countries = Array.Empty();
+ Cultures = Array.Empty();
+ ExternalIdInfos = Array.Empty();
+ ContentTypeOptions = Array.Empty();
+ }
+
public ParentalRating[] ParentalRatingOptions { get; set; }
public CountryInfo[] Countries { get; set; }
@@ -21,14 +30,5 @@ namespace MediaBrowser.Model.Dto
public string ContentType { get; set; }
public NameValuePair[] ContentTypeOptions { get; set; }
-
- public MetadataEditorInfo()
- {
- ParentalRatingOptions = Array.Empty();
- Countries = Array.Empty();
- Cultures = Array.Empty();
- ExternalIdInfos = Array.Empty();
- ContentTypeOptions = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/Dto/NameGuidPair.cs b/MediaBrowser.Model/Dto/NameGuidPair.cs
new file mode 100644
index 000000000..71166df97
--- /dev/null
+++ b/MediaBrowser.Model/Dto/NameGuidPair.cs
@@ -0,0 +1,14 @@
+#nullable disable
+#pragma warning disable CS1591
+
+using System;
+
+namespace MediaBrowser.Model.Dto
+{
+ public class NameGuidPair
+ {
+ public string Name { get; set; }
+
+ public Guid Id { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Dto/NameIdPair.cs b/MediaBrowser.Model/Dto/NameIdPair.cs
index 45c2fb35d..7f18b4502 100644
--- a/MediaBrowser.Model/Dto/NameIdPair.cs
+++ b/MediaBrowser.Model/Dto/NameIdPair.cs
@@ -19,11 +19,4 @@ namespace MediaBrowser.Model.Dto
/// The identifier.
public string Id { get; set; }
}
-
- public class NameGuidPair
- {
- public string Name { get; set; }
-
- public Guid Id { get; set; }
- }
}
diff --git a/MediaBrowser.Model/Dto/UserDto.cs b/MediaBrowser.Model/Dto/UserDto.cs
index 40222c9dc..256d7b10f 100644
--- a/MediaBrowser.Model/Dto/UserDto.cs
+++ b/MediaBrowser.Model/Dto/UserDto.cs
@@ -10,6 +10,15 @@ namespace MediaBrowser.Model.Dto
///
public class UserDto : IItemDto, IHasServerId
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public UserDto()
+ {
+ Configuration = new UserConfiguration();
+ Policy = new UserPolicy();
+ }
+
///
/// Gets or sets the name.
///
@@ -94,15 +103,6 @@ namespace MediaBrowser.Model.Dto
/// The primary image aspect ratio.
public double? PrimaryImageAspectRatio { get; set; }
- ///
- /// Initializes a new instance of the class.
- ///
- public UserDto()
- {
- Configuration = new UserConfiguration();
- Policy = new UserPolicy();
- }
-
///
public override string ToString()
{
diff --git a/MediaBrowser.Model/Entities/CollectionType.cs b/MediaBrowser.Model/Entities/CollectionType.cs
index 354038712..60b69d4b0 100644
--- a/MediaBrowser.Model/Entities/CollectionType.cs
+++ b/MediaBrowser.Model/Entities/CollectionType.cs
@@ -24,36 +24,4 @@ namespace MediaBrowser.Model.Entities
public const string Playlists = "playlists";
public const string Folders = "folders";
}
-
- public static class SpecialFolder
- {
- public const string TvShowSeries = "TvShowSeries";
- public const string TvGenres = "TvGenres";
- public const string TvGenre = "TvGenre";
- public const string TvLatest = "TvLatest";
- public const string TvNextUp = "TvNextUp";
- public const string TvResume = "TvResume";
- public const string TvFavoriteSeries = "TvFavoriteSeries";
- public const string TvFavoriteEpisodes = "TvFavoriteEpisodes";
-
- public const string MovieLatest = "MovieLatest";
- public const string MovieResume = "MovieResume";
- public const string MovieMovies = "MovieMovies";
- public const string MovieCollections = "MovieCollections";
- public const string MovieFavorites = "MovieFavorites";
- public const string MovieGenres = "MovieGenres";
- public const string MovieGenre = "MovieGenre";
-
- public const string MusicArtists = "MusicArtists";
- public const string MusicAlbumArtists = "MusicAlbumArtists";
- public const string MusicAlbums = "MusicAlbums";
- public const string MusicGenres = "MusicGenres";
- public const string MusicLatest = "MusicLatest";
- public const string MusicPlaylists = "MusicPlaylists";
- public const string MusicSongs = "MusicSongs";
- public const string MusicFavorites = "MusicFavorites";
- public const string MusicFavoriteArtists = "MusicFavoriteArtists";
- public const string MusicFavoriteAlbums = "MusicFavoriteAlbums";
- public const string MusicFavoriteSongs = "MusicFavoriteSongs";
- }
}
diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs
index ca0b93c30..ade9d7e8d 100644
--- a/MediaBrowser.Model/Entities/MediaStream.cs
+++ b/MediaBrowser.Model/Entities/MediaStream.cs
@@ -84,7 +84,7 @@ namespace MediaBrowser.Model.Entities
public string Title { get; set; }
///
- /// Gets or sets the video range.
+ /// Gets the video range.
///
/// The video range.
public string VideoRange
@@ -108,11 +108,11 @@ namespace MediaBrowser.Model.Entities
}
}
- public string localizedUndefined { get; set; }
+ public string LocalizedUndefined { get; set; }
- public string localizedDefault { get; set; }
+ public string LocalizedDefault { get; set; }
- public string localizedForced { get; set; }
+ public string LocalizedForced { get; set; }
public string DisplayTitle
{
@@ -154,7 +154,7 @@ namespace MediaBrowser.Model.Entities
if (IsDefault)
{
- attributes.Add(string.IsNullOrEmpty(localizedDefault) ? "Default" : localizedDefault);
+ attributes.Add(string.IsNullOrEmpty(LocalizedDefault) ? "Default" : LocalizedDefault);
}
if (!string.IsNullOrEmpty(Title))
@@ -211,7 +211,7 @@ namespace MediaBrowser.Model.Entities
return result.ToString();
}
- return string.Join(" ", attributes);
+ return string.Join(' ', attributes);
}
case MediaStreamType.Subtitle:
@@ -229,17 +229,17 @@ namespace MediaBrowser.Model.Entities
}
else
{
- attributes.Add(string.IsNullOrEmpty(localizedUndefined) ? "Und" : localizedUndefined);
+ attributes.Add(string.IsNullOrEmpty(LocalizedUndefined) ? "Und" : LocalizedUndefined);
}
if (IsDefault)
{
- attributes.Add(string.IsNullOrEmpty(localizedDefault) ? "Default" : localizedDefault);
+ attributes.Add(string.IsNullOrEmpty(LocalizedDefault) ? "Default" : LocalizedDefault);
}
if (IsForced)
{
- attributes.Add(string.IsNullOrEmpty(localizedForced) ? "Forced" : localizedForced);
+ attributes.Add(string.IsNullOrEmpty(LocalizedForced) ? "Forced" : LocalizedForced);
}
if (!string.IsNullOrEmpty(Title))
@@ -266,67 +266,6 @@ namespace MediaBrowser.Model.Entities
}
}
- private string GetResolutionText()
- {
- var i = this;
-
- if (i.Width.HasValue && i.Height.HasValue)
- {
- var width = i.Width.Value;
- var height = i.Height.Value;
-
- if (width >= 3800 || height >= 2000)
- {
- return "4K";
- }
-
- if (width >= 2500)
- {
- if (i.IsInterlaced)
- {
- return "1440i";
- }
-
- return "1440p";
- }
-
- if (width >= 1900 || height >= 1000)
- {
- if (i.IsInterlaced)
- {
- return "1080i";
- }
-
- return "1080p";
- }
-
- if (width >= 1260 || height >= 700)
- {
- if (i.IsInterlaced)
- {
- return "720i";
- }
-
- return "720p";
- }
-
- if (width >= 700 || height >= 440)
- {
-
- if (i.IsInterlaced)
- {
- return "480i";
- }
-
- return "480p";
- }
-
- return "SD";
- }
-
- return null;
- }
-
public string NalLengthSize { get; set; }
///
@@ -487,6 +426,96 @@ namespace MediaBrowser.Model.Entities
}
}
+ ///
+ /// Gets or sets a value indicating whether [supports external stream].
+ ///
+ /// true if [supports external stream]; otherwise, false.
+ public bool SupportsExternalStream { get; set; }
+
+ ///
+ /// Gets or sets the filename.
+ ///
+ /// The filename.
+ public string Path { get; set; }
+
+ ///
+ /// Gets or sets the pixel format.
+ ///
+ /// The pixel format.
+ public string PixelFormat { get; set; }
+
+ ///
+ /// Gets or sets the level.
+ ///
+ /// The level.
+ public double? Level { get; set; }
+
+ ///
+ /// Gets or sets whether this instance is anamorphic.
+ ///
+ /// true if this instance is anamorphic; otherwise, false.
+ public bool? IsAnamorphic { get; set; }
+
+ private string GetResolutionText()
+ {
+ var i = this;
+
+ if (i.Width.HasValue && i.Height.HasValue)
+ {
+ var width = i.Width.Value;
+ var height = i.Height.Value;
+
+ if (width >= 3800 || height >= 2000)
+ {
+ return "4K";
+ }
+
+ if (width >= 2500)
+ {
+ if (i.IsInterlaced)
+ {
+ return "1440i";
+ }
+
+ return "1440p";
+ }
+
+ if (width >= 1900 || height >= 1000)
+ {
+ if (i.IsInterlaced)
+ {
+ return "1080i";
+ }
+
+ return "1080p";
+ }
+
+ if (width >= 1260 || height >= 700)
+ {
+ if (i.IsInterlaced)
+ {
+ return "720i";
+ }
+
+ return "720p";
+ }
+
+ if (width >= 700 || height >= 440)
+ {
+ if (i.IsInterlaced)
+ {
+ return "480i";
+ }
+
+ return "480p";
+ }
+
+ return "SD";
+ }
+
+ return null;
+ }
+
public static bool IsTextFormat(string format)
{
string codec = format ?? string.Empty;
@@ -533,35 +562,5 @@ namespace MediaBrowser.Model.Entities
return true;
}
-
- ///
- /// Gets or sets a value indicating whether [supports external stream].
- ///
- /// true if [supports external stream]; otherwise, false.
- public bool SupportsExternalStream { get; set; }
-
- ///
- /// Gets or sets the filename.
- ///
- /// The filename.
- public string Path { get; set; }
-
- ///
- /// Gets or sets the pixel format.
- ///
- /// The pixel format.
- public string PixelFormat { get; set; }
-
- ///
- /// Gets or sets the level.
- ///
- /// The level.
- public double? Level { get; set; }
-
- ///
- /// Gets a value indicating whether this instance is anamorphic.
- ///
- /// true if this instance is anamorphic; otherwise, false.
- public bool? IsAnamorphic { get; set; }
}
}
diff --git a/MediaBrowser.Model/Entities/PackageReviewInfo.cs b/MediaBrowser.Model/Entities/PackageReviewInfo.cs
deleted file mode 100644
index 5b22b34ac..000000000
--- a/MediaBrowser.Model/Entities/PackageReviewInfo.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-#nullable disable
-#pragma warning disable CS1591
-
-using System;
-
-namespace MediaBrowser.Model.Entities
-{
- public class PackageReviewInfo
- {
- ///
- /// Gets or sets the package id (database key) for this review.
- ///
- public int id { get; set; }
-
- ///
- /// Gets or sets the rating value.
- ///
- public int rating { get; set; }
-
- ///
- /// Gets or sets whether or not this review recommends this item.
- ///
- public bool recommend { get; set; }
-
- ///
- /// Gets or sets a short description of the review.
- ///
- public string title { get; set; }
-
- ///
- /// Gets or sets the full review.
- ///
- public string review { get; set; }
-
- ///
- /// Gets or sets the time of review.
- ///
- public DateTime timestamp { get; set; }
- }
-}
diff --git a/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs b/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs
index 98097477c..4aff6e3a4 100644
--- a/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs
+++ b/MediaBrowser.Model/Entities/ProviderIdsExtensions.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
namespace MediaBrowser.Model.Entities
{
@@ -9,14 +10,50 @@ namespace MediaBrowser.Model.Entities
public static class ProviderIdsExtensions
{
///
- /// Determines whether [has provider identifier] [the specified instance].
+ /// Gets a provider id.
+ ///
+ /// The instance.
+ /// The name.
+ /// The provider id.
+ /// true if a provider id with the given name was found; otherwise false.
+ public static bool TryGetProviderId(this IHasProviderIds instance, string name, [MaybeNullWhen(false)] out string id)
+ {
+ if (instance == null)
+ {
+ throw new ArgumentNullException(nameof(instance));
+ }
+
+ if (instance.ProviderIds == null)
+ {
+ id = null;
+ return false;
+ }
+
+ return instance.ProviderIds.TryGetValue(name, out id);
+ }
+
+ ///
+ /// Gets a provider id.
///
/// The instance.
/// The provider.
- /// true if [has provider identifier] [the specified instance]; otherwise, false.
- public static bool HasProviderId(this IHasProviderIds instance, MetadataProvider provider)
+ /// The provider id.
+ /// true if a provider id with the given name was found; otherwise false.
+ public static bool TryGetProviderId(this IHasProviderIds instance, MetadataProvider provider, [MaybeNullWhen(false)] out string id)
{
- return !string.IsNullOrEmpty(instance.GetProviderId(provider.ToString()));
+ return instance.TryGetProviderId(provider.ToString(), out id);
+ }
+
+ ///
+ /// Gets a provider id.
+ ///
+ /// The instance.
+ /// The name.
+ /// System.String.
+ public static string? GetProviderId(this IHasProviderIds instance, string name)
+ {
+ instance.TryGetProviderId(name, out string? id);
+ return id;
}
///
@@ -30,28 +67,6 @@ namespace MediaBrowser.Model.Entities
return instance.GetProviderId(provider.ToString());
}
- ///
- /// Gets a provider id.
- ///
- /// The instance.
- /// The name.
- /// System.String.
- public static string? GetProviderId(this IHasProviderIds instance, string name)
- {
- if (instance == null)
- {
- throw new ArgumentNullException(nameof(instance));
- }
-
- if (instance.ProviderIds == null)
- {
- return null;
- }
-
- instance.ProviderIds.TryGetValue(name, out string? id);
- return string.IsNullOrEmpty(id) ? null : id;
- }
-
///
/// Sets a provider id.
///
@@ -68,13 +83,7 @@ namespace MediaBrowser.Model.Entities
// If it's null remove the key from the dictionary
if (string.IsNullOrEmpty(value))
{
- if (instance.ProviderIds != null)
- {
- if (instance.ProviderIds.ContainsKey(name))
- {
- instance.ProviderIds.Remove(name);
- }
- }
+ instance.ProviderIds?.Remove(name);
}
else
{
diff --git a/MediaBrowser.Model/Entities/SpecialFolder.cs b/MediaBrowser.Model/Entities/SpecialFolder.cs
new file mode 100644
index 000000000..2250c5dff
--- /dev/null
+++ b/MediaBrowser.Model/Entities/SpecialFolder.cs
@@ -0,0 +1,36 @@
+#pragma warning disable CS1591
+
+namespace MediaBrowser.Model.Entities
+{
+ public static class SpecialFolder
+ {
+ public const string TvShowSeries = "TvShowSeries";
+ public const string TvGenres = "TvGenres";
+ public const string TvGenre = "TvGenre";
+ public const string TvLatest = "TvLatest";
+ public const string TvNextUp = "TvNextUp";
+ public const string TvResume = "TvResume";
+ public const string TvFavoriteSeries = "TvFavoriteSeries";
+ public const string TvFavoriteEpisodes = "TvFavoriteEpisodes";
+
+ public const string MovieLatest = "MovieLatest";
+ public const string MovieResume = "MovieResume";
+ public const string MovieMovies = "MovieMovies";
+ public const string MovieCollections = "MovieCollections";
+ public const string MovieFavorites = "MovieFavorites";
+ public const string MovieGenres = "MovieGenres";
+ public const string MovieGenre = "MovieGenre";
+
+ public const string MusicArtists = "MusicArtists";
+ public const string MusicAlbumArtists = "MusicAlbumArtists";
+ public const string MusicAlbums = "MusicAlbums";
+ public const string MusicGenres = "MusicGenres";
+ public const string MusicLatest = "MusicLatest";
+ public const string MusicPlaylists = "MusicPlaylists";
+ public const string MusicSongs = "MusicSongs";
+ public const string MusicFavorites = "MusicFavorites";
+ public const string MusicFavoriteArtists = "MusicFavoriteArtists";
+ public const string MusicFavoriteAlbums = "MusicFavoriteAlbums";
+ public const string MusicFavoriteSongs = "MusicFavoriteSongs";
+ }
+}
diff --git a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs
index f2bc6f25e..1b0e59240 100644
--- a/MediaBrowser.Model/Entities/VirtualFolderInfo.cs
+++ b/MediaBrowser.Model/Entities/VirtualFolderInfo.cs
@@ -11,6 +11,14 @@ namespace MediaBrowser.Model.Entities
///
public class VirtualFolderInfo
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public VirtualFolderInfo()
+ {
+ Locations = Array.Empty();
+ }
+
///
/// Gets or sets the name.
///
@@ -31,14 +39,6 @@ namespace MediaBrowser.Model.Entities
public LibraryOptions LibraryOptions { get; set; }
- ///
- /// Initializes a new instance of the class.
- ///
- public VirtualFolderInfo()
- {
- Locations = Array.Empty();
- }
-
///
/// Gets or sets the item identifier.
///
diff --git a/MediaBrowser.Model/Globalization/CultureDto.cs b/MediaBrowser.Model/Globalization/CultureDto.cs
index 6af4a872c..5246f87d9 100644
--- a/MediaBrowser.Model/Globalization/CultureDto.cs
+++ b/MediaBrowser.Model/Globalization/CultureDto.cs
@@ -10,6 +10,11 @@ namespace MediaBrowser.Model.Globalization
///
public class CultureDto
{
+ public CultureDto()
+ {
+ ThreeLetterISOLanguageNames = Array.Empty();
+ }
+
///
/// Gets or sets the name.
///
@@ -29,7 +34,7 @@ namespace MediaBrowser.Model.Globalization
public string TwoLetterISOLanguageName { get; set; }
///
- /// Gets or sets the name of the three letter ISO language.
+ /// Gets the name of the three letter ISO language.
///
/// The name of the three letter ISO language.
public string ThreeLetterISOLanguageName
@@ -47,10 +52,5 @@ namespace MediaBrowser.Model.Globalization
}
public string[] ThreeLetterISOLanguageNames { get; set; }
-
- public CultureDto()
- {
- ThreeLetterISOLanguageNames = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/IO/IFileSystem.cs b/MediaBrowser.Model/IO/IFileSystem.cs
index dc6549787..ef08ecec6 100644
--- a/MediaBrowser.Model/IO/IFileSystem.cs
+++ b/MediaBrowser.Model/IO/IFileSystem.cs
@@ -155,13 +155,16 @@ namespace MediaBrowser.Model.IO
/// Gets the directories.
///
/// The path.
- /// if set to true [recursive].
- /// IEnumerable<DirectoryInfo>.
+ /// If set to true also searches in subdirectiories.
+ /// All found directories.
IEnumerable GetDirectories(string path, bool recursive = false);
///
/// Gets the files.
///
+ /// The path in which to search.
+ /// If set to true also searches in subdirectiories.
+ /// All found files.
IEnumerable GetFiles(string path, bool recursive = false);
IEnumerable GetFiles(string path, IReadOnlyList extensions, bool enableCaseSensitiveExtensions, bool recursive);
diff --git a/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs b/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs
index 07e76d960..c6de4c1ab 100644
--- a/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs
+++ b/MediaBrowser.Model/LiveTv/BaseTimerInfoDto.cs
@@ -9,7 +9,7 @@ namespace MediaBrowser.Model.LiveTv
public class BaseTimerInfoDto : IHasServerId
{
///
- /// Id of the recording.
+ /// Gets or sets the Id of the recording.
///
public string Id { get; set; }
@@ -28,7 +28,7 @@ namespace MediaBrowser.Model.LiveTv
public string ExternalId { get; set; }
///
- /// ChannelId of the recording.
+ /// Gets or sets the channel id of the recording.
///
public Guid ChannelId { get; set; }
@@ -39,7 +39,7 @@ namespace MediaBrowser.Model.LiveTv
public string ExternalChannelId { get; set; }
///
- /// ChannelName of the recording.
+ /// Gets or sets the channel name of the recording.
///
public string ChannelName { get; set; }
@@ -58,22 +58,22 @@ namespace MediaBrowser.Model.LiveTv
public string ExternalProgramId { get; set; }
///
- /// Name of the recording.
+ /// Gets or sets the name of the recording.
///
public string Name { get; set; }
///
- /// Description of the recording.
+ /// Gets or sets the description of the recording.
///
public string Overview { get; set; }
///
- /// The start date of the recording, in UTC.
+ /// Gets or sets the start date of the recording, in UTC.
///
public DateTime StartDate { get; set; }
///
- /// The end date of the recording, in UTC.
+ /// Gets or sets the end date of the recording, in UTC.
///
public DateTime EndDate { get; set; }
@@ -108,7 +108,7 @@ namespace MediaBrowser.Model.LiveTv
public bool IsPrePaddingRequired { get; set; }
///
- /// If the item does not have any backdrops, this will hold the Id of the Parent that has one.
+ /// Gets or sets the Id of the Parent that has a backdrop if the item does not have one.
///
/// The parent backdrop item id.
public string ParentBackdropItemId { get; set; }
diff --git a/MediaBrowser.Model/LiveTv/ListingsProviderInfo.cs b/MediaBrowser.Model/LiveTv/ListingsProviderInfo.cs
new file mode 100644
index 000000000..082daeb51
--- /dev/null
+++ b/MediaBrowser.Model/LiveTv/ListingsProviderInfo.cs
@@ -0,0 +1,58 @@
+#nullable disable
+#pragma warning disable CS1591
+
+using System;
+using MediaBrowser.Model.Dto;
+
+namespace MediaBrowser.Model.LiveTv
+{
+ public class ListingsProviderInfo
+ {
+ public ListingsProviderInfo()
+ {
+ NewsCategories = new[] { "news", "journalism", "documentary", "current affairs" };
+ SportsCategories = new[] { "sports", "basketball", "baseball", "football" };
+ KidsCategories = new[] { "kids", "family", "children", "childrens", "disney" };
+ MovieCategories = new[] { "movie" };
+ EnabledTuners = Array.Empty();
+ EnableAllTuners = true;
+ ChannelMappings = Array.Empty();
+ }
+
+ public string Id { get; set; }
+
+ public string Type { get; set; }
+
+ public string Username { get; set; }
+
+ public string Password { get; set; }
+
+ public string ListingsId { get; set; }
+
+ public string ZipCode { get; set; }
+
+ public string Country { get; set; }
+
+ public string Path { get; set; }
+
+ public string[] EnabledTuners { get; set; }
+
+ public bool EnableAllTuners { get; set; }
+
+ public string[] NewsCategories { get; set; }
+
+ public string[] SportsCategories { get; set; }
+
+ public string[] KidsCategories { get; set; }
+
+ public string[] MovieCategories { get; set; }
+
+ public NameValuePair[] ChannelMappings { get; set; }
+
+ public string MoviePrefix { get; set; }
+
+ public string PreferredLanguage { get; set; }
+
+ public string UserAgent { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs
index bcba344cc..673d97a9e 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvChannelQuery.cs
@@ -11,6 +11,12 @@ namespace MediaBrowser.Model.LiveTv
///
public class LiveTvChannelQuery
{
+ public LiveTvChannelQuery()
+ {
+ EnableUserData = true;
+ SortBy = Array.Empty();
+ }
+
///
/// Gets or sets the type of the channel.
///
@@ -48,13 +54,13 @@ namespace MediaBrowser.Model.LiveTv
public Guid UserId { get; set; }
///
- /// Skips over a given number of items within the results. Use for paging.
+ /// Gets or sets the start index. Used for paging.
///
/// The start index.
public int? StartIndex { get; set; }
///
- /// The maximum number of items to return.
+ /// Gets or sets the maximum number of items to return.
///
/// The limit.
public int? Limit { get; set; }
@@ -68,15 +74,15 @@ namespace MediaBrowser.Model.LiveTv
public bool EnableUserData { get; set; }
///
- /// Used to specific whether to return news or not.
+ /// Gets or sets a value whether to return news or not.
///
- /// If set to null, all programs will be returned
+ /// If set to null, all programs will be returned.
public bool? IsNews { get; set; }
///
- /// Used to specific whether to return movies or not.
+ /// Gets or sets a value whether to return movies or not.
///
- /// If set to null, all programs will be returned
+ /// If set to null, all programs will be returned.
public bool? IsMovie { get; set; }
///
@@ -96,15 +102,9 @@ namespace MediaBrowser.Model.LiveTv
public string[] SortBy { get; set; }
///
- /// The sort order to return results with.
+ /// Gets or sets the sort order to return results with.
///
/// The sort order.
public SortOrder? SortOrder { get; set; }
-
- public LiveTvChannelQuery()
- {
- EnableUserData = true;
- SortBy = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
index 789de3198..4cece941c 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs
@@ -2,12 +2,19 @@
#pragma warning disable CS1591
using System;
-using MediaBrowser.Model.Dto;
namespace MediaBrowser.Model.LiveTv
{
public class LiveTvOptions
{
+ public LiveTvOptions()
+ {
+ TunerHosts = Array.Empty();
+ ListingProviders = Array.Empty();
+ MediaLocationsCreated = Array.Empty();
+ RecordingPostProcessorArguments = "\"{path}\"";
+ }
+
public int? GuideDays { get; set; }
public string RecordingPath { get; set; }
@@ -33,93 +40,5 @@ namespace MediaBrowser.Model.LiveTv
public string RecordingPostProcessor { get; set; }
public string RecordingPostProcessorArguments { get; set; }
-
- public LiveTvOptions()
- {
- TunerHosts = Array.Empty();
- ListingProviders = Array.Empty();
- MediaLocationsCreated = Array.Empty();
- RecordingPostProcessorArguments = "\"{path}\"";
- }
- }
-
- public class TunerHostInfo
- {
- public string Id { get; set; }
-
- public string Url { get; set; }
-
- public string Type { get; set; }
-
- public string DeviceId { get; set; }
-
- public string FriendlyName { get; set; }
-
- public bool ImportFavoritesOnly { get; set; }
-
- public bool AllowHWTranscoding { get; set; }
-
- public bool EnableStreamLooping { get; set; }
-
- public string Source { get; set; }
-
- public int TunerCount { get; set; }
-
- public string UserAgent { get; set; }
-
- public TunerHostInfo()
- {
- AllowHWTranscoding = true;
- }
- }
-
- public class ListingsProviderInfo
- {
- public string Id { get; set; }
-
- public string Type { get; set; }
-
- public string Username { get; set; }
-
- public string Password { get; set; }
-
- public string ListingsId { get; set; }
-
- public string ZipCode { get; set; }
-
- public string Country { get; set; }
-
- public string Path { get; set; }
-
- public string[] EnabledTuners { get; set; }
-
- public bool EnableAllTuners { get; set; }
-
- public string[] NewsCategories { get; set; }
-
- public string[] SportsCategories { get; set; }
-
- public string[] KidsCategories { get; set; }
-
- public string[] MovieCategories { get; set; }
-
- public NameValuePair[] ChannelMappings { get; set; }
-
- public string MoviePrefix { get; set; }
-
- public string PreferredLanguage { get; set; }
-
- public string UserAgent { get; set; }
-
- public ListingsProviderInfo()
- {
- NewsCategories = new[] { "news", "journalism", "documentary", "current affairs" };
- SportsCategories = new[] { "sports", "basketball", "baseball", "football" };
- KidsCategories = new[] { "kids", "family", "children", "childrens", "disney" };
- MovieCategories = new[] { "movie" };
- EnabledTuners = Array.Empty();
- EnableAllTuners = true;
- ChannelMappings = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs b/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs
index 856f638c5..ef5c5d2f3 100644
--- a/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs
+++ b/MediaBrowser.Model/LiveTv/LiveTvServiceInfo.cs
@@ -10,6 +10,11 @@ namespace MediaBrowser.Model.LiveTv
///
public class LiveTvServiceInfo
{
+ public LiveTvServiceInfo()
+ {
+ Tuners = Array.Empty();
+ }
+
///
/// Gets or sets the name.
///
@@ -53,10 +58,5 @@ namespace MediaBrowser.Model.LiveTv
public bool IsVisible { get; set; }
public string[] Tuners { get; set; }
-
- public LiveTvServiceInfo()
- {
- Tuners = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/LiveTv/RecordingQuery.cs b/MediaBrowser.Model/LiveTv/RecordingQuery.cs
index 69e7db470..99bb1603c 100644
--- a/MediaBrowser.Model/LiveTv/RecordingQuery.cs
+++ b/MediaBrowser.Model/LiveTv/RecordingQuery.cs
@@ -12,6 +12,11 @@ namespace MediaBrowser.Model.LiveTv
///
public class RecordingQuery
{
+ public RecordingQuery()
+ {
+ EnableTotalRecordCount = true;
+ }
+
///
/// Gets or sets the channel identifier.
///
@@ -31,13 +36,13 @@ namespace MediaBrowser.Model.LiveTv
public string Id { get; set; }
///
- /// Skips over a given number of items within the results. Use for paging.
+ /// Gets or sets the start index. Use for paging.
///
/// The start index.
public int? StartIndex { get; set; }
///
- /// The maximum number of items to return.
+ /// Gets or sets the maximum number of items to return.
///
/// The limit.
public int? Limit { get; set; }
@@ -61,7 +66,7 @@ namespace MediaBrowser.Model.LiveTv
public string SeriesTimerId { get; set; }
///
- /// Fields to return within the items, in addition to basic information.
+ /// Gets or sets the fields to return within the items, in addition to basic information.
///
/// The fields.
public ItemFields[] Fields { get; set; }
@@ -85,10 +90,5 @@ namespace MediaBrowser.Model.LiveTv
public ImageType[] EnableImageTypes { get; set; }
public bool EnableTotalRecordCount { get; set; }
-
- public RecordingQuery()
- {
- EnableTotalRecordCount = true;
- }
}
}
diff --git a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs
index 90422d19c..b26f5f45f 100644
--- a/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs
+++ b/MediaBrowser.Model/LiveTv/SeriesTimerInfoDto.cs
@@ -7,6 +7,14 @@ using MediaBrowser.Model.Entities;
namespace MediaBrowser.Model.LiveTv
{
+ public enum KeepUntil
+ {
+ UntilDeleted,
+ UntilSpaceNeeded,
+ UntilWatched,
+ UntilDate
+ }
+
///
/// Class SeriesTimerInfoDto.
///
@@ -83,12 +91,4 @@ namespace MediaBrowser.Model.LiveTv
/// The parent primary image tag.
public string ParentPrimaryImageTag { get; set; }
}
-
- public enum KeepUntil
- {
- UntilDeleted,
- UntilSpaceNeeded,
- UntilWatched,
- UntilDate
- }
}
diff --git a/MediaBrowser.Model/LiveTv/TunerHostInfo.cs b/MediaBrowser.Model/LiveTv/TunerHostInfo.cs
new file mode 100644
index 000000000..7d4bbb2d0
--- /dev/null
+++ b/MediaBrowser.Model/LiveTv/TunerHostInfo.cs
@@ -0,0 +1,38 @@
+#nullable disable
+#pragma warning disable CS1591
+
+using System;
+using MediaBrowser.Model.Dto;
+
+namespace MediaBrowser.Model.LiveTv
+{
+ public class TunerHostInfo
+ {
+ public TunerHostInfo()
+ {
+ AllowHWTranscoding = true;
+ }
+
+ public string Id { get; set; }
+
+ public string Url { get; set; }
+
+ public string Type { get; set; }
+
+ public string DeviceId { get; set; }
+
+ public string FriendlyName { get; set; }
+
+ public bool ImportFavoritesOnly { get; set; }
+
+ public bool AllowHWTranscoding { get; set; }
+
+ public bool EnableStreamLooping { get; set; }
+
+ public string Source { get; set; }
+
+ public int TunerCount { get; set; }
+
+ public string UserAgent { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj
index c53428651..b6d916913 100644
--- a/MediaBrowser.Model/MediaBrowser.Model.csproj
+++ b/MediaBrowser.Model/MediaBrowser.Model.csproj
@@ -17,7 +17,7 @@
net5.0
false
true
- true
+ true
enable
latest
true
@@ -44,7 +44,7 @@
-
+
diff --git a/MediaBrowser.Model/MediaInfo/MediaInfo.cs b/MediaBrowser.Model/MediaInfo/MediaInfo.cs
index 472055c22..a268a4fa6 100644
--- a/MediaBrowser.Model/MediaInfo/MediaInfo.cs
+++ b/MediaBrowser.Model/MediaInfo/MediaInfo.cs
@@ -10,6 +10,17 @@ namespace MediaBrowser.Model.MediaInfo
{
public class MediaInfo : MediaSourceInfo, IHasProviderIds
{
+ public MediaInfo()
+ {
+ Chapters = Array.Empty();
+ Artists = Array.Empty();
+ AlbumArtists = Array.Empty();
+ Studios = Array.Empty();
+ Genres = Array.Empty();
+ People = Array.Empty();
+ ProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ }
+
public ChapterInfo[] Chapters { get; set; }
///
@@ -69,16 +80,5 @@ namespace MediaBrowser.Model.MediaInfo
///
/// The overview.
public string Overview { get; set; }
-
- public MediaInfo()
- {
- Chapters = Array.Empty();
- Artists = Array.Empty();
- AlbumArtists = Array.Empty();
- Studios = Array.Empty();
- Genres = Array.Empty();
- People = Array.Empty();
- ProviderIds = new Dictionary(StringComparer.OrdinalIgnoreCase);
- }
}
}
diff --git a/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs b/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs
index 321685677..ecd9b8834 100644
--- a/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs
+++ b/MediaBrowser.Model/MediaInfo/PlaybackInfoRequest.cs
@@ -8,6 +8,17 @@ namespace MediaBrowser.Model.MediaInfo
{
public class PlaybackInfoRequest
{
+ public PlaybackInfoRequest()
+ {
+ EnableDirectPlay = true;
+ EnableDirectStream = true;
+ EnableTranscoding = true;
+ AllowVideoStreamCopy = true;
+ AllowAudioStreamCopy = true;
+ IsPlayback = true;
+ DirectPlayProtocols = new MediaProtocol[] { MediaProtocol.Http };
+ }
+
public Guid Id { get; set; }
public Guid UserId { get; set; }
@@ -43,16 +54,5 @@ namespace MediaBrowser.Model.MediaInfo
public bool AutoOpenLiveStream { get; set; }
public MediaProtocol[] DirectPlayProtocols { get; set; }
-
- public PlaybackInfoRequest()
- {
- EnableDirectPlay = true;
- EnableDirectStream = true;
- EnableTranscoding = true;
- AllowVideoStreamCopy = true;
- AllowAudioStreamCopy = true;
- IsPlayback = true;
- DirectPlayProtocols = new MediaProtocol[] { MediaProtocol.Http };
- }
}
}
diff --git a/MediaBrowser.Model/MediaInfo/PlaybackInfoResponse.cs b/MediaBrowser.Model/MediaInfo/PlaybackInfoResponse.cs
index 273350182..32971b108 100644
--- a/MediaBrowser.Model/MediaInfo/PlaybackInfoResponse.cs
+++ b/MediaBrowser.Model/MediaInfo/PlaybackInfoResponse.cs
@@ -10,6 +10,14 @@ namespace MediaBrowser.Model.MediaInfo
///
public class PlaybackInfoResponse
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PlaybackInfoResponse()
+ {
+ MediaSources = Array.Empty();
+ }
+
///
/// Gets or sets the media sources.
///
@@ -27,13 +35,5 @@ namespace MediaBrowser.Model.MediaInfo
///
/// The error code.
public PlaybackErrorCode? ErrorCode { get; set; }
-
- ///
- /// Initializes a new instance of the class.
- ///
- public PlaybackInfoResponse()
- {
- MediaSources = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/MediaInfo/SubtitleTrackEvent.cs b/MediaBrowser.Model/MediaInfo/SubtitleTrackEvent.cs
index 72bb3d9c6..88b00c166 100644
--- a/MediaBrowser.Model/MediaInfo/SubtitleTrackEvent.cs
+++ b/MediaBrowser.Model/MediaInfo/SubtitleTrackEvent.cs
@@ -1,10 +1,15 @@
-#nullable disable
#pragma warning disable CS1591
namespace MediaBrowser.Model.MediaInfo
{
public class SubtitleTrackEvent
{
+ public SubtitleTrackEvent(string id, string text)
+ {
+ Id = id;
+ Text = text;
+ }
+
public string Id { get; set; }
public string Text { get; set; }
diff --git a/MediaBrowser.Model/MediaInfo/SubtitleTrackInfo.cs b/MediaBrowser.Model/MediaInfo/SubtitleTrackInfo.cs
index 37f5c55da..b3db57b6d 100644
--- a/MediaBrowser.Model/MediaInfo/SubtitleTrackInfo.cs
+++ b/MediaBrowser.Model/MediaInfo/SubtitleTrackInfo.cs
@@ -1,3 +1,4 @@
+#nullable enable
#pragma warning disable CS1591
using System;
@@ -7,11 +8,11 @@ namespace MediaBrowser.Model.MediaInfo
{
public class SubtitleTrackInfo
{
- public IReadOnlyList TrackEvents { get; set; }
-
public SubtitleTrackInfo()
{
TrackEvents = Array.Empty();
}
+
+ public IReadOnlyList TrackEvents { get; set; }
}
}
diff --git a/MediaBrowser.Model/Net/ISocket.cs b/MediaBrowser.Model/Net/ISocket.cs
index 5b6ed92df..3de41d565 100644
--- a/MediaBrowser.Model/Net/ISocket.cs
+++ b/MediaBrowser.Model/Net/ISocket.cs
@@ -23,6 +23,12 @@ namespace MediaBrowser.Model.Net
///
/// Sends a UDP message to a particular end point (uni or multicast).
///
+ /// An array of type that contains the data to send.
+ /// The zero-based position in buffer at which to begin sending data.
+ /// The number of bytes to send.
+ /// An that represents the remote device.
+ /// The cancellation token to cancel operation.
+ /// The task object representing the asynchronous operation.
Task SendToAsync(byte[] buffer, int offset, int bytes, IPEndPoint endPoint, CancellationToken cancellationToken);
}
}
diff --git a/MediaBrowser.Model/Net/ISocketFactory.cs b/MediaBrowser.Model/Net/ISocketFactory.cs
index 363abefc1..1527ef595 100644
--- a/MediaBrowser.Model/Net/ISocketFactory.cs
+++ b/MediaBrowser.Model/Net/ISocketFactory.cs
@@ -14,6 +14,9 @@ namespace MediaBrowser.Model.Net
///
/// Creates a new unicast socket using the specified local port number.
///
+ /// The local IP address to bind to.
+ /// The local port to bind to.
+ /// A new unicast socket using the specified local port number.
ISocket CreateSsdpUdpSocket(IPAddress localIp, int localPort);
///
diff --git a/MediaBrowser.Model/Net/MimeTypes.cs b/MediaBrowser.Model/Net/MimeTypes.cs
index 902db1e9e..96f5ab51a 100644
--- a/MediaBrowser.Model/Net/MimeTypes.cs
+++ b/MediaBrowser.Model/Net/MimeTypes.cs
@@ -91,9 +91,9 @@ namespace MediaBrowser.Model.Net
{ ".webp", "image/webp" },
// Type font
- { ".ttf" , "font/ttf" },
- { ".woff" , "font/woff" },
- { ".woff2" , "font/woff2" },
+ { ".ttf", "font/ttf" },
+ { ".woff", "font/woff" },
+ { ".woff2", "font/woff2" },
// Type text
{ ".ass", "text/x-ssa" },
@@ -168,14 +168,17 @@ namespace MediaBrowser.Model.Net
///
/// Gets the type of the MIME.
///
- public static string? GetMimeType(string path, bool enableStreamDefault)
+ /// The filename to find the MIME type of.
+ /// Whether of not to return a default value if no fitting MIME type is found.
+ /// The worrect MIME type for the given filename, or `null` if it wasn't found and is false.
+ public static string? GetMimeType(string filename, bool enableStreamDefault)
{
- if (path.Length == 0)
+ if (filename.Length == 0)
{
- throw new ArgumentException("String can't be empty.", nameof(path));
+ throw new ArgumentException("String can't be empty.", nameof(filename));
}
- var ext = Path.GetExtension(path);
+ var ext = Path.GetExtension(filename);
if (_mimeTypeLookup.TryGetValue(ext, out string? result))
{
@@ -210,9 +213,9 @@ namespace MediaBrowser.Model.Net
return enableStreamDefault ? "application/octet-stream" : null;
}
- public static string? ToExtension(string? mimeType)
+ public static string? ToExtension(string mimeType)
{
- if (string.IsNullOrEmpty(mimeType))
+ if (mimeType.Length == 0)
{
throw new ArgumentException("String can't be empty.", nameof(mimeType));
}
diff --git a/MediaBrowser.Model/Net/NetworkShare.cs b/MediaBrowser.Model/Net/NetworkShare.cs
deleted file mode 100644
index 6344cbe21..000000000
--- a/MediaBrowser.Model/Net/NetworkShare.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-#nullable disable
-#pragma warning disable CS1591
-
-namespace MediaBrowser.Model.Net
-{
- public class NetworkShare
- {
- ///
- /// The name of the computer that this share belongs to.
- ///
- public string Server { get; set; }
-
- ///
- /// Share name.
- ///
- public string Name { get; set; }
-
- ///
- /// Local path.
- ///
- public string Path { get; set; }
-
- ///
- /// Share type.
- ///
- public NetworkShareType ShareType { get; set; }
-
- ///
- /// Comment.
- ///
- public string Remark { get; set; }
- }
-}
diff --git a/MediaBrowser.Model/Net/SocketReceiveResult.cs b/MediaBrowser.Model/Net/SocketReceiveResult.cs
index 54139fe9c..1524786ea 100644
--- a/MediaBrowser.Model/Net/SocketReceiveResult.cs
+++ b/MediaBrowser.Model/Net/SocketReceiveResult.cs
@@ -20,12 +20,12 @@ namespace MediaBrowser.Model.Net
public int ReceivedBytes { get; set; }
///
- /// The the data was received from.
+ /// Gets or sets the the data was received from.
///
public IPEndPoint RemoteEndPoint { get; set; }
///
- /// The local .
+ /// Gets or sets the local .
///
public IPAddress LocalIPAddress { get; set; }
}
diff --git a/MediaBrowser.Model/Net/WebSocketMessage.cs b/MediaBrowser.Model/Net/WebSocketMessage.cs
index bffbbe612..b00158cb3 100644
--- a/MediaBrowser.Model/Net/WebSocketMessage.cs
+++ b/MediaBrowser.Model/Net/WebSocketMessage.cs
@@ -9,7 +9,7 @@ namespace MediaBrowser.Model.Net
///
/// Class WebSocketMessage.
///
- ///
+ /// The type of the data.
public class WebSocketMessage
{
///
diff --git a/MediaBrowser.Model/Notifications/NotificationOptions.cs b/MediaBrowser.Model/Notifications/NotificationOptions.cs
index 239a3777e..94bb5d6e3 100644
--- a/MediaBrowser.Model/Notifications/NotificationOptions.cs
+++ b/MediaBrowser.Model/Notifications/NotificationOptions.cs
@@ -2,18 +2,16 @@
#pragma warning disable CS1591
using System;
-using Jellyfin.Data.Enums;
-using MediaBrowser.Model.Extensions;
using System.Linq;
using Jellyfin.Data.Entities;
+using Jellyfin.Data.Enums;
+using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.Users;
namespace MediaBrowser.Model.Notifications
{
public class NotificationOptions
{
- public NotificationOption[] Options { get; set; }
-
public NotificationOptions()
{
Options = new[]
@@ -71,6 +69,8 @@ namespace MediaBrowser.Model.Notifications
};
}
+ public NotificationOption[] Options { get; set; }
+
public NotificationOption GetOptions(string type)
{
foreach (NotificationOption i in Options)
@@ -104,7 +104,7 @@ namespace MediaBrowser.Model.Notifications
NotificationOption opt = GetOptions(type);
return opt != null && opt.Enabled &&
- !opt.DisabledMonitorUsers.Contains(userId.ToString(""), StringComparer.OrdinalIgnoreCase);
+ !opt.DisabledMonitorUsers.Contains(userId.ToString(string.Empty), StringComparer.OrdinalIgnoreCase);
}
public bool IsEnabledToSendToUser(string type, string userId, User user)
diff --git a/MediaBrowser.Model/Notifications/NotificationRequest.cs b/MediaBrowser.Model/Notifications/NotificationRequest.cs
index febc2bc09..622c50cd8 100644
--- a/MediaBrowser.Model/Notifications/NotificationRequest.cs
+++ b/MediaBrowser.Model/Notifications/NotificationRequest.cs
@@ -7,6 +7,12 @@ namespace MediaBrowser.Model.Notifications
{
public class NotificationRequest
{
+ public NotificationRequest()
+ {
+ UserIds = Array.Empty();
+ Date = DateTime.UtcNow;
+ }
+
public string Name { get; set; }
public string Description { get; set; }
@@ -20,16 +26,10 @@ namespace MediaBrowser.Model.Notifications
public DateTime Date { get; set; }
///
- /// The corresponding type name used in configuration. Not for display.
+ /// Gets or sets the corresponding type name used in configuration. Not for display.
///
public string NotificationType { get; set; }
public SendToUserType? SendToUserMode { get; set; }
-
- public NotificationRequest()
- {
- UserIds = Array.Empty();
- Date = DateTime.UtcNow;
- }
}
}
diff --git a/MediaBrowser.Model/Providers/ExternalIdInfo.cs b/MediaBrowser.Model/Providers/ExternalIdInfo.cs
index afe95e6ee..0ea3e96ca 100644
--- a/MediaBrowser.Model/Providers/ExternalIdInfo.cs
+++ b/MediaBrowser.Model/Providers/ExternalIdInfo.cs
@@ -6,11 +6,11 @@ namespace MediaBrowser.Model.Providers
public class ExternalIdInfo
{
///
- /// Represents the external id information for serialization to the client.
+ /// Initializes a new instance of the class.
///
/// Name of the external id provider (IE: IMDB, MusicBrainz, etc).
/// Key for this id. This key should be unique across all providers.
- /// Specific media type for this id
+ /// Specific media type for this id.
/// URL format string.
public ExternalIdInfo(string name, string key, ExternalIdMediaType? type, string urlFormatString)
{
diff --git a/MediaBrowser.Model/Providers/RemoteImageInfo.cs b/MediaBrowser.Model/Providers/RemoteImageInfo.cs
index fb25999e0..48207d2d4 100644
--- a/MediaBrowser.Model/Providers/RemoteImageInfo.cs
+++ b/MediaBrowser.Model/Providers/RemoteImageInfo.cs
@@ -22,7 +22,7 @@ namespace MediaBrowser.Model.Providers
public string Url { get; set; }
///
- /// Gets a url used for previewing a smaller version.
+ /// Gets or sets a url used for previewing a smaller version.
///
public string ThumbnailUrl { get; set; }
diff --git a/MediaBrowser.Model/Providers/SubtitleOptions.cs b/MediaBrowser.Model/Providers/SubtitleOptions.cs
index 5702c460b..6ea1e1486 100644
--- a/MediaBrowser.Model/Providers/SubtitleOptions.cs
+++ b/MediaBrowser.Model/Providers/SubtitleOptions.cs
@@ -7,6 +7,14 @@ namespace MediaBrowser.Model.Providers
{
public class SubtitleOptions
{
+ public SubtitleOptions()
+ {
+ DownloadLanguages = Array.Empty();
+
+ SkipIfAudioTrackMatches = true;
+ RequirePerfectMatch = true;
+ }
+
public bool SkipIfEmbeddedSubtitlesPresent { get; set; }
public bool SkipIfAudioTrackMatches { get; set; }
@@ -24,13 +32,5 @@ namespace MediaBrowser.Model.Providers
public bool IsOpenSubtitleVipAccount { get; set; }
public bool RequirePerfectMatch { get; set; }
-
- public SubtitleOptions()
- {
- DownloadLanguages = Array.Empty();
-
- SkipIfAudioTrackMatches = true;
- RequirePerfectMatch = true;
- }
}
}
diff --git a/MediaBrowser.Model/Querying/EpisodeQuery.cs b/MediaBrowser.Model/Querying/EpisodeQuery.cs
index 13b1a0dcb..56a7f3320 100644
--- a/MediaBrowser.Model/Querying/EpisodeQuery.cs
+++ b/MediaBrowser.Model/Querying/EpisodeQuery.cs
@@ -7,6 +7,11 @@ namespace MediaBrowser.Model.Querying
{
public class EpisodeQuery
{
+ public EpisodeQuery()
+ {
+ Fields = Array.Empty();
+ }
+
///
/// Gets or sets the user identifier.
///
@@ -66,10 +71,5 @@ namespace MediaBrowser.Model.Querying
///
/// The start item identifier.
public string StartItemId { get; set; }
-
- public EpisodeQuery()
- {
- Fields = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/Querying/LatestItemsQuery.cs b/MediaBrowser.Model/Querying/LatestItemsQuery.cs
index 7954ef4b4..f555ffb36 100644
--- a/MediaBrowser.Model/Querying/LatestItemsQuery.cs
+++ b/MediaBrowser.Model/Querying/LatestItemsQuery.cs
@@ -14,31 +14,32 @@ namespace MediaBrowser.Model.Querying
}
///
- /// The user to localize search results for.
+ /// Gets or sets the user to localize search results for.
///
/// The user id.
public Guid UserId { get; set; }
///
+ /// Gets or sets the parent id.
/// Specify this to localize the search to a specific item or folder. Omit to use the root.
///
/// The parent id.
public Guid ParentId { get; set; }
///
- /// Skips over a given number of items within the results. Use for paging.
+ /// Gets or sets the start index. Used for paging.
///
/// The start index.
public int? StartIndex { get; set; }
///
- /// The maximum number of items to return.
+ /// Gets or sets the maximum number of items to return.
///
/// The limit.
public int? Limit { get; set; }
///
- /// Fields to return within the items, in addition to basic information.
+ /// Gets or sets the fields to return within the items, in addition to basic information.
///
/// The fields.
public ItemFields[] Fields { get; set; }
diff --git a/MediaBrowser.Model/Querying/MovieRecommendationQuery.cs b/MediaBrowser.Model/Querying/MovieRecommendationQuery.cs
index 1c8875890..b800f5de5 100644
--- a/MediaBrowser.Model/Querying/MovieRecommendationQuery.cs
+++ b/MediaBrowser.Model/Querying/MovieRecommendationQuery.cs
@@ -7,6 +7,13 @@ namespace MediaBrowser.Model.Querying
{
public class MovieRecommendationQuery
{
+ public MovieRecommendationQuery()
+ {
+ ItemLimit = 10;
+ CategoryLimit = 6;
+ Fields = Array.Empty();
+ }
+
///
/// Gets or sets the user identifier.
///
@@ -36,12 +43,5 @@ namespace MediaBrowser.Model.Querying
///
/// The fields.
public ItemFields[] Fields { get; set; }
-
- public MovieRecommendationQuery()
- {
- ItemLimit = 10;
- CategoryLimit = 6;
- Fields = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/Querying/NextUpQuery.cs b/MediaBrowser.Model/Querying/NextUpQuery.cs
index 001d0623c..0555afc00 100644
--- a/MediaBrowser.Model/Querying/NextUpQuery.cs
+++ b/MediaBrowser.Model/Querying/NextUpQuery.cs
@@ -8,6 +8,13 @@ namespace MediaBrowser.Model.Querying
{
public class NextUpQuery
{
+ public NextUpQuery()
+ {
+ EnableImageTypes = Array.Empty();
+ EnableTotalRecordCount = true;
+ DisableFirstEpisode = false;
+ }
+
///
/// Gets or sets the user id.
///
@@ -27,19 +34,19 @@ namespace MediaBrowser.Model.Querying
public string SeriesId { get; set; }
///
- /// Skips over a given number of items within the results. Use for paging.
+ /// Gets or sets the start index. Use for paging.
///
/// The start index.
public int? StartIndex { get; set; }
///
- /// The maximum number of items to return.
+ /// Gets or sets the maximum number of items to return.
///
/// The limit.
public int? Limit { get; set; }
///
- /// Fields to return within the items, in addition to basic information.
+ /// gets or sets the fields to return within the items, in addition to basic information.
///
/// The fields.
public ItemFields[] Fields { get; set; }
@@ -68,12 +75,5 @@ namespace MediaBrowser.Model.Querying
/// Gets or sets a value indicating whether do disable sending first episode as next up.
///
public bool DisableFirstEpisode { get; set; }
-
- public NextUpQuery()
- {
- EnableImageTypes = Array.Empty();
- EnableTotalRecordCount = true;
- DisableFirstEpisode = false;
- }
}
}
diff --git a/MediaBrowser.Model/Querying/QueryFilters.cs b/MediaBrowser.Model/Querying/QueryFilters.cs
index 6e4d25181..73b27a7b0 100644
--- a/MediaBrowser.Model/Querying/QueryFilters.cs
+++ b/MediaBrowser.Model/Querying/QueryFilters.cs
@@ -6,35 +6,16 @@ using MediaBrowser.Model.Dto;
namespace MediaBrowser.Model.Querying
{
- public class QueryFiltersLegacy
- {
- public string[] Genres { get; set; }
-
- public string[] Tags { get; set; }
-
- public string[] OfficialRatings { get; set; }
-
- public int[] Years { get; set; }
-
- public QueryFiltersLegacy()
- {
- Genres = Array.Empty();
- Tags = Array.Empty();
- OfficialRatings = Array.Empty();
- Years = Array.Empty();
- }
- }
-
public class QueryFilters
{
- public NameGuidPair[] Genres { get; set; }
-
- public string[] Tags { get; set; }
-
public QueryFilters()
{
Tags = Array.Empty();
Genres = Array.Empty();
}
+
+ public NameGuidPair[] Genres { get; set; }
+
+ public string[] Tags { get; set; }
}
}
diff --git a/MediaBrowser.Model/Querying/QueryFiltersLegacy.cs b/MediaBrowser.Model/Querying/QueryFiltersLegacy.cs
new file mode 100644
index 000000000..fcb450ed3
--- /dev/null
+++ b/MediaBrowser.Model/Querying/QueryFiltersLegacy.cs
@@ -0,0 +1,26 @@
+#nullable disable
+#pragma warning disable CS1591
+
+using System;
+
+namespace MediaBrowser.Model.Querying
+{
+ public class QueryFiltersLegacy
+ {
+ public QueryFiltersLegacy()
+ {
+ Genres = Array.Empty();
+ Tags = Array.Empty();
+ OfficialRatings = Array.Empty();
+ Years = Array.Empty();
+ }
+
+ public string[] Genres { get; set; }
+
+ public string[] Tags { get; set; }
+
+ public string[] OfficialRatings { get; set; }
+
+ public int[] Years { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Querying/QueryResult.cs b/MediaBrowser.Model/Querying/QueryResult.cs
index 490f48b84..8ce794800 100644
--- a/MediaBrowser.Model/Querying/QueryResult.cs
+++ b/MediaBrowser.Model/Querying/QueryResult.cs
@@ -8,24 +8,6 @@ namespace MediaBrowser.Model.Querying
{
public class QueryResult
{
- ///
- /// Gets or sets the items.
- ///
- /// The items.
- public IReadOnlyList Items { get; set; }
-
- ///
- /// The total number of records available.
- ///
- /// The total record count.
- public int TotalRecordCount { get; set; }
-
- ///
- /// The index of the first record in Items.
- ///
- /// First record index.
- public int StartIndex { get; set; }
-
public QueryResult()
{
Items = Array.Empty();
@@ -36,5 +18,23 @@ namespace MediaBrowser.Model.Querying
Items = items;
TotalRecordCount = items.Count;
}
+
+ ///
+ /// Gets or sets the items.
+ ///
+ /// The items.
+ public IReadOnlyList Items { get; set; }
+
+ ///
+ /// Gets or sets the total number of records available.
+ ///
+ /// The total record count.
+ public int TotalRecordCount { get; set; }
+
+ ///
+ /// Gets or sets the index of the first record in Items.
+ ///
+ /// First record index.
+ public int StartIndex { get; set; }
}
}
diff --git a/MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs b/MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs
index eb6239460..2cf0f0d5f 100644
--- a/MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs
+++ b/MediaBrowser.Model/Querying/UpcomingEpisodesQuery.cs
@@ -8,6 +8,11 @@ namespace MediaBrowser.Model.Querying
{
public class UpcomingEpisodesQuery
{
+ public UpcomingEpisodesQuery()
+ {
+ EnableImageTypes = Array.Empty();
+ }
+
///
/// Gets or sets the user id.
///
@@ -21,19 +26,19 @@ namespace MediaBrowser.Model.Querying
public string ParentId { get; set; }
///
- /// Skips over a given number of items within the results. Use for paging.
+ /// Gets or sets the start index. Use for paging.
///
/// The start index.
public int? StartIndex { get; set; }
///
- /// The maximum number of items to return.
+ /// Gets or sets the maximum number of items to return.
///
/// The limit.
public int? Limit { get; set; }
///
- /// Fields to return within the items, in addition to basic information.
+ /// Gets or sets the fields to return within the items, in addition to basic information.
///
/// The fields.
public ItemFields[] Fields { get; set; }
@@ -55,10 +60,5 @@ namespace MediaBrowser.Model.Querying
///
/// The enable image types.
public ImageType[] EnableImageTypes { get; set; }
-
- public UpcomingEpisodesQuery()
- {
- EnableImageTypes = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/Search/SearchQuery.cs b/MediaBrowser.Model/Search/SearchQuery.cs
index ce60062cd..aedfa4d36 100644
--- a/MediaBrowser.Model/Search/SearchQuery.cs
+++ b/MediaBrowser.Model/Search/SearchQuery.cs
@@ -7,8 +7,21 @@ namespace MediaBrowser.Model.Search
{
public class SearchQuery
{
+ public SearchQuery()
+ {
+ IncludeArtists = true;
+ IncludeGenres = true;
+ IncludeMedia = true;
+ IncludePeople = true;
+ IncludeStudios = true;
+
+ MediaTypes = Array.Empty();
+ IncludeItemTypes = Array.Empty();
+ ExcludeItemTypes = Array.Empty();
+ }
+
///
- /// The user to localize search results for.
+ /// Gets or sets the user to localize search results for.
///
/// The user id.
public Guid UserId { get; set; }
@@ -20,13 +33,13 @@ namespace MediaBrowser.Model.Search
public string SearchTerm { get; set; }
///
- /// Skips over a given number of items within the results. Use for paging.
+ /// Gets or sets the start index. Used for paging.
///
/// The start index.
public int? StartIndex { get; set; }
///
- /// The maximum number of items to return.
+ /// Gets or sets the maximum number of items to return.
///
/// The limit.
public int? Limit { get; set; }
@@ -58,18 +71,5 @@ namespace MediaBrowser.Model.Search
public bool? IsKids { get; set; }
public bool? IsSports { get; set; }
-
- public SearchQuery()
- {
- IncludeArtists = true;
- IncludeGenres = true;
- IncludeMedia = true;
- IncludePeople = true;
- IncludeStudios = true;
-
- MediaTypes = Array.Empty();
- IncludeItemTypes = Array.Empty();
- ExcludeItemTypes = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/Session/BrowseRequest.cs b/MediaBrowser.Model/Session/BrowseRequest.cs
index 1c997d584..65afe5cf3 100644
--- a/MediaBrowser.Model/Session/BrowseRequest.cs
+++ b/MediaBrowser.Model/Session/BrowseRequest.cs
@@ -7,6 +7,7 @@ namespace MediaBrowser.Model.Session
public class BrowseRequest
{
///
+ /// Gets or sets the item type.
/// Artist, Genre, Studio, Person, or any kind of BaseItem.
///
/// The type of the item.
diff --git a/MediaBrowser.Model/Session/ClientCapabilities.cs b/MediaBrowser.Model/Session/ClientCapabilities.cs
index 5852f4e37..d692906c6 100644
--- a/MediaBrowser.Model/Session/ClientCapabilities.cs
+++ b/MediaBrowser.Model/Session/ClientCapabilities.cs
@@ -9,6 +9,13 @@ namespace MediaBrowser.Model.Session
{
public class ClientCapabilities
{
+ public ClientCapabilities()
+ {
+ PlayableMediaTypes = Array.Empty();
+ SupportedCommands = Array.Empty();
+ SupportsPersistentIdentifier = true;
+ }
+
public IReadOnlyList PlayableMediaTypes { get; set; }
public IReadOnlyList SupportedCommands { get; set; }
@@ -28,12 +35,5 @@ namespace MediaBrowser.Model.Session
public string AppStoreUrl { get; set; }
public string IconUrl { get; set; }
-
- public ClientCapabilities()
- {
- PlayableMediaTypes = Array.Empty();
- SupportedCommands = Array.Empty();
- SupportsPersistentIdentifier = true;
- }
}
}
diff --git a/MediaBrowser.Model/Session/GeneralCommand.cs b/MediaBrowser.Model/Session/GeneralCommand.cs
index 77bb6bcf7..29528c110 100644
--- a/MediaBrowser.Model/Session/GeneralCommand.cs
+++ b/MediaBrowser.Model/Session/GeneralCommand.cs
@@ -1,4 +1,3 @@
-#nullable disable
#pragma warning disable CS1591
using System;
@@ -8,15 +7,15 @@ namespace MediaBrowser.Model.Session
{
public class GeneralCommand
{
- public GeneralCommandType Name { get; set; }
-
- public Guid ControllingUserId { get; set; }
-
- public Dictionary Arguments { get; set; }
-
public GeneralCommand()
{
Arguments = new Dictionary();
}
+
+ public GeneralCommandType Name { get; set; }
+
+ public Guid ControllingUserId { get; set; }
+
+ public Dictionary Arguments { get; }
}
}
diff --git a/MediaBrowser.Model/Session/PlaybackProgressInfo.cs b/MediaBrowser.Model/Session/PlaybackProgressInfo.cs
index 73dbe6a2d..a6e7efcb0 100644
--- a/MediaBrowser.Model/Session/PlaybackProgressInfo.cs
+++ b/MediaBrowser.Model/Session/PlaybackProgressInfo.cs
@@ -111,18 +111,4 @@ namespace MediaBrowser.Model.Session
public string PlaylistItemId { get; set; }
}
-
- public enum RepeatMode
- {
- RepeatNone = 0,
- RepeatAll = 1,
- RepeatOne = 2
- }
-
- public class QueueItem
- {
- public Guid Id { get; set; }
-
- public string PlaylistItemId { get; set; }
- }
}
diff --git a/MediaBrowser.Model/Session/PlaystateCommand.cs b/MediaBrowser.Model/Session/PlaystateCommand.cs
index 3aa091f79..df47f3b73 100644
--- a/MediaBrowser.Model/Session/PlaystateCommand.cs
+++ b/MediaBrowser.Model/Session/PlaystateCommand.cs
@@ -1,5 +1,3 @@
-#pragma warning disable CS1591
-
namespace MediaBrowser.Model.Session
{
///
@@ -46,6 +44,10 @@ namespace MediaBrowser.Model.Session
/// The fast forward.
///
FastForward,
+
+ ///
+ /// The play pause.
+ ///
PlayPause
}
}
diff --git a/MediaBrowser.Model/Session/QueueItem.cs b/MediaBrowser.Model/Session/QueueItem.cs
new file mode 100644
index 000000000..32b19101b
--- /dev/null
+++ b/MediaBrowser.Model/Session/QueueItem.cs
@@ -0,0 +1,14 @@
+#nullable disable
+#pragma warning disable CS1591
+
+using System;
+
+namespace MediaBrowser.Model.Session
+{
+ public class QueueItem
+ {
+ public Guid Id { get; set; }
+
+ public string PlaylistItemId { get; set; }
+ }
+}
diff --git a/MediaBrowser.Model/Session/RepeatMode.cs b/MediaBrowser.Model/Session/RepeatMode.cs
new file mode 100644
index 000000000..c6e173d6b
--- /dev/null
+++ b/MediaBrowser.Model/Session/RepeatMode.cs
@@ -0,0 +1,11 @@
+#pragma warning disable CS1591
+
+namespace MediaBrowser.Model.Session
+{
+ public enum RepeatMode
+ {
+ RepeatNone = 0,
+ RepeatAll = 1,
+ RepeatOne = 2
+ }
+}
diff --git a/MediaBrowser.Model/Session/TranscodeReason.cs b/MediaBrowser.Model/Session/TranscodeReason.cs
new file mode 100644
index 000000000..e93b5d288
--- /dev/null
+++ b/MediaBrowser.Model/Session/TranscodeReason.cs
@@ -0,0 +1,31 @@
+#pragma warning disable CS1591
+
+namespace MediaBrowser.Model.Session
+{
+ public enum TranscodeReason
+ {
+ ContainerNotSupported = 0,
+ VideoCodecNotSupported = 1,
+ AudioCodecNotSupported = 2,
+ ContainerBitrateExceedsLimit = 3,
+ AudioBitrateNotSupported = 4,
+ AudioChannelsNotSupported = 5,
+ VideoResolutionNotSupported = 6,
+ UnknownVideoStreamInfo = 7,
+ UnknownAudioStreamInfo = 8,
+ AudioProfileNotSupported = 9,
+ AudioSampleRateNotSupported = 10,
+ AnamorphicVideoNotSupported = 11,
+ InterlacedVideoNotSupported = 12,
+ SecondaryAudioNotSupported = 13,
+ RefFramesNotSupported = 14,
+ VideoBitDepthNotSupported = 15,
+ VideoBitrateNotSupported = 16,
+ VideoFramerateNotSupported = 17,
+ VideoLevelNotSupported = 18,
+ VideoProfileNotSupported = 19,
+ AudioBitDepthNotSupported = 20,
+ SubtitleCodecNotSupported = 21,
+ DirectPlayError = 22
+ }
+}
diff --git a/MediaBrowser.Model/Session/TranscodingInfo.cs b/MediaBrowser.Model/Session/TranscodingInfo.cs
index e832c2f6f..064a087d5 100644
--- a/MediaBrowser.Model/Session/TranscodingInfo.cs
+++ b/MediaBrowser.Model/Session/TranscodingInfo.cs
@@ -7,6 +7,11 @@ namespace MediaBrowser.Model.Session
{
public class TranscodingInfo
{
+ public TranscodingInfo()
+ {
+ TranscodeReasons = Array.Empty();
+ }
+
public string AudioCodec { get; set; }
public string VideoCodec { get; set; }
@@ -30,37 +35,5 @@ namespace MediaBrowser.Model.Session
public int? AudioChannels { get; set; }
public TranscodeReason[] TranscodeReasons { get; set; }
-
- public TranscodingInfo()
- {
- TranscodeReasons = Array.Empty();
- }
- }
-
- public enum TranscodeReason
- {
- ContainerNotSupported = 0,
- VideoCodecNotSupported = 1,
- AudioCodecNotSupported = 2,
- ContainerBitrateExceedsLimit = 3,
- AudioBitrateNotSupported = 4,
- AudioChannelsNotSupported = 5,
- VideoResolutionNotSupported = 6,
- UnknownVideoStreamInfo = 7,
- UnknownAudioStreamInfo = 8,
- AudioProfileNotSupported = 9,
- AudioSampleRateNotSupported = 10,
- AnamorphicVideoNotSupported = 11,
- InterlacedVideoNotSupported = 12,
- SecondaryAudioNotSupported = 13,
- RefFramesNotSupported = 14,
- VideoBitDepthNotSupported = 15,
- VideoBitrateNotSupported = 16,
- VideoFramerateNotSupported = 17,
- VideoLevelNotSupported = 18,
- VideoProfileNotSupported = 19,
- AudioBitDepthNotSupported = 20,
- SubtitleCodecNotSupported = 21,
- DirectPlayError = 22
}
}
diff --git a/MediaBrowser.Model/Sync/SyncJob.cs b/MediaBrowser.Model/Sync/SyncJob.cs
index b9290b6e8..3e396e5d1 100644
--- a/MediaBrowser.Model/Sync/SyncJob.cs
+++ b/MediaBrowser.Model/Sync/SyncJob.cs
@@ -7,6 +7,11 @@ namespace MediaBrowser.Model.Sync
{
public class SyncJob
{
+ public SyncJob()
+ {
+ RequestedItemIds = Array.Empty();
+ }
+
///
/// Gets or sets the identifier.
///
@@ -126,10 +131,5 @@ namespace MediaBrowser.Model.Sync
public string PrimaryImageItemId { get; set; }
public string PrimaryImageTag { get; set; }
-
- public SyncJob()
- {
- RequestedItemIds = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/System/SystemInfo.cs b/MediaBrowser.Model/System/SystemInfo.cs
index 4b83fb7e6..d75ae91c0 100644
--- a/MediaBrowser.Model/System/SystemInfo.cs
+++ b/MediaBrowser.Model/System/SystemInfo.cs
@@ -30,6 +30,14 @@ namespace MediaBrowser.Model.System
///
public class SystemInfo : PublicSystemInfo
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SystemInfo()
+ {
+ CompletedInstallations = Array.Empty();
+ }
+
///
/// Gets or sets the display name of the operating system.
///
@@ -37,7 +45,7 @@ namespace MediaBrowser.Model.System
public string OperatingSystemDisplayName { get; set; }
///
- /// Get or sets the package name.
+ /// Gets or sets the package name.
///
/// The value of the '-package' command line argument.
public string PackageName { get; set; }
@@ -127,13 +135,5 @@ namespace MediaBrowser.Model.System
public FFmpegLocation EncoderLocation { get; set; }
public Architecture SystemArchitecture { get; set; }
-
- ///
- /// Initializes a new instance of the class.
- ///
- public SystemInfo()
- {
- CompletedInstallations = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/System/WakeOnLanInfo.cs b/MediaBrowser.Model/System/WakeOnLanInfo.cs
index b2cbe737d..aba19a6ba 100644
--- a/MediaBrowser.Model/System/WakeOnLanInfo.cs
+++ b/MediaBrowser.Model/System/WakeOnLanInfo.cs
@@ -36,7 +36,7 @@ namespace MediaBrowser.Model.System
/// Gets the MAC address of the device.
///
/// The MAC address.
- public string? MacAddress { get; set; }
+ public string? MacAddress { get; }
///
/// Gets or sets the wake-on-LAN port.
diff --git a/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs b/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs
index 2f05e08c5..ca769e26b 100644
--- a/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs
+++ b/MediaBrowser.Model/Tasks/IScheduledTaskWorker.cs
@@ -15,7 +15,7 @@ namespace MediaBrowser.Model.Tasks
event EventHandler> TaskProgress;
///
- /// Gets or sets the scheduled task.
+ /// Gets the scheduled task.
///
/// The scheduled task.
IScheduledTask ScheduledTask { get; }
@@ -57,10 +57,9 @@ namespace MediaBrowser.Model.Tasks
double? CurrentProgress { get; }
///
- /// Gets the triggers that define when the task will run.
+ /// Gets or sets the triggers that define when the task will run.
///
/// The triggers.
- /// value
TaskTriggerInfo[] Triggers { get; set; }
///
diff --git a/MediaBrowser.Model/Tasks/ITaskManager.cs b/MediaBrowser.Model/Tasks/ITaskManager.cs
index 02b29074e..a86bf2a1c 100644
--- a/MediaBrowser.Model/Tasks/ITaskManager.cs
+++ b/MediaBrowser.Model/Tasks/ITaskManager.cs
@@ -9,6 +9,10 @@ namespace MediaBrowser.Model.Tasks
{
public interface ITaskManager : IDisposable
{
+ event EventHandler> TaskExecuting;
+
+ event EventHandler TaskCompleted;
+
///
/// Gets the list of Scheduled Tasks.
///
@@ -18,7 +22,7 @@ namespace MediaBrowser.Model.Tasks
///
/// Cancels if running and queue.
///
- ///
+ /// An implementatin of .
/// Task options.
void CancelIfRunningAndQueue(TaskOptions options)
where T : IScheduledTask;
@@ -26,21 +30,21 @@ namespace MediaBrowser.Model.Tasks
///
/// Cancels if running and queue.
///
- ///
+ /// An implementatin of .
void CancelIfRunningAndQueue()
where T : IScheduledTask;
///
/// Cancels if running.
///
- ///
+ /// An implementatin of .
void CancelIfRunning()
where T : IScheduledTask;
///
/// Queues the scheduled task.
///
- ///
+ /// An implementatin of .
/// Task options.
void QueueScheduledTask(TaskOptions options)
where T : IScheduledTask;
@@ -48,7 +52,7 @@ namespace MediaBrowser.Model.Tasks
///
/// Queues the scheduled task.
///
- ///
+ /// An implementatin of .
void QueueScheduledTask()
where T : IScheduledTask;
@@ -58,6 +62,8 @@ namespace MediaBrowser.Model.Tasks
///
/// Queues the scheduled task.
///
+ /// The to queue.
+ /// The to use.
void QueueScheduledTask(IScheduledTask task, TaskOptions options);
///
@@ -67,12 +73,10 @@ namespace MediaBrowser.Model.Tasks
void AddTasks(IEnumerable tasks);
void Cancel(IScheduledTaskWorker task);
+
Task Execute(IScheduledTaskWorker task, TaskOptions options);
void Execute()
where T : IScheduledTask;
-
- event EventHandler> TaskExecuting;
- event EventHandler TaskCompleted;
}
}
diff --git a/MediaBrowser.Model/Tasks/ITaskTrigger.cs b/MediaBrowser.Model/Tasks/ITaskTrigger.cs
index 5c30d6c22..cbd60cca1 100644
--- a/MediaBrowser.Model/Tasks/ITaskTrigger.cs
+++ b/MediaBrowser.Model/Tasks/ITaskTrigger.cs
@@ -21,6 +21,10 @@ namespace MediaBrowser.Model.Tasks
///
/// Stars waiting for the trigger action.
///
+ /// Result of the last run triggerd task.
+ /// The .
+ /// The name of the task.
+ /// Wheter or not this is is fired during startup.
void Start(TaskResult lastResult, ILogger logger, string taskName, bool isApplicationStartup);
///
diff --git a/MediaBrowser.Model/Tasks/TaskInfo.cs b/MediaBrowser.Model/Tasks/TaskInfo.cs
index 77100dfe7..16de0b121 100644
--- a/MediaBrowser.Model/Tasks/TaskInfo.cs
+++ b/MediaBrowser.Model/Tasks/TaskInfo.cs
@@ -8,6 +8,14 @@ namespace MediaBrowser.Model.Tasks
///
public class TaskInfo
{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public TaskInfo()
+ {
+ Triggers = Array.Empty();
+ }
+
///
/// Gets or sets the name.
///
@@ -67,13 +75,5 @@ namespace MediaBrowser.Model.Tasks
///
/// The key.
public string Key { get; set; }
-
- ///
- /// Initializes a new instance of the class.
- ///
- public TaskInfo()
- {
- Triggers = Array.Empty();
- }
}
}
diff --git a/MediaBrowser.Model/Tasks/TaskTriggerInfo.cs b/MediaBrowser.Model/Tasks/TaskTriggerInfo.cs
index 5aeaffc2b..f8a8c727e 100644
--- a/MediaBrowser.Model/Tasks/TaskTriggerInfo.cs
+++ b/MediaBrowser.Model/Tasks/TaskTriggerInfo.cs
@@ -10,6 +10,12 @@ namespace MediaBrowser.Model.Tasks
///
public class TaskTriggerInfo
{
+ public const string TriggerDaily = "DailyTrigger";
+ public const string TriggerWeekly = "WeeklyTrigger";
+ public const string TriggerInterval = "IntervalTrigger";
+ public const string TriggerSystemEvent = "SystemEventTrigger";
+ public const string TriggerStartup = "StartupTrigger";
+
///
/// Gets or sets the type.
///
@@ -39,11 +45,5 @@ namespace MediaBrowser.Model.Tasks
///
/// The maximum runtime ticks.
public long? MaxRuntimeTicks { get; set; }
-
- public const string TriggerDaily = "DailyTrigger";
- public const string TriggerWeekly = "WeeklyTrigger";
- public const string TriggerInterval = "IntervalTrigger";
- public const string TriggerSystemEvent = "SystemEventTrigger";
- public const string TriggerStartup = "StartupTrigger";
}
}
diff --git a/MediaBrowser.Model/Users/UserPolicy.cs b/MediaBrowser.Model/Users/UserPolicy.cs
index 37da04adf..111070d81 100644
--- a/MediaBrowser.Model/Users/UserPolicy.cs
+++ b/MediaBrowser.Model/Users/UserPolicy.cs
@@ -10,6 +10,56 @@ namespace MediaBrowser.Model.Users
{
public class UserPolicy
{
+ public UserPolicy()
+ {
+ IsHidden = true;
+
+ EnableContentDeletion = false;
+ EnableContentDeletionFromFolders = Array.Empty();
+
+ EnableSyncTranscoding = true;
+ EnableMediaConversion = true;
+
+ EnableMediaPlayback = true;
+ EnableAudioPlaybackTranscoding = true;
+ EnableVideoPlaybackTranscoding = true;
+ EnablePlaybackRemuxing = true;
+ ForceRemoteSourceTranscoding = false;
+ EnableLiveTvManagement = true;
+ EnableLiveTvAccess = true;
+
+ // Without this on by default, admins won't be able to do this
+ // Improve in the future
+ EnableLiveTvManagement = true;
+
+ EnableSharedDeviceControl = true;
+
+ BlockedTags = Array.Empty();
+ BlockUnratedItems = Array.Empty();
+
+ EnableUserPreferenceAccess = true;
+
+ AccessSchedules = Array.Empty();
+
+ LoginAttemptsBeforeLockout = -1;
+
+ MaxActiveSessions = 0;
+
+ EnableAllChannels = true;
+ EnabledChannels = Array.Empty();
+
+ EnableAllFolders = true;
+ EnabledFolders = Array.Empty();
+
+ EnabledDevices = Array.Empty();
+ EnableAllDevices = true;
+
+ EnableContentDownloading = true;
+ EnablePublicSharing = true;
+ EnableRemoteAccess = true;
+ SyncPlayAccess = SyncPlayUserAccessType.CreateAndJoinGroups;
+ }
+
///
/// Gets or sets a value indicating whether this instance is administrator.
///
@@ -112,55 +162,5 @@ namespace MediaBrowser.Model.Users
///
/// Access level to SyncPlay features.
public SyncPlayUserAccessType SyncPlayAccess { get; set; }
-
- public UserPolicy()
- {
- IsHidden = true;
-
- EnableContentDeletion = false;
- EnableContentDeletionFromFolders = Array.Empty();
-
- EnableSyncTranscoding = true;
- EnableMediaConversion = true;
-
- EnableMediaPlayback = true;
- EnableAudioPlaybackTranscoding = true;
- EnableVideoPlaybackTranscoding = true;
- EnablePlaybackRemuxing = true;
- ForceRemoteSourceTranscoding = false;
- EnableLiveTvManagement = true;
- EnableLiveTvAccess = true;
-
- // Without this on by default, admins won't be able to do this
- // Improve in the future
- EnableLiveTvManagement = true;
-
- EnableSharedDeviceControl = true;
-
- BlockedTags = Array.Empty();
- BlockUnratedItems = Array.Empty();
-
- EnableUserPreferenceAccess = true;
-
- AccessSchedules = Array.Empty();
-
- LoginAttemptsBeforeLockout = -1;
-
- MaxActiveSessions = 0;
-
- EnableAllChannels = true;
- EnabledChannels = Array.Empty();
-
- EnableAllFolders = true;
- EnabledFolders = Array.Empty();
-
- EnabledDevices = Array.Empty();
- EnableAllDevices = true;
-
- EnableContentDownloading = true;
- EnablePublicSharing = true;
- EnableRemoteAccess = true;
- SyncPlayAccess = SyncPlayUserAccessType.CreateAndJoinGroups;
- }
}
}
diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs
index 19a42d506..9dd87aef5 100644
--- a/MediaBrowser.Providers/Manager/ImageSaver.cs
+++ b/MediaBrowser.Providers/Manager/ImageSaver.cs
@@ -102,10 +102,8 @@ namespace MediaBrowser.Providers.Manager
{
saveLocally = false;
- var season = item as Season;
-
// If season is virtual under a physical series, save locally if using compatible convention
- if (season != null && _config.Configuration.ImageSavingConvention == ImageSavingConvention.Compatible)
+ if (item is Season season && _config.Configuration.ImageSavingConvention == ImageSavingConvention.Compatible)
{
var series = season.Series;
@@ -138,7 +136,7 @@ namespace MediaBrowser.Providers.Manager
var memoryStream = new MemoryStream();
await using (source.ConfigureAwait(false))
{
- await source.CopyToAsync(memoryStream).ConfigureAwait(false);
+ await source.CopyToAsync(memoryStream, cancellationToken).ConfigureAwait(false);
}
source = memoryStream;
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs
index ef7933b1a..e5ad0f3e0 100644
--- a/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/MusicBrainzAlbumProvider.cs
@@ -756,7 +756,10 @@ namespace MediaBrowser.Providers.Music
_stopWatchMusicBrainz.Restart();
using var request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
- response = await _httpClientFactory.CreateClient(NamedClient.MusicBrainz).SendAsync(request).ConfigureAwait(false);
+ response = await _httpClientFactory
+ .CreateClient(NamedClient.MusicBrainz)
+ .SendAsync(request, cancellationToken)
+ .ConfigureAwait(false);
// We retry a finite number of times, and only whilst MB is indicating 503 (throttling).
}
diff --git a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
index bcf9459ef..9a3e3d5fa 100644
--- a/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
+++ b/MediaBrowser.Providers/Plugins/Tmdb/Movies/TmdbMovieProvider.cs
@@ -7,6 +7,8 @@ using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
+using TMDbLib.Objects.Find;
+using TMDbLib.Objects.Search;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
@@ -43,63 +45,89 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
public async Task> GetSearchResults(MovieInfo searchInfo, CancellationToken cancellationToken)
{
- var tmdbId = Convert.ToInt32(searchInfo.GetProviderId(MetadataProvider.Tmdb), CultureInfo.InvariantCulture);
-
- if (tmdbId == 0)
+ if (searchInfo.TryGetProviderId(MetadataProvider.Tmdb, out var id))
{
- var movieResults = await _tmdbClientManager
- .SearchMovieAsync(searchInfo.Name, searchInfo.MetadataLanguage, cancellationToken)
+ var movie = await _tmdbClientManager
+ .GetMovieAsync(
+ int.Parse(id, CultureInfo.InvariantCulture),
+ searchInfo.MetadataLanguage,
+ TmdbUtils.GetImageLanguagesParam(searchInfo.MetadataLanguage),
+ cancellationToken)
.ConfigureAwait(false);
- var remoteSearchResults = new List();
- for (var i = 0; i < movieResults.Count; i++)
+
+ var remoteResult = new RemoteSearchResult
{
- var movieResult = movieResults[i];
- var remoteSearchResult = new RemoteSearchResult
- {
- Name = movieResult.Title ?? movieResult.OriginalTitle,
- ImageUrl = _tmdbClientManager.GetPosterUrl(movieResult.PosterPath),
- Overview = movieResult.Overview,
- SearchProviderName = Name
- };
+ Name = movie.Title ?? movie.OriginalTitle,
+ SearchProviderName = Name,
+ ImageUrl = _tmdbClientManager.GetPosterUrl(movie.PosterPath),
+ Overview = movie.Overview
+ };
- var releaseDate = movieResult.ReleaseDate?.ToUniversalTime();
- remoteSearchResult.PremiereDate = releaseDate;
- remoteSearchResult.ProductionYear = releaseDate?.Year;
-
- remoteSearchResult.SetProviderId(MetadataProvider.Tmdb, movieResult.Id.ToString(CultureInfo.InvariantCulture));
- remoteSearchResults.Add(remoteSearchResult);
+ if (movie.ReleaseDate != null)
+ {
+ var releaseDate = movie.ReleaseDate.Value.ToUniversalTime();
+ remoteResult.PremiereDate = releaseDate;
+ remoteResult.ProductionYear = releaseDate.Year;
}
- return remoteSearchResults;
+ remoteResult.SetProviderId(MetadataProvider.Tmdb, movie.Id.ToString(CultureInfo.InvariantCulture));
+
+ if (!string.IsNullOrWhiteSpace(movie.ImdbId))
+ {
+ remoteResult.SetProviderId(MetadataProvider.Imdb, movie.ImdbId);
+ }
+
+ return new[] { remoteResult };
}
- var movie = await _tmdbClientManager
- .GetMovieAsync(tmdbId, searchInfo.MetadataLanguage, TmdbUtils.GetImageLanguagesParam(searchInfo.MetadataLanguage), cancellationToken)
- .ConfigureAwait(false);
-
- var remoteResult = new RemoteSearchResult
+ IReadOnlyList movieResults;
+ if (searchInfo.TryGetProviderId(MetadataProvider.Imdb, out id))
{
- Name = movie.Title ?? movie.OriginalTitle,
- SearchProviderName = Name,
- ImageUrl = _tmdbClientManager.GetPosterUrl(movie.PosterPath),
- Overview = movie.Overview
- };
-
- if (movie.ReleaseDate != null)
+ var result = await _tmdbClientManager.FindByExternalIdAsync(
+ id,
+ FindExternalSource.Imdb,
+ TmdbUtils.GetImageLanguagesParam(searchInfo.MetadataLanguage),
+ cancellationToken).ConfigureAwait(false);
+ movieResults = result.MovieResults;
+ }
+ else if (searchInfo.TryGetProviderId(MetadataProvider.Tvdb, out id))
{
- var releaseDate = movie.ReleaseDate.Value.ToUniversalTime();
- remoteResult.PremiereDate = releaseDate;
- remoteResult.ProductionYear = releaseDate.Year;
+ var result = await _tmdbClientManager.FindByExternalIdAsync(
+ id,
+ FindExternalSource.TvDb,
+ TmdbUtils.GetImageLanguagesParam(searchInfo.MetadataLanguage),
+ cancellationToken).ConfigureAwait(false);
+ movieResults = result.MovieResults;
+ }
+ else
+ {
+ movieResults = await _tmdbClientManager
+ .SearchMovieAsync(searchInfo.Name, searchInfo.Year ?? 0, searchInfo.MetadataLanguage, cancellationToken)
+ .ConfigureAwait(false);
}
- remoteResult.SetProviderId(MetadataProvider.Tmdb, movie.Id.ToString(CultureInfo.InvariantCulture));
-
- if (!string.IsNullOrWhiteSpace(movie.ImdbId))
+ var len = movieResults.Count;
+ var remoteSearchResults = new RemoteSearchResult[len];
+ for (var i = 0; i < len; i++)
{
- remoteResult.SetProviderId(MetadataProvider.Imdb, movie.ImdbId);
+ var movieResult = movieResults[i];
+ var remoteSearchResult = new RemoteSearchResult
+ {
+ Name = movieResult.Title ?? movieResult.OriginalTitle,
+ ImageUrl = _tmdbClientManager.GetPosterUrl(movieResult.PosterPath),
+ Overview = movieResult.Overview,
+ SearchProviderName = Name
+ };
+
+ var releaseDate = movieResult.ReleaseDate?.ToUniversalTime();
+ remoteSearchResult.PremiereDate = releaseDate;
+ remoteSearchResult.ProductionYear = releaseDate?.Year;
+
+ remoteSearchResult.SetProviderId(MetadataProvider.Tmdb, movieResult.Id.ToString(CultureInfo.InvariantCulture));
+ remoteSearchResults[i] = remoteSearchResult;
}
- return new[] { remoteResult };
+ return remoteSearchResults;
}
public async Task> GetMetadata(MovieInfo info, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
index 90e13f12f..5fcf6d9aa 100644
--- a/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
+++ b/MediaBrowser.Providers/Studios/StudiosImageProvider.cs
@@ -144,7 +144,7 @@ namespace MediaBrowser.Providers.Studios
var httpClient = _httpClientFactory.CreateClient(NamedClient.Default);
Directory.CreateDirectory(Path.GetDirectoryName(file));
- await using var response = await httpClient.GetStreamAsync(url).ConfigureAwait(false);
+ await using var response = await httpClient.GetStreamAsync(url, cancellationToken).ConfigureAwait(false);
await using var fileStream = new FileStream(file, FileMode.Create);
await response.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false);
}
diff --git a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
index 67700f5fb..6f164caf3 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/BaseNfoParser.cs
@@ -12,6 +12,7 @@ using System.Xml;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.XbmcMetadata.Configuration;
@@ -24,20 +25,31 @@ namespace MediaBrowser.XbmcMetadata.Parsers
where T : BaseItem
{
private readonly IConfigurationManager _config;
+ private readonly IUserManager _userManager;
+ private readonly IUserDataManager _userDataManager;
private Dictionary _validProviderIds;
///
/// Initializes a new instance of the class.
///
- /// The logger.
- /// the configuration manager.
- /// The provider manager.
- public BaseNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager)
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ public BaseNfoParser(
+ ILogger logger,
+ IConfigurationManager config,
+ IProviderManager providerManager,
+ IUserManager userManager,
+ IUserDataManager userDataManager)
{
Logger = logger;
_config = config;
ProviderManager = providerManager;
_validProviderIds = new Dictionary();
+ _userManager = userManager;
+ _userDataManager = userDataManager;
}
protected CultureInfo UsCulture { get; } = new CultureInfo("en-US");
@@ -261,6 +273,14 @@ namespace MediaBrowser.XbmcMetadata.Parsers
{
var item = itemResult.Item;
+ var nfoConfiguration = _config.GetNfoConfiguration();
+ UserItemData? userData = null;
+ if (!string.IsNullOrWhiteSpace(nfoConfiguration.UserId))
+ {
+ var user = _userManager.GetUserById(Guid.Parse(nfoConfiguration.UserId));
+ userData = _userDataManager.GetUserData(user, item);
+ }
+
switch (reader.Name)
{
// DateCreated
@@ -355,6 +375,50 @@ namespace MediaBrowser.XbmcMetadata.Parsers
break;
}
+ case "watched":
+ {
+ var val = reader.ReadElementContentAsBoolean();
+
+ if (userData != null)
+ {
+ userData.Played = val;
+ }
+
+ break;
+ }
+
+ case "playcount":
+ {
+ var val = reader.ReadElementContentAsString();
+ if (!string.IsNullOrWhiteSpace(val) && userData != null)
+ {
+ if (int.TryParse(val, NumberStyles.Integer, UsCulture, out var count))
+ {
+ userData.PlayCount = count;
+ }
+ }
+
+ break;
+ }
+
+ case "lastplayed":
+ {
+ var val = reader.ReadElementContentAsString();
+ if (!string.IsNullOrWhiteSpace(val) && userData != null)
+ {
+ if (DateTime.TryParse(val, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var added))
+ {
+ userData.LastPlayedDate = added.ToUniversalTime();
+ }
+ else
+ {
+ Logger.LogWarning("Invalid lastplayed value found: {Value}", val);
+ }
+ }
+
+ break;
+ }
+
case "countrycode":
{
var val = reader.ReadElementContentAsString();
@@ -622,7 +686,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
case "premiered":
case "releasedate":
{
- var formatString = _config.GetNfoConfiguration().ReleaseDateFormat;
+ var formatString = nfoConfiguration.ReleaseDateFormat;
var val = reader.ReadElementContentAsString();
@@ -640,7 +704,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
case "enddate":
{
- var formatString = _config.GetNfoConfiguration().ReleaseDateFormat;
+ var formatString = nfoConfiguration.ReleaseDateFormat;
var val = reader.ReadElementContentAsString();
diff --git a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs
index 81774b873..f0c50d8e5 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/EpisodeNfoParser.cs
@@ -6,6 +6,7 @@ using System.Threading;
using System.Xml;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using Microsoft.Extensions.Logging;
@@ -19,11 +20,18 @@ namespace MediaBrowser.XbmcMetadata.Parsers
///
/// Initializes a new instance of the class.
///
- /// The logger.
- /// the configuration manager.
- /// The provider manager.
- public EpisodeNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager)
- : base(logger, config, providerManager)
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ public EpisodeNfoParser(
+ ILogger logger,
+ IConfigurationManager config,
+ IProviderManager providerManager,
+ IUserManager userManager,
+ IUserDataManager userDataManager)
+ : base(logger, config, providerManager, userManager, userDataManager)
{
}
diff --git a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs
index 33b0ae887..2d0eb8433 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/MovieNfoParser.cs
@@ -5,6 +5,7 @@ using System.Xml;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using Microsoft.Extensions.Logging;
@@ -19,11 +20,18 @@ namespace MediaBrowser.XbmcMetadata.Parsers
///
/// Initializes a new instance of the class.
///
- /// The logger.
- /// the configuration manager.
- /// The provider manager.
- public MovieNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager)
- : base(logger, config, providerManager)
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ public MovieNfoParser(
+ ILogger logger,
+ IConfigurationManager config,
+ IProviderManager providerManager,
+ IUserManager userManager,
+ IUserDataManager userDataManager)
+ : base(logger, config, providerManager, userManager, userDataManager)
{
}
diff --git a/MediaBrowser.XbmcMetadata/Parsers/SeasonNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/SeasonNfoParser.cs
index d8cd88b9a..bd2607bd8 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/SeasonNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/SeasonNfoParser.cs
@@ -2,6 +2,7 @@ using System.Globalization;
using System.Xml;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using Microsoft.Extensions.Logging;
@@ -15,11 +16,18 @@ namespace MediaBrowser.XbmcMetadata.Parsers
///
/// Initializes a new instance of the class.
///
- /// The logger.
- /// the configuration manager.
- /// The provider manager.
- public SeasonNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager)
- : base(logger, config, providerManager)
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ public SeasonNfoParser(
+ ILogger logger,
+ IConfigurationManager config,
+ IProviderManager providerManager,
+ IUserManager userManager,
+ IUserDataManager userDataManager)
+ : base(logger, config, providerManager, userManager, userDataManager)
{
}
diff --git a/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs b/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs
index 74a724989..fbab8b521 100644
--- a/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs
+++ b/MediaBrowser.XbmcMetadata/Parsers/SeriesNfoParser.cs
@@ -17,11 +17,18 @@ namespace MediaBrowser.XbmcMetadata.Parsers
///
/// Initializes a new instance of the class.
///
- /// The logger.
- /// the configuration manager.
- /// The provider manager.
- public SeriesNfoParser(ILogger logger, IConfigurationManager config, IProviderManager providerManager)
- : base(logger, config, providerManager)
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ public SeriesNfoParser(
+ ILogger logger,
+ IConfigurationManager config,
+ IProviderManager providerManager,
+ IUserManager userManager,
+ IUserDataManager userDataManager)
+ : base(logger, config, providerManager, userManager, userDataManager)
{
}
diff --git a/MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs b/MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs
index b3e2f2717..cfe06b940 100644
--- a/MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs
+++ b/MediaBrowser.XbmcMetadata/Properties/AssemblyInfo.cs
@@ -1,5 +1,6 @@
using System.Reflection;
using System.Resources;
+using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
@@ -14,6 +15,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
+[assembly: InternalsVisibleTo("Jellyfin.XbmcMetadata.Tests")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
diff --git a/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs
index 433a936d9..24f127411 100644
--- a/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/AlbumNfoProvider.cs
@@ -2,6 +2,7 @@ using System.IO;
using System.Threading;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.IO;
using MediaBrowser.XbmcMetadata.Parsers;
@@ -17,30 +18,38 @@ namespace MediaBrowser.XbmcMetadata.Providers
private readonly ILogger _logger;
private readonly IConfigurationManager _config;
private readonly IProviderManager _providerManager;
+ private readonly IUserManager _userManager;
+ private readonly IUserDataManager _userDataManager;
///
/// Initializes a new instance of the class.
///
- /// The logger.
- /// The file system.
- /// the configuration manager.
- /// The provider manager.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
public AlbumNfoProvider(
ILogger logger,
IFileSystem fileSystem,
IConfigurationManager config,
- IProviderManager providerManager)
+ IProviderManager providerManager,
+ IUserManager userManager,
+ IUserDataManager userDataManager)
: base(fileSystem)
{
_logger = logger;
_config = config;
_providerManager = providerManager;
+ _userManager = userManager;
+ _userDataManager = userDataManager;
}
///
protected override void Fetch(MetadataResult result, string path, CancellationToken cancellationToken)
{
- new BaseNfoParser(_logger, _config, _providerManager).Fetch(result, path, cancellationToken);
+ new BaseNfoParser(_logger, _config, _providerManager, _userManager, _userDataManager).Fetch(result, path, cancellationToken);
}
///
diff --git a/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs
index d69cdc90a..fac28ab59 100644
--- a/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/ArtistNfoProvider.cs
@@ -2,6 +2,7 @@ using System.IO;
using System.Threading;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.IO;
using MediaBrowser.XbmcMetadata.Parsers;
@@ -17,30 +18,38 @@ namespace MediaBrowser.XbmcMetadata.Providers
private readonly ILogger _logger;
private readonly IConfigurationManager _config;
private readonly IProviderManager _providerManager;
+ private readonly IUserManager _userManager;
+ private readonly IUserDataManager _userDataManager;
///
/// Initializes a new instance of the class.
///
- /// The logger.
- /// The file system.
- /// the configuration manager.
- /// The provider manager.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
public ArtistNfoProvider(
IFileSystem fileSystem,
ILogger logger,
IConfigurationManager config,
- IProviderManager providerManager)
+ IProviderManager providerManager,
+ IUserManager userManager,
+ IUserDataManager userDataManager)
: base(fileSystem)
{
_logger = logger;
_config = config;
_providerManager = providerManager;
+ _userManager = userManager;
+ _userDataManager = userDataManager;
}
///
protected override void Fetch(MetadataResult result, string path, CancellationToken cancellationToken)
{
- new BaseNfoParser(_logger, _config, _providerManager).Fetch(result, path, cancellationToken);
+ new BaseNfoParser(_logger, _config, _providerManager, _userManager, _userDataManager).Fetch(result, path, cancellationToken);
}
///
diff --git a/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs
index e7aa3ca07..af722748b 100644
--- a/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/BaseVideoNfoProvider.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Threading;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.IO;
using MediaBrowser.XbmcMetadata.Parsers;
@@ -18,17 +19,23 @@ namespace MediaBrowser.XbmcMetadata.Providers
private readonly ILogger> _logger;
private readonly IConfigurationManager _config;
private readonly IProviderManager _providerManager;
+ private readonly IUserManager _userManager;
+ private readonly IUserDataManager _userDataManager;
public BaseVideoNfoProvider(
ILogger> logger,
IFileSystem fileSystem,
IConfigurationManager config,
- IProviderManager providerManager)
+ IProviderManager providerManager,
+ IUserManager userManager,
+ IUserDataManager userDataManager)
: base(fileSystem)
{
_logger = logger;
_config = config;
_providerManager = providerManager;
+ _userManager = userManager;
+ _userDataManager = userDataManager;
}
///
@@ -38,7 +45,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
{
Item = result.Item
};
- new MovieNfoParser(_logger, _config, _providerManager).Fetch(tmpItem, path, cancellationToken);
+ new MovieNfoParser(_logger, _config, _providerManager, _userManager, _userDataManager).Fetch(tmpItem, path, cancellationToken);
result.Item = (T)tmpItem.Item;
result.People = tmpItem.People;
diff --git a/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs
index 26983b1a6..7233f99dc 100644
--- a/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/EpisodeNfoProvider.cs
@@ -2,6 +2,7 @@ using System.IO;
using System.Threading;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.IO;
using MediaBrowser.XbmcMetadata.Parsers;
@@ -17,30 +18,38 @@ namespace MediaBrowser.XbmcMetadata.Providers
private readonly ILogger _logger;
private readonly IConfigurationManager _config;
private readonly IProviderManager _providerManager;
+ private readonly IUserManager _userManager;
+ private readonly IUserDataManager _userDataManager;
///
/// Initializes a new instance of the class.
///
- /// The logger.
- /// The file system.
- /// the configuration manager.
- /// The provider manager.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
public EpisodeNfoProvider(
ILogger logger,
IFileSystem fileSystem,
IConfigurationManager config,
- IProviderManager providerManager)
+ IProviderManager providerManager,
+ IUserManager userManager,
+ IUserDataManager userDataManager)
: base(fileSystem)
{
_logger = logger;
_config = config;
_providerManager = providerManager;
+ _userManager = userManager;
+ _userDataManager = userDataManager;
}
///
protected override void Fetch(MetadataResult result, string path, CancellationToken cancellationToken)
{
- new EpisodeNfoParser(_logger, _config, _providerManager).Fetch(result, path, cancellationToken);
+ new EpisodeNfoParser(_logger, _config, _providerManager, _userManager, _userDataManager).Fetch(result, path, cancellationToken);
}
///
diff --git a/MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs
index e3f6bada1..811d39a9d 100644
--- a/MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/MovieNfoProvider.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging;
@@ -14,16 +15,20 @@ namespace MediaBrowser.XbmcMetadata.Providers
///
/// Initializes a new instance of the class.
///
- /// The logger.
- /// The file system.
- /// the configuration manager.
- /// The provider manager.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
public MovieNfoProvider(
ILogger logger,
IFileSystem fileSystem,
IConfigurationManager config,
- IProviderManager providerManager)
- : base(logger, fileSystem, config, providerManager)
+ IProviderManager providerManager,
+ IUserManager userManager,
+ IUserDataManager userDataManager)
+ : base(logger, fileSystem, config, providerManager, userManager, userDataManager)
{
}
}
diff --git a/MediaBrowser.XbmcMetadata/Providers/MusicVideoNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/MusicVideoNfoProvider.cs
index b490a7120..09df509ee 100644
--- a/MediaBrowser.XbmcMetadata/Providers/MusicVideoNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/MusicVideoNfoProvider.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging;
@@ -14,12 +15,20 @@ namespace MediaBrowser.XbmcMetadata.Providers
///
/// Initializes a new instance of the class.
///
- /// The logger.
- /// The file system.
- /// the configuration manager.
- /// The provider manager.
- public MusicVideoNfoProvider(ILogger logger, IFileSystem fileSystem, IConfigurationManager config, IProviderManager providerManager)
- : base(logger, fileSystem, config, providerManager)
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ public MusicVideoNfoProvider(
+ ILogger logger,
+ IFileSystem fileSystem,
+ IConfigurationManager config,
+ IProviderManager providerManager,
+ IUserManager userManager,
+ IUserDataManager userDataManager)
+ : base(logger, fileSystem, config, providerManager, userManager, userDataManager)
{
}
}
diff --git a/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs
index 0603fd0d1..8f0ed6df7 100644
--- a/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/SeasonNfoProvider.cs
@@ -2,6 +2,7 @@ using System.IO;
using System.Threading;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.IO;
using MediaBrowser.XbmcMetadata.Parsers;
@@ -17,30 +18,38 @@ namespace MediaBrowser.XbmcMetadata.Providers
private readonly ILogger _logger;
private readonly IConfigurationManager _config;
private readonly IProviderManager _providerManager;
+ private readonly IUserManager _userManager;
+ private readonly IUserDataManager _userDataManager;
///
/// Initializes a new instance of the class.
///
- /// The logger.
- /// The file system.
- /// the configuration manager.
- /// The provider manager.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
public SeasonNfoProvider(
ILogger logger,
IFileSystem fileSystem,
IConfigurationManager config,
- IProviderManager providerManager)
+ IProviderManager providerManager,
+ IUserManager userManager,
+ IUserDataManager userDataManager)
: base(fileSystem)
{
_logger = logger;
_config = config;
_providerManager = providerManager;
+ _userManager = userManager;
+ _userDataManager = userDataManager;
}
///
protected override void Fetch(MetadataResult result, string path, CancellationToken cancellationToken)
{
- new SeasonNfoParser(_logger, _config, _providerManager).Fetch(result, path, cancellationToken);
+ new SeasonNfoParser(_logger, _config, _providerManager, _userManager, _userDataManager).Fetch(result, path, cancellationToken);
}
///
diff --git a/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs
index 7e059e0aa..3e496dc58 100644
--- a/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/SeriesNfoProvider.cs
@@ -2,6 +2,7 @@ using System.IO;
using System.Threading;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.IO;
using MediaBrowser.XbmcMetadata.Parsers;
@@ -17,30 +18,38 @@ namespace MediaBrowser.XbmcMetadata.Providers
private readonly ILogger _logger;
private readonly IConfigurationManager _config;
private readonly IProviderManager _providerManager;
+ private readonly IUserManager _userManager;
+ private readonly IUserDataManager _userDataManager;
///
/// Initializes a new instance of the class.
///
- /// The logger.
- /// The file system.
- /// the configuration manager.
- /// The provider manager.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
public SeriesNfoProvider(
ILogger logger,
IFileSystem fileSystem,
IConfigurationManager config,
- IProviderManager providerManager)
+ IProviderManager providerManager,
+ IUserManager userManager,
+ IUserDataManager userDataManager)
: base(fileSystem)
{
_logger = logger;
_config = config;
_providerManager = providerManager;
+ _userManager = userManager;
+ _userDataManager = userDataManager;
}
///
protected override void Fetch(MetadataResult result, string path, CancellationToken cancellationToken)
{
- new SeriesNfoParser(_logger, _config, _providerManager).Fetch(result, path, cancellationToken);
+ new SeriesNfoParser(_logger, _config, _providerManager, _userManager, _userDataManager).Fetch(result, path, cancellationToken);
}
///
diff --git a/MediaBrowser.XbmcMetadata/Providers/VideoNfoProvider.cs b/MediaBrowser.XbmcMetadata/Providers/VideoNfoProvider.cs
index f66ad30ca..4717d81e6 100644
--- a/MediaBrowser.XbmcMetadata/Providers/VideoNfoProvider.cs
+++ b/MediaBrowser.XbmcMetadata/Providers/VideoNfoProvider.cs
@@ -1,5 +1,6 @@
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.IO;
using Microsoft.Extensions.Logging;
@@ -14,12 +15,20 @@ namespace MediaBrowser.XbmcMetadata.Providers
///
/// Initializes a new instance of the class.
///
- /// The logger.
- /// The file system.
- /// the configuration manager.
- /// The provider manager.
- public VideoNfoProvider(ILogger logger, IFileSystem fileSystem, IConfigurationManager config, IProviderManager providerManager)
- : base(logger, fileSystem, config, providerManager)
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ /// Instance of the interface.
+ public VideoNfoProvider(
+ ILogger logger,
+ IFileSystem fileSystem,
+ IConfigurationManager config,
+ IProviderManager providerManager,
+ IUserManager userManager,
+ IUserDataManager userDataManager)
+ : base(logger, fileSystem, config, providerManager, userManager, userDataManager)
{
}
}
diff --git a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
index 9f22e618e..0edab3787 100644
--- a/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
+++ b/MediaBrowser.XbmcMetadata/Savers/BaseNfoSaver.cs
@@ -465,7 +465,7 @@ namespace MediaBrowser.XbmcMetadata.Savers
if (item.LockedFields.Length > 0)
{
- writer.WriteElementString("lockedfields", string.Join("|", item.LockedFields));
+ writer.WriteElementString("lockedfields", string.Join('|', item.LockedFields));
}
writer.WriteElementString("dateadded", item.DateCreated.ToLocalTime().ToString(DateAddedFormat, CultureInfo.InvariantCulture));
diff --git a/jellyfin.ruleset b/jellyfin.ruleset
index 371f02566..81337390c 100644
--- a/jellyfin.ruleset
+++ b/jellyfin.ruleset
@@ -32,11 +32,17 @@
+
+
+
+
+
diff --git a/tests/Jellyfin.Api.Tests/BrandingServiceTests.cs b/tests/Jellyfin.Api.Tests/Controllers/BrandingControllerTests.cs
similarity index 60%
rename from tests/Jellyfin.Api.Tests/BrandingServiceTests.cs
rename to tests/Jellyfin.Api.Tests/Controllers/BrandingControllerTests.cs
index 1cbe94c5b..40933562d 100644
--- a/tests/Jellyfin.Api.Tests/BrandingServiceTests.cs
+++ b/tests/Jellyfin.Api.Tests/Controllers/BrandingControllerTests.cs
@@ -1,3 +1,5 @@
+using System.Net.Mime;
+using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using MediaBrowser.Model.Branding;
@@ -5,11 +7,11 @@ using Xunit;
namespace Jellyfin.Api.Tests
{
- public sealed class BrandingServiceTests : IClassFixture
+ public sealed class BrandingControllerTests : IClassFixture
{
private readonly JellyfinApplicationFactory _factory;
- public BrandingServiceTests(JellyfinApplicationFactory factory)
+ public BrandingControllerTests(JellyfinApplicationFactory factory)
{
_factory = factory;
}
@@ -24,8 +26,9 @@ namespace Jellyfin.Api.Tests
var response = await client.GetAsync("/Branding/Configuration");
// Assert
- response.EnsureSuccessStatusCode();
- Assert.Equal("application/json; charset=utf-8", response.Content.Headers.ContentType?.ToString());
+ Assert.True(response.IsSuccessStatusCode);
+ Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
+ Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
var responseBody = await response.Content.ReadAsStreamAsync();
_ = await JsonSerializer.DeserializeAsync(responseBody);
}
@@ -42,8 +45,9 @@ namespace Jellyfin.Api.Tests
var response = await client.GetAsync(url);
// Assert
- response.EnsureSuccessStatusCode();
- Assert.Equal("text/css; charset=utf-8", response.Content.Headers.ContentType?.ToString());
+ Assert.True(response.IsSuccessStatusCode);
+ Assert.Equal("text/css", response.Content.Headers.ContentType?.MediaType);
+ Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
}
}
}
diff --git a/tests/Jellyfin.Api.Tests/Controllers/DashboardControllerTests.cs b/tests/Jellyfin.Api.Tests/Controllers/DashboardControllerTests.cs
new file mode 100644
index 000000000..300b2697f
--- /dev/null
+++ b/tests/Jellyfin.Api.Tests/Controllers/DashboardControllerTests.cs
@@ -0,0 +1,86 @@
+using System.IO;
+using System.Net;
+using System.Net.Mime;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Jellyfin.Api.Models;
+using MediaBrowser.Common.Json;
+using Xunit;
+
+namespace Jellyfin.Api.Tests.Controllers
+{
+ public sealed class DashboardControllerTests : IClassFixture
+ {
+ private readonly JellyfinApplicationFactory _factory;
+ private readonly JsonSerializerOptions _jsonOpions = JsonDefaults.GetOptions();
+
+ public DashboardControllerTests(JellyfinApplicationFactory factory)
+ {
+ _factory = factory;
+ }
+
+ [Fact]
+ public async Task GetDashboardConfigurationPage_NonExistingPage_NotFound()
+ {
+ var client = _factory.CreateClient();
+
+ var response = await client.GetAsync("web/ConfigurationPage?name=ThisPageDoesntExists").ConfigureAwait(false);
+
+ Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
+ }
+
+ [Fact]
+ public async Task GetDashboardConfigurationPage_ExistingPage_CorrectPage()
+ {
+ var client = _factory.CreateClient();
+
+ var response = await client.GetAsync("/web/ConfigurationPage?name=TestPlugin").ConfigureAwait(false);
+
+ Assert.True(response.IsSuccessStatusCode);
+ Assert.Equal(MediaTypeNames.Text.Html, response.Content.Headers.ContentType?.MediaType);
+ StreamReader reader = new StreamReader(typeof(TestPlugin).Assembly.GetManifestResourceStream("Jellyfin.Api.Tests.TestPage.html")!);
+ Assert.Equal(await response.Content.ReadAsStringAsync(), reader.ReadToEnd());
+ }
+
+ [Fact]
+ public async Task GetDashboardConfigurationPage_BrokenPage_NotFound()
+ {
+ var client = _factory.CreateClient();
+
+ var response = await client.GetAsync("/web/ConfigurationPage?name=BrokenPage").ConfigureAwait(false);
+
+ Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
+ }
+
+ [Fact]
+ public async Task GetConfigurationPages_NoParams_AllConfigurationPages()
+ {
+ var client = _factory.CreateClient();
+
+ var response = await client.GetAsync("/web/ConfigurationPages").ConfigureAwait(false);
+
+ Assert.True(response.IsSuccessStatusCode);
+
+ var res = await response.Content.ReadAsStreamAsync();
+ _ = await JsonSerializer.DeserializeAsync(res, _jsonOpions);
+ // TODO: check content
+ }
+
+ [Fact]
+ public async Task GetConfigurationPages_True_MainMenuConfigurationPages()
+ {
+ var client = _factory.CreateClient();
+
+ var response = await client.GetAsync("/web/ConfigurationPages?enableInMainMenu=true").ConfigureAwait(false);
+
+ Assert.True(response.IsSuccessStatusCode);
+ Assert.Equal(MediaTypeNames.Application.Json, response.Content.Headers.ContentType?.MediaType);
+ Assert.Equal(Encoding.UTF8.BodyName, response.Content.Headers.ContentType?.CharSet);
+
+ var res = await response.Content.ReadAsStreamAsync();
+ var data = await JsonSerializer.DeserializeAsync(res, _jsonOpions);
+ Assert.Empty(data);
+ }
+ }
+}
diff --git a/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs b/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs
index 606041c7f..97e441b1d 100644
--- a/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs
+++ b/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs
@@ -6,11 +6,11 @@ using Xunit;
namespace Jellyfin.Api.Tests.Helpers
{
- public class RequestHelpersTests
+ public static class RequestHelpersTests
{
[Theory]
[MemberData(nameof(GetOrderBy_Success_TestData))]
- public void GetOrderBy_Success(IReadOnlyList sortBy, IReadOnlyList requestedSortOrder, (string, SortOrder)[] expected)
+ public static void GetOrderBy_Success(IReadOnlyList sortBy, IReadOnlyList requestedSortOrder, (string, SortOrder)[] expected)
{
Assert.Equal(expected, RequestHelpers.GetOrderBy(sortBy, requestedSortOrder));
}
@@ -55,5 +55,35 @@ namespace Jellyfin.Api.Tests.Helpers
}
};
}
+
+ [Fact]
+ public static void GetItemTypeStrings_Empty_Empty()
+ {
+ Assert.Empty(RequestHelpers.GetItemTypeStrings(Array.Empty()));
+ }
+
+ [Fact]
+ public static void GetItemTypeStrings_Valid_Success()
+ {
+ BaseItemKind[] input =
+ {
+ BaseItemKind.AggregateFolder,
+ BaseItemKind.Audio,
+ BaseItemKind.BasePluginFolder,
+ BaseItemKind.CollectionFolder
+ };
+
+ string[] expected =
+ {
+ "AggregateFolder",
+ "Audio",
+ "BasePluginFolder",
+ "CollectionFolder"
+ };
+
+ var res = RequestHelpers.GetItemTypeStrings(input);
+
+ Assert.Equal(expected, res);
+ }
}
}
diff --git a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
index eca3df79b..c6a8ffbd0 100644
--- a/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
+++ b/tests/Jellyfin.Api.Tests/Jellyfin.Api.Tests.csproj
@@ -21,7 +21,7 @@
-
+
@@ -41,4 +41,8 @@
../jellyfin-tests.ruleset
+
+
+
+
diff --git a/tests/Jellyfin.Api.Tests/JellyfinApplicationFactory.cs b/tests/Jellyfin.Api.Tests/JellyfinApplicationFactory.cs
index 54f8eb225..dbbd5ac28 100644
--- a/tests/Jellyfin.Api.Tests/JellyfinApplicationFactory.cs
+++ b/tests/Jellyfin.Api.Tests/JellyfinApplicationFactory.cs
@@ -73,7 +73,7 @@ namespace Jellyfin.Api.Tests
_disposableComponents.Add(loggerFactory);
// Create the app host and initialize it
- var appHost = new CoreAppHost(
+ var appHost = new TestAppHost(
appPaths,
loggerFactory,
commandLineOpts,
@@ -93,7 +93,7 @@ namespace Jellyfin.Api.Tests
var testServer = base.CreateServer(builder);
// Finish initializing the app host
- var appHost = (CoreAppHost)testServer.Services.GetRequiredService();
+ var appHost = (TestAppHost)testServer.Services.GetRequiredService();
appHost.ServiceProvider = testServer.Services;
appHost.InitializeServices().GetAwaiter().GetResult();
appHost.RunStartupTasksAsync().GetAwaiter().GetResult();
diff --git a/tests/Jellyfin.Api.Tests/ModelBinders/TestType.cs b/tests/Jellyfin.Api.Tests/ModelBinders/TestType.cs
index 544a74637..92c534eae 100644
--- a/tests/Jellyfin.Api.Tests/ModelBinders/TestType.cs
+++ b/tests/Jellyfin.Api.Tests/ModelBinders/TestType.cs
@@ -1,17 +1,11 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
namespace Jellyfin.Api.Tests.ModelBinders
{
public enum TestType
{
-#pragma warning disable SA1602 // Enumeration items should be documented
How,
Much,
Is,
The,
Fish
-#pragma warning restore SA1602 // Enumeration items should be documented
}
}
diff --git a/tests/Jellyfin.Api.Tests/ParseNetworkTests.cs b/tests/Jellyfin.Api.Tests/ParseNetworkTests.cs
index 6c3fd0ee1..3984407ee 100644
--- a/tests/Jellyfin.Api.Tests/ParseNetworkTests.cs
+++ b/tests/Jellyfin.Api.Tests/ParseNetworkTests.cs
@@ -37,28 +37,28 @@ namespace Jellyfin.Api.Tests
EnableIPV6 = ip6
};
- var result = match + ',';
+ var result = match + ",";
ForwardedHeadersOptions options = new ForwardedHeadersOptions();
// Need this here as ::1 and 127.0.0.1 are in them by default.
options.KnownProxies.Clear();
options.KnownNetworks.Clear();
- ApiServiceCollectionExtensions.AddProxyAddresses(settings, hostList.Split(","), options);
+ ApiServiceCollectionExtensions.AddProxyAddresses(settings, hostList.Split(','), options);
var sb = new StringBuilder();
foreach (var item in options.KnownProxies)
{
- sb.Append(item);
- sb.Append(',');
+ sb.Append(item)
+ .Append(',');
}
foreach (var item in options.KnownNetworks)
{
- sb.Append(item.Prefix);
- sb.Append('/');
- sb.Append(item.PrefixLength.ToString(CultureInfo.InvariantCulture));
- sb.Append(',');
+ sb.Append(item.Prefix)
+ .Append('/')
+ .Append(item.PrefixLength.ToString(CultureInfo.InvariantCulture))
+ .Append(',');
}
Assert.Equal(sb.ToString(), result);
diff --git a/tests/Jellyfin.Api.Tests/TestAppHost.cs b/tests/Jellyfin.Api.Tests/TestAppHost.cs
new file mode 100644
index 000000000..772e98d04
--- /dev/null
+++ b/tests/Jellyfin.Api.Tests/TestAppHost.cs
@@ -0,0 +1,51 @@
+using System.Collections.Generic;
+using System.Reflection;
+using Emby.Server.Implementations;
+using Jellyfin.Server;
+using MediaBrowser.Controller;
+using MediaBrowser.Model.IO;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+
+namespace Jellyfin.Api.Tests
+{
+ ///
+ /// Implementation of the abstract class.
+ ///
+ public class TestAppHost : CoreAppHost
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The to be used by the .
+ /// The to be used by the .
+ /// The to be used by the .
+ /// The to be used by the .
+ /// The to be used by the .
+ public TestAppHost(
+ IServerApplicationPaths applicationPaths,
+ ILoggerFactory loggerFactory,
+ IStartupOptions options,
+ IFileSystem fileSystem,
+ IServiceCollection collection)
+ : base(
+ applicationPaths,
+ loggerFactory,
+ options,
+ fileSystem,
+ collection)
+ {
+ }
+
+ ///
+ protected override IEnumerable GetAssembliesWithPartsInternal()
+ {
+ foreach (var a in base.GetAssembliesWithPartsInternal())
+ {
+ yield return a;
+ }
+
+ yield return typeof(TestPlugin).Assembly;
+ }
+ }
+}
diff --git a/tests/Jellyfin.Api.Tests/TestPage.html b/tests/Jellyfin.Api.Tests/TestPage.html
new file mode 100644
index 000000000..8037af8a6
--- /dev/null
+++ b/tests/Jellyfin.Api.Tests/TestPage.html
@@ -0,0 +1,9 @@
+
+
+
+ TestPlugin
+
+
+ This is a Test Page.
+
+
diff --git a/tests/Jellyfin.Api.Tests/TestPlugin.cs b/tests/Jellyfin.Api.Tests/TestPlugin.cs
new file mode 100644
index 000000000..a3b4b6994
--- /dev/null
+++ b/tests/Jellyfin.Api.Tests/TestPlugin.cs
@@ -0,0 +1,43 @@
+#pragma warning disable CS1591
+
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Plugins;
+using MediaBrowser.Model.Plugins;
+using MediaBrowser.Model.Serialization;
+
+namespace Jellyfin.Api.Tests
+{
+ public class TestPlugin : BasePlugin, IHasWebPages
+ {
+ public TestPlugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
+ : base(applicationPaths, xmlSerializer)
+ {
+ Instance = this;
+ }
+
+ public static TestPlugin? Instance { get; private set; }
+
+ public override Guid Id => new Guid("2d350a13-0bf7-4b61-859c-d5e601b5facf");
+
+ public override string Name => nameof(TestPlugin);
+
+ public override string Description => "Server test Plugin.";
+
+ public IEnumerable GetPages()
+ {
+ yield return new PluginPageInfo
+ {
+ Name = Name,
+ EmbeddedResourcePath = GetType().Namespace + ".TestPage.html"
+ };
+
+ yield return new PluginPageInfo
+ {
+ Name = "BrokenPage",
+ EmbeddedResourcePath = GetType().Namespace + ".foobar"
+ };
+ }
+ }
+}
diff --git a/tests/Jellyfin.Common.Tests/Extensions/StringExtensionsTests.cs b/tests/Jellyfin.Common.Tests/Extensions/StringExtensionsTests.cs
deleted file mode 100644
index 8bf613f05..000000000
--- a/tests/Jellyfin.Common.Tests/Extensions/StringExtensionsTests.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using System;
-using MediaBrowser.Common.Extensions;
-using Xunit;
-
-namespace Jellyfin.Common.Tests.Extensions
-{
- public class StringExtensionsTests
- {
- [Theory]
- [InlineData("", 'q', "")]
- [InlineData("Banana split", ' ', "Banana")]
- [InlineData("Banana split", 'q', "Banana split")]
- public void LeftPart_ValidArgsCharNeedle_Correct(string str, char needle, string expectedResult)
- {
- var result = str.AsSpan().LeftPart(needle).ToString();
- Assert.Equal(expectedResult, result);
- }
-
- [Theory]
- [InlineData("", "", "")]
- [InlineData("", "q", "")]
- [InlineData("Banana split", "", "")]
- [InlineData("Banana split", " ", "Banana")]
- [InlineData("Banana split test", " split", "Banana")]
- public void LeftPart_ValidArgsWithoutStringComparison_Correct(string str, string needle, string expectedResult)
- {
- var result = str.AsSpan().LeftPart(needle).ToString();
- Assert.Equal(expectedResult, result);
- }
-
- [Theory]
- [InlineData("", "", StringComparison.Ordinal, "")]
- [InlineData("Banana split", " ", StringComparison.Ordinal, "Banana")]
- [InlineData("Banana split test", " split", StringComparison.Ordinal, "Banana")]
- [InlineData("Banana split test", " Split", StringComparison.Ordinal, "Banana split test")]
- [InlineData("Banana split test", " Splït", StringComparison.InvariantCultureIgnoreCase, "Banana split test")]
- public void LeftPart_ValidArgs_Correct(string str, string needle, StringComparison stringComparison, string expectedResult)
- {
- var result = str.AsSpan().LeftPart(needle, stringComparison).ToString();
- Assert.Equal(expectedResult, result);
- }
- }
-}
diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
index 57edbf902..47e235441 100644
--- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
+++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj
@@ -16,7 +16,7 @@
-
+
diff --git a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
index c766c5445..fb18a8a8d 100644
--- a/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
+++ b/tests/Jellyfin.Controller.Tests/Jellyfin.Controller.Tests.csproj
@@ -16,7 +16,7 @@
-
+
diff --git a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj
index 52a9e1193..7e4a2efad 100644
--- a/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj
+++ b/tests/Jellyfin.Dlna.Tests/Jellyfin.Dlna.Tests.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
index 24f6fb356..ec9cc656a 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
+++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj
@@ -22,7 +22,7 @@
-
+
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs
index 14ad49839..3775555de 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs
+++ b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs
@@ -3,6 +3,7 @@ using System.Globalization;
using System.IO;
using System.Threading;
using MediaBrowser.MediaEncoding.Subtitles;
+using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
namespace Jellyfin.MediaEncoding.Subtitles.Tests
@@ -14,25 +15,15 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests
{
using (var stream = File.OpenRead("Test Data/example.ass"))
{
- var parsed = new AssParser().Parse(stream, CancellationToken.None);
+ var parsed = new AssParser(new NullLogger()).Parse(stream, CancellationToken.None);
Assert.Single(parsed.TrackEvents);
var trackEvent = parsed.TrackEvents[0];
Assert.Equal("1", trackEvent.Id);
Assert.Equal(TimeSpan.Parse("00:00:01.18", CultureInfo.InvariantCulture).Ticks, trackEvent.StartPositionTicks);
Assert.Equal(TimeSpan.Parse("00:00:06.85", CultureInfo.InvariantCulture).Ticks, trackEvent.EndPositionTicks);
- Assert.Equal("Like an Angel with pity on nobody\r\nThe second line in subtitle", trackEvent.Text);
+ Assert.Equal("{\\pos(400,570)}Like an Angel with pity on nobody" + Environment.NewLine + "The second line in subtitle", trackEvent.Text);
}
}
-
- [Fact]
- public void ParseFieldHeaders_Valid_Success()
- {
- const string Line = "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text";
- var headers = AssParser.ParseFieldHeaders(Line);
- Assert.Equal(1, headers["Start"]);
- Assert.Equal(2, headers["End"]);
- Assert.Equal(9, headers["Text"]);
- }
}
}
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs
index 3e2d2de10..537a944b0 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs
+++ b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs
@@ -22,7 +22,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests
Assert.Equal("1", trackEvent1.Id);
Assert.Equal(TimeSpan.Parse("00:02:17.440", CultureInfo.InvariantCulture).Ticks, trackEvent1.StartPositionTicks);
Assert.Equal(TimeSpan.Parse("00:02:20.375", CultureInfo.InvariantCulture).Ticks, trackEvent1.EndPositionTicks);
- Assert.Equal("Senator, we're making\r\nour final approach into Coruscant.", trackEvent1.Text);
+ Assert.Equal("Senator, we're making" + Environment.NewLine + "our final approach into Coruscant.", trackEvent1.Text);
var trackEvent2 = parsed.TrackEvents[1];
Assert.Equal("2", trackEvent2.Id);
diff --git a/tests/Jellyfin.MediaEncoding.Tests/SsaParserTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SsaParserTests.cs
similarity index 61%
rename from tests/Jellyfin.MediaEncoding.Tests/SsaParserTests.cs
rename to tests/Jellyfin.MediaEncoding.Tests/Subtitles/SsaParserTests.cs
index d11cb242c..5033d1de9 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/SsaParserTests.cs
+++ b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SsaParserTests.cs
@@ -1,37 +1,42 @@
+using System;
using System.Collections.Generic;
+using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;
using MediaBrowser.MediaEncoding.Subtitles;
using MediaBrowser.Model.MediaInfo;
+using Microsoft.Extensions.Logging.Abstractions;
using Xunit;
-namespace Jellyfin.MediaEncoding.Tests
+namespace Jellyfin.MediaEncoding.Subtitles.Tests
{
public class SsaParserTests
{
// commonly shared invariant value between tests, assumes default format order
private const string InvariantDialoguePrefix = "[Events]\nDialogue: ,0:00:00.00,0:00:00.01,,,,,,,";
- private SsaParser parser = new SsaParser();
+ private readonly SsaParser _parser = new SsaParser(new NullLogger());
[Theory]
[InlineData("[EvEnTs]\nDialogue: ,0:00:00.00,0:00:00.01,,,,,,,text", "text")] // label casing insensitivity
[InlineData("[Events]\n,0:00:00.00,0:00:00.01,,,,,,,labelless dialogue", "labelless dialogue")] // no "Dialogue:" label, it is optional
- [InlineData("[Events]\nFormat: Text, Start, End, Layer, Effect, Style\nDialogue: reordered text,0:00:00.00,0:00:00.01", "reordered text")] // reordered formats
+ // TODO: Fix upstream
+ // [InlineData("[Events]\nFormat: Text, Start, End, Layer, Effect, Style\nDialogue: reordered text,0:00:00.00,0:00:00.01", "reordered text")] // reordered formats
[InlineData(InvariantDialoguePrefix + "Cased TEXT", "Cased TEXT")] // preserve text casing
[InlineData(InvariantDialoguePrefix + " text ", " text ")] // do not trim text
[InlineData(InvariantDialoguePrefix + "text, more text", "text, more text")] // append excess dialogue values (> 10) to text
[InlineData(InvariantDialoguePrefix + "start {\\fnFont Name}text{\\fn} end", "start text end")] // font name
[InlineData(InvariantDialoguePrefix + "start {\\fs10}text{\\fs} end", "start text end")] // font size
[InlineData(InvariantDialoguePrefix + "start {\\c&H112233}text{\\c} end", "start text end")] // color
- [InlineData(InvariantDialoguePrefix + "start {\\1c&H112233}text{\\1c} end", "start text end")] // primay color
- [InlineData(InvariantDialoguePrefix + "start {\\fnFont Name}text1 {\\fs10}text2{\\fs}{\\fn} {\\1c&H112233}text3{\\1c} end", "start text1 text2 text3 end")] // nested formatting
+ // TODO: Fix upstream
+ // [InlineData(InvariantDialoguePrefix + "start {\\1c&H112233}text{\\1c} end", "start text end")] // primay color
+ // [InlineData(InvariantDialoguePrefix + "start {\\fnFont Name}text1 {\\fs10}text2{\\fs}{\\fn} {\\1c&H112233}text3{\\1c} end", "start text1 text2 text3 end")] // nested formatting
public void Parse(string ssa, string expectedText)
{
using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(ssa)))
{
- SubtitleTrackInfo subtitleTrackInfo = parser.Parse(stream, CancellationToken.None);
+ SubtitleTrackInfo subtitleTrackInfo = _parser.Parse(stream, CancellationToken.None);
SubtitleTrackEvent actual = subtitleTrackInfo.TrackEvents[0];
Assert.Equal(expectedText, actual.Text);
}
@@ -43,7 +48,7 @@ namespace Jellyfin.MediaEncoding.Tests
{
using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(ssa)))
{
- SubtitleTrackInfo subtitleTrackInfo = parser.Parse(stream, CancellationToken.None);
+ SubtitleTrackInfo subtitleTrackInfo = _parser.Parse(stream, CancellationToken.None);
Assert.Equal(expectedSubtitleTrackEvents.Count, subtitleTrackInfo.TrackEvents.Count);
@@ -52,9 +57,10 @@ namespace Jellyfin.MediaEncoding.Tests
SubtitleTrackEvent expected = expectedSubtitleTrackEvents[i];
SubtitleTrackEvent actual = subtitleTrackInfo.TrackEvents[i];
+ Assert.Equal(expected.Id, actual.Id);
+ Assert.Equal(expected.Text, actual.Text);
Assert.Equal(expected.StartPositionTicks, actual.StartPositionTicks);
Assert.Equal(expected.EndPositionTicks, actual.EndPositionTicks);
- Assert.Equal(expected.Text, actual.Text);
}
}
}
@@ -71,26 +77,39 @@ namespace Jellyfin.MediaEncoding.Tests
",
new List
{
- new SubtitleTrackEvent
+ new SubtitleTrackEvent("1", "dialogue1")
{
StartPositionTicks = 11800000,
- EndPositionTicks = 18500000,
- Text = "dialogue1"
+ EndPositionTicks = 18500000
},
- new SubtitleTrackEvent
+ new SubtitleTrackEvent("2", "dialogue2")
{
StartPositionTicks = 21800000,
- EndPositionTicks = 28500000,
- Text = "dialogue2"
+ EndPositionTicks = 28500000
},
- new SubtitleTrackEvent
+ new SubtitleTrackEvent("3", "dialogue3")
{
StartPositionTicks = 31800000,
- EndPositionTicks = 38500000,
- Text = "dialogue3"
+ EndPositionTicks = 38500000
}
}
};
}
+
+ [Fact]
+ public void Parse_Valid_Success()
+ {
+ using (var stream = File.OpenRead("Test Data/example.ssa"))
+ {
+ var parsed = _parser.Parse(stream, CancellationToken.None);
+ Assert.Single(parsed.TrackEvents);
+ var trackEvent = parsed.TrackEvents[0];
+
+ Assert.Equal("1", trackEvent.Id);
+ Assert.Equal(TimeSpan.Parse("00:00:01.18", CultureInfo.InvariantCulture).Ticks, trackEvent.StartPositionTicks);
+ Assert.Equal(TimeSpan.Parse("00:00:06.85", CultureInfo.InvariantCulture).Ticks, trackEvent.EndPositionTicks);
+ Assert.Equal("{\\pos(400,570)}Like an angel with pity on nobody", trackEvent.Text);
+ }
+ }
}
}
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Test Data/example.ssa b/tests/Jellyfin.MediaEncoding.Tests/Test Data/example.ssa
new file mode 100644
index 000000000..dcbb972eb
--- /dev/null
+++ b/tests/Jellyfin.MediaEncoding.Tests/Test Data/example.ssa
@@ -0,0 +1,20 @@
+[Script Info]
+; This is a Sub Station Alpha v4 script.
+; For Sub Station Alpha info and downloads,
+; go to http://www.eswat.demon.co.uk/
+Title: Neon Genesis Evangelion - Episode 26 (neutral Spanish)
+Original Script: RoRo
+Script Updated By: version 2.8.01
+ScriptType: v4.00
+Collisions: Normal
+PlayResY: 600
+PlayDepth: 0
+Timer: 100,0000
+
+[V4 Styles]
+Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding
+Style: DefaultVCD, Arial,28,11861244,11861244,11861244,-2147483640,-1,0,1,1,2,2,30,30,30,0,0
+
+[Events]
+Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
+Dialogue: Marked=0,0:00:01.18,0:00:06.85,DefaultVCD, NTP,0000,0000,0000,,{\pos(400,570)}Like an angel with pity on nobody
diff --git a/tests/Jellyfin.Model.Tests/Entities/ProviderIdsExtensionsTests.cs b/tests/Jellyfin.Model.Tests/Entities/ProviderIdsExtensionsTests.cs
new file mode 100644
index 000000000..c1a1525ba
--- /dev/null
+++ b/tests/Jellyfin.Model.Tests/Entities/ProviderIdsExtensionsTests.cs
@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Model.Entities;
+using Xunit;
+
+namespace Jellyfin.Model.Tests.Entities
+{
+ public class ProviderIdsExtensionsTests
+ {
+ private const string ExampleImdbId = "tt0113375";
+
+ [Fact]
+ public void GetProviderId_NullInstance_ThrowsArgumentNullException()
+ {
+ Assert.Throws(() => ProviderIdsExtensions.GetProviderId(null!, MetadataProvider.Imdb));
+ }
+
+ [Fact]
+ public void GetProviderId_NullName_ThrowsArgumentNullException()
+ {
+ Assert.Throws(() => ProviderIdsExtensionsTestsObject.Empty.GetProviderId(null!));
+ }
+
+ [Fact]
+ public void GetProviderId_NotFoundName_Null()
+ {
+ Assert.Null(ProviderIdsExtensionsTestsObject.Empty.GetProviderId(MetadataProvider.Imdb));
+ }
+
+ [Fact]
+ public void GetProviderId_NullProvider_Null()
+ {
+ var nullProvider = new ProviderIdsExtensionsTestsObject()
+ {
+ ProviderIds = null!
+ };
+
+ Assert.Null(nullProvider.GetProviderId(MetadataProvider.Imdb));
+ }
+
+ [Fact]
+ public void TryGetProviderId_NotFoundName_False()
+ {
+ Assert.False(ProviderIdsExtensionsTestsObject.Empty.TryGetProviderId(MetadataProvider.Imdb, out _));
+ }
+
+ [Fact]
+ public void TryGetProviderId_NullProvider_False()
+ {
+ var nullProvider = new ProviderIdsExtensionsTestsObject()
+ {
+ ProviderIds = null!
+ };
+
+ Assert.False(nullProvider.TryGetProviderId(MetadataProvider.Imdb, out _));
+ }
+
+ [Fact]
+ public void GetProviderId_FoundName_Id()
+ {
+ var provider = new ProviderIdsExtensionsTestsObject();
+ provider.ProviderIds[MetadataProvider.Imdb.ToString()] = ExampleImdbId;
+
+ Assert.Equal(ExampleImdbId, provider.GetProviderId(MetadataProvider.Imdb));
+ }
+
+ [Fact]
+ public void TryGetProviderId_FoundName_True()
+ {
+ var provider = new ProviderIdsExtensionsTestsObject();
+ provider.ProviderIds[MetadataProvider.Imdb.ToString()] = ExampleImdbId;
+
+ Assert.True(provider.TryGetProviderId(MetadataProvider.Imdb, out var id));
+ Assert.Equal(ExampleImdbId, id);
+ }
+
+ [Fact]
+ public void SetProviderId_NullInstance_ThrowsArgumentNullException()
+ {
+ Assert.Throws(() => ProviderIdsExtensions.SetProviderId(null!, MetadataProvider.Imdb, ExampleImdbId));
+ }
+
+ [Fact]
+ public void SetProviderId_Null_Remove()
+ {
+ var provider = new ProviderIdsExtensionsTestsObject();
+ provider.SetProviderId(MetadataProvider.Imdb, null!);
+ Assert.Empty(provider.ProviderIds);
+ }
+
+ [Fact]
+ public void SetProviderId_EmptyName_Remove()
+ {
+ var provider = new ProviderIdsExtensionsTestsObject();
+ provider.ProviderIds[MetadataProvider.Imdb.ToString()] = ExampleImdbId;
+ provider.SetProviderId(MetadataProvider.Imdb, string.Empty);
+ Assert.Empty(provider.ProviderIds);
+ }
+
+ [Fact]
+ public void SetProviderId_NonEmptyId_Success()
+ {
+ var provider = new ProviderIdsExtensionsTestsObject();
+ provider.SetProviderId(MetadataProvider.Imdb, ExampleImdbId);
+ Assert.Single(provider.ProviderIds);
+ }
+
+ [Fact]
+ public void SetProviderId_NullProvider_Success()
+ {
+ var nullProvider = new ProviderIdsExtensionsTestsObject()
+ {
+ ProviderIds = null!
+ };
+
+ nullProvider.SetProviderId(MetadataProvider.Imdb, ExampleImdbId);
+ Assert.Single(nullProvider.ProviderIds);
+ }
+
+ [Fact]
+ public void SetProviderId_NullProviderAndEmptyName_Success()
+ {
+ var nullProvider = new ProviderIdsExtensionsTestsObject()
+ {
+ ProviderIds = null!
+ };
+
+ nullProvider.SetProviderId(MetadataProvider.Imdb, string.Empty);
+ Assert.Null(nullProvider.ProviderIds);
+ }
+
+ private class ProviderIdsExtensionsTestsObject : IHasProviderIds
+ {
+ public static readonly ProviderIdsExtensionsTestsObject Empty = new ProviderIdsExtensionsTestsObject();
+
+ public Dictionary ProviderIds { get; set; } = new Dictionary();
+ }
+ }
+}
diff --git a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj
index 64d51e063..ebdad7c72 100644
--- a/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj
+++ b/tests/Jellyfin.Model.Tests/Jellyfin.Model.Tests.csproj
@@ -11,7 +11,7 @@
-
+
diff --git a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
index a4d5c0d6f..247e6aa7a 100644
--- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
+++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj
@@ -16,7 +16,7 @@
-
+
diff --git a/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs b/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs
index 215c7e540..08af76669 100644
--- a/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs
+++ b/tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs
@@ -1,3 +1,4 @@
+using System;
using System.Linq;
using Emby.Naming.Common;
using Emby.Naming.Video;
@@ -8,11 +9,10 @@ namespace Jellyfin.Naming.Tests.Video
{
public class VideoListResolverTests
{
- private readonly NamingOptions _namingOptions = new NamingOptions();
+ private readonly VideoListResolver _videoListResolver = new VideoListResolver(new NamingOptions());
- // FIXME
- // [Fact]
- private void TestStackAndExtras()
+ [Fact]
+ public void TestStackAndExtras()
{
// No stacking here because there is no part/disc/etc
var files = new[]
@@ -40,23 +40,22 @@ namespace Jellyfin.Naming.Tests.Video
"WillyWonka-trailer.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
}).ToList()).ToList();
Assert.Equal(5, result.Count);
+ var batman = result.FirstOrDefault(x => string.Equals(x.Name, "Batman", StringComparison.Ordinal));
+ Assert.NotNull(batman);
+ Assert.Equal(3, batman!.Files.Count);
+ Assert.Equal(3, batman!.Extras.Count);
- Assert.Equal(3, result[1].Files.Count);
- Assert.Equal(3, result[1].Extras.Count);
- Assert.Equal("Batman", result[1].Name);
-
- Assert.Equal(4, result[2].Files.Count);
- Assert.Equal(2, result[2].Extras.Count);
- Assert.Equal("Harry Potter and the Deathly Hallows", result[2].Name);
+ var harry = result.FirstOrDefault(x => string.Equals(x.Name, "Harry Potter and the Deathly Hallows", StringComparison.Ordinal));
+ Assert.NotNull(harry);
+ Assert.Equal(4, harry!.Files.Count);
+ Assert.Equal(2, harry!.Extras.Count);
}
[Fact]
@@ -68,9 +67,7 @@ namespace Jellyfin.Naming.Tests.Video
"300.nfo"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -88,9 +85,7 @@ namespace Jellyfin.Naming.Tests.Video
"300 trailer.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -108,9 +103,7 @@ namespace Jellyfin.Naming.Tests.Video
"X-Men Days of Future Past-trailer.mp4"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -129,9 +122,7 @@ namespace Jellyfin.Naming.Tests.Video
"X-Men Days of Future Past-trailer2.mp4"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -149,9 +140,7 @@ namespace Jellyfin.Naming.Tests.Video
"Looper.2012.bluray.720p.x264.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -173,9 +162,7 @@ namespace Jellyfin.Naming.Tests.Video
"My video 5.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -193,9 +180,7 @@ namespace Jellyfin.Naming.Tests.Video
@"M:/Movies (DVD)/Movies (Musical)/Sound of Music (1965)/Sound of Music Disc 2"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = true,
FullName = i
@@ -214,9 +199,7 @@ namespace Jellyfin.Naming.Tests.Video
@"My movie #2.mp4"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = true,
FullName = i
@@ -235,9 +218,7 @@ namespace Jellyfin.Naming.Tests.Video
@"No (2012) part1-trailer.mp4"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -256,9 +237,7 @@ namespace Jellyfin.Naming.Tests.Video
@"No (2012)-trailer.mp4"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -278,9 +257,7 @@ namespace Jellyfin.Naming.Tests.Video
@"trailer.mp4"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -300,9 +277,7 @@ namespace Jellyfin.Naming.Tests.Video
@"/MCFAMILY-PC/Private3$/Heterosexual/Breast In Class 2 Counterfeit Racks (2011)/Breast In Class 2 Disc 2 cd2.avi"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -319,9 +294,7 @@ namespace Jellyfin.Naming.Tests.Video
@"/nas-markrobbo78/Videos/INDEX HTPC/Movies/Watched/3 - ACTION/Argo (2012)/movie.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -338,9 +311,7 @@ namespace Jellyfin.Naming.Tests.Video
@"The Colony.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -358,9 +329,7 @@ namespace Jellyfin.Naming.Tests.Video
@"Four Sisters and a Wedding - B.avi"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -378,9 +347,7 @@ namespace Jellyfin.Naming.Tests.Video
@"Four Rooms - A.mp4"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -398,9 +365,7 @@ namespace Jellyfin.Naming.Tests.Video
@"/Server/Despicable Me/movie-trailer.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -420,9 +385,7 @@ namespace Jellyfin.Naming.Tests.Video
@"/Server/Despicable Me/Baywatch (2017) - Trailer.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -440,9 +403,7 @@ namespace Jellyfin.Naming.Tests.Video
@"/Movies/Despicable Me/trailers/trailer.mkv"
};
- var resolver = GetResolver();
-
- var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
+ var result = _videoListResolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
@@ -457,10 +418,5 @@ namespace Jellyfin.Naming.Tests.Video
var stack = new FileStack();
Assert.False(stack.ContainsFile("XX", true));
}
-
- private VideoListResolver GetResolver()
- {
- return new VideoListResolver(_namingOptions);
- }
}
}
diff --git a/tests/Jellyfin.Networking.Tests/NetworkTesting/Jellyfin.Networking.Tests.csproj b/tests/Jellyfin.Networking.Tests/NetworkTesting/Jellyfin.Networking.Tests.csproj
index d77645cd9..36ff93a45 100644
--- a/tests/Jellyfin.Networking.Tests/NetworkTesting/Jellyfin.Networking.Tests.csproj
+++ b/tests/Jellyfin.Networking.Tests/NetworkTesting/Jellyfin.Networking.Tests.csproj
@@ -16,7 +16,7 @@
-
+
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
index 174f29b09..14b8cbd54 100644
--- a/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
+++ b/tests/Jellyfin.Server.Implementations.Tests/Jellyfin.Server.Implementations.Tests.csproj
@@ -26,7 +26,7 @@
-
+
@@ -39,6 +39,7 @@
+
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Users/UserManagerTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Users/UserManagerTests.cs
new file mode 100644
index 000000000..867dda29d
--- /dev/null
+++ b/tests/Jellyfin.Server.Implementations.Tests/Users/UserManagerTests.cs
@@ -0,0 +1,28 @@
+using System;
+using Jellyfin.Server.Implementations.Users;
+using Xunit;
+
+namespace Jellyfin.Server.Implementations.Tests.Users
+{
+ public class UserManagerTests
+ {
+ [Theory]
+ [InlineData("this_is_valid")]
+ [InlineData("this is also valid")]
+ [InlineData("0@_-' .")]
+ public void ThrowIfInvalidUsername_WhenValidUsername_DoesNotThrowArgumentException(string username)
+ {
+ var ex = Record.Exception(() => UserManager.ThrowIfInvalidUsername(username));
+ Assert.Null(ex);
+ }
+
+ [Theory]
+ [InlineData(" ")]
+ [InlineData("")]
+ [InlineData("special characters like & $ ? are not allowed")]
+ public void ThrowIfInvalidUsername_WhenInvalidUsername_ThrowsArgumentException(string username)
+ {
+ Assert.Throws(() => UserManager.ThrowIfInvalidUsername(username));
+ }
+ }
+}
diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj
index aed3e8ac5..bc076caed 100644
--- a/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj
+++ b/tests/Jellyfin.XbmcMetadata.Tests/Jellyfin.XbmcMetadata.Tests.csproj
@@ -18,7 +18,7 @@
-
+
diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Location/MovieNfoLocationTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Location/MovieNfoLocationTests.cs
new file mode 100644
index 000000000..357d61c0b
--- /dev/null
+++ b/tests/Jellyfin.XbmcMetadata.Tests/Location/MovieNfoLocationTests.cs
@@ -0,0 +1,65 @@
+using System.Linq;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Model.System;
+using MediaBrowser.XbmcMetadata.Savers;
+using Xunit;
+
+namespace Jellyfin.XbmcMetadata.Tests.Location
+{
+ public class MovieNfoLocationTests
+ {
+ [Fact]
+ public static void Movie_MixedFolder_Success()
+ {
+ var movie = new Movie() { Path = "/media/movies/Avengers Endgame.mp4", IsInMixedFolder = true };
+
+ var paths = MovieNfoSaver.GetMovieSavePaths(new ItemInfo(movie)).ToArray();
+ Assert.Single(paths);
+ Assert.Contains("/media/movies/Avengers Endgame.nfo", paths);
+ }
+
+ [Fact]
+ public static void Movie_SeparateFolder_Success()
+ {
+ var movie = new Movie() { Path = "/media/movies/Avengers Endgame/Avengers Endgame.mp4" };
+ var path1 = "/media/movies/Avengers Endgame/Avengers Endgame.nfo";
+ var path2 = "/media/movies/Avengers Endgame/movie.nfo";
+
+ // uses ContainingFolderPath which uses Operating system specific paths
+ if (MediaBrowser.Common.System.OperatingSystem.Id == OperatingSystemId.Windows)
+ {
+ movie.Path = movie.Path.Replace('/', '\\');
+ path1 = path1.Replace('/', '\\');
+ path2 = path2.Replace('/', '\\');
+ }
+
+ var paths = MovieNfoSaver.GetMovieSavePaths(new ItemInfo(movie)).ToArray();
+ Assert.Equal(2, paths.Length);
+ Assert.Contains(path1, paths);
+ Assert.Contains(path2, paths);
+ }
+
+ [Fact]
+ public void Movie_DVD_Success()
+ {
+ var movie = new Movie() { Path = "/media/movies/Avengers Endgame", VideoType = VideoType.Dvd };
+ var path1 = "/media/movies/Avengers Endgame/Avengers Endgame.nfo";
+ var path2 = "/media/movies/Avengers Endgame/VIDEO_TS/VIDEO_TS.nfo";
+
+ // uses ContainingFolderPath which uses Operating system specific paths
+ if (MediaBrowser.Common.System.OperatingSystem.Id == OperatingSystemId.Windows)
+ {
+ movie.Path = movie.Path.Replace('/', '\\');
+ path1 = path1.Replace('/', '\\');
+ path2 = path2.Replace('/', '\\');
+ }
+
+ var paths = MovieNfoSaver.GetMovieSavePaths(new ItemInfo(movie)).ToArray();
+ Assert.Equal(2, paths.Length);
+ Assert.Contains(path1, paths);
+ Assert.Contains(path2, paths);
+ }
+ }
+}
diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs
index d0cd8b287..d10ef9b47 100644
--- a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs
+++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/EpisodeNfoProviderTests.cs
@@ -3,6 +3,7 @@ using System.Linq;
using System.Threading;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
@@ -34,7 +35,10 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
var config = new Mock();
config.Setup(x => x.GetConfiguration(It.IsAny()))
.Returns(new XbmcMetadataOptions());
- _parser = new EpisodeNfoParser(new NullLogger(), config.Object, providerManager.Object);
+ var user = new Mock();
+ var userData = new Mock();
+
+ _parser = new EpisodeNfoParser(new NullLogger(), config.Object, providerManager.Object, user.Object, userData.Object);
}
[Fact]
@@ -62,6 +66,10 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
Assert.Equal(2017, item.ProductionYear);
Assert.Single(item.Studios);
Assert.Contains("Starz", item.Studios);
+ Assert.Equal(1, item.IndexNumberEnd);
+ Assert.Equal(2, item.AirsAfterSeasonNumber);
+ Assert.Equal(3, item.AirsBeforeSeasonNumber);
+ Assert.Equal(1, item.AirsBeforeEpisodeNumber);
Assert.Equal("tt5017734", item.ProviderIds[MetadataProvider.Imdb.ToString()]);
Assert.Equal("1276153", item.ProviderIds[MetadataProvider.Tmdb.ToString()]);
diff --git a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs
index 2f7ee65d5..76231391e 100644
--- a/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs
+++ b/tests/Jellyfin.XbmcMetadata.Tests/Parsers/MovieNfoParserTests.cs
@@ -1,8 +1,11 @@
using System;
using System.Linq;
using System.Threading;
+using Jellyfin.Data.Entities;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities;
@@ -18,9 +21,13 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
public class MovieNfoParserTests
{
private readonly MovieNfoParser _parser;
+ private readonly IUserDataManager _userDataManager;
+ private readonly User _testUser;
public MovieNfoParserTests()
{
+ _testUser = new User("Test User", "Auth provider", "Reset provider");
+
var providerManager = new Mock();
var tmdbExternalId = new TmdbMovieExternalId();
@@ -29,10 +36,24 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
providerManager.Setup(x => x.GetExternalIdInfos(It.IsAny()))
.Returns(new[] { externalIdInfo });
- var config = new Mock();
- config.Setup(x => x.GetConfiguration(It.IsAny()))
- .Returns(new XbmcMetadataOptions());
- _parser = new MovieNfoParser(new NullLogger(), config.Object, providerManager.Object);
+ var nfoConfig = new XbmcMetadataOptions()
+ {
+ UserId = "F38E6443-090B-4F7A-BD12-9CFF5020F7BC"
+ };
+ var configManager = new Mock();
+ configManager.Setup(x => x.GetConfiguration(It.IsAny()))
+ .Returns(nfoConfig);
+
+ var user = new Mock();
+ user.Setup(x => x.GetUserById(It.IsAny()))
+ .Returns(_testUser);
+
+ var userData = new Mock();
+ userData.Setup(x => x.GetUserData(_testUser, It.IsAny()))
+ .Returns(new UserItemData());
+
+ _userDataManager = userData.Object;
+ _parser = new MovieNfoParser(new NullLogger(), configManager.Object, providerManager.Object, user.Object, userData.Object);
}
[Fact]
@@ -40,11 +61,11 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
{
var result = new MetadataResult