mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-12-26 17:36:52 +00:00
Minor improvements
This commit is contained in:
parent
fc9f45b42d
commit
19824bff94
|
@ -880,7 +880,7 @@ namespace Emby.Server.Implementations.Channels
|
|||
}
|
||||
}
|
||||
|
||||
private async Task CacheResponse(object result, string path)
|
||||
private async Task CacheResponse(ChannelItemResult result, string path)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
@ -63,13 +61,13 @@ namespace Emby.Server.Implementations.Collections
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<CollectionCreatedEventArgs> CollectionCreated;
|
||||
public event EventHandler<CollectionCreatedEventArgs>? CollectionCreated;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<CollectionModifiedEventArgs> ItemsAddedToCollection;
|
||||
public event EventHandler<CollectionModifiedEventArgs>? ItemsAddedToCollection;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<CollectionModifiedEventArgs> ItemsRemovedFromCollection;
|
||||
public event EventHandler<CollectionModifiedEventArgs>? ItemsRemovedFromCollection;
|
||||
|
||||
private IEnumerable<Folder> FindFolders(string path)
|
||||
{
|
||||
|
@ -80,7 +78,7 @@ namespace Emby.Server.Implementations.Collections
|
|||
.Where(i => _fileSystem.AreEqual(path, i.Path) || _fileSystem.ContainsSubPath(i.Path, path));
|
||||
}
|
||||
|
||||
internal async Task<Folder> EnsureLibraryFolder(string path, bool createIfNeeded)
|
||||
internal async Task<Folder?> EnsureLibraryFolder(string path, bool createIfNeeded)
|
||||
{
|
||||
var existingFolder = FindFolders(path).FirstOrDefault();
|
||||
if (existingFolder != null)
|
||||
|
@ -114,7 +112,7 @@ namespace Emby.Server.Implementations.Collections
|
|||
return Path.Combine(_appPaths.DataPath, "collections");
|
||||
}
|
||||
|
||||
private Task<Folder> GetCollectionsFolder(bool createIfNeeded)
|
||||
private Task<Folder?> GetCollectionsFolder(bool createIfNeeded)
|
||||
{
|
||||
return EnsureLibraryFolder(GetCollectionsFolderPath(), createIfNeeded);
|
||||
}
|
||||
|
@ -203,8 +201,7 @@ namespace Emby.Server.Implementations.Collections
|
|||
|
||||
private async Task AddToCollectionAsync(Guid collectionId, IEnumerable<Guid> ids, bool fireEvent, MetadataRefreshOptions refreshOptions)
|
||||
{
|
||||
var collection = _libraryManager.GetItemById(collectionId) as BoxSet;
|
||||
if (collection == null)
|
||||
if (_libraryManager.GetItemById(collectionId) is not BoxSet collection)
|
||||
{
|
||||
throw new ArgumentException("No collection exists with the supplied Id");
|
||||
}
|
||||
|
@ -256,9 +253,7 @@ namespace Emby.Server.Implementations.Collections
|
|||
/// <inheritdoc />
|
||||
public async Task RemoveFromCollectionAsync(Guid collectionId, IEnumerable<Guid> itemIds)
|
||||
{
|
||||
var collection = _libraryManager.GetItemById(collectionId) as BoxSet;
|
||||
|
||||
if (collection == null)
|
||||
if (_libraryManager.GetItemById(collectionId) is not BoxSet collection)
|
||||
{
|
||||
throw new ArgumentException("No collection exists with the supplied Id");
|
||||
}
|
||||
|
@ -312,11 +307,7 @@ namespace Emby.Server.Implementations.Collections
|
|||
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item is not ISupportsBoxSetGrouping)
|
||||
{
|
||||
results[item.Id] = item;
|
||||
}
|
||||
else
|
||||
if (item is ISupportsBoxSetGrouping)
|
||||
{
|
||||
var itemId = item.Id;
|
||||
|
||||
|
@ -340,6 +331,7 @@ namespace Emby.Server.Implementations.Collections
|
|||
}
|
||||
|
||||
var alreadyInResults = false;
|
||||
|
||||
// this is kind of a performance hack because only Video has alternate versions that should be in a box set?
|
||||
if (item is Video video)
|
||||
{
|
||||
|
@ -355,11 +347,13 @@ namespace Emby.Server.Implementations.Collections
|
|||
}
|
||||
}
|
||||
|
||||
if (!alreadyInResults)
|
||||
if (alreadyInResults)
|
||||
{
|
||||
results[itemId] = item;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
results[item.Id] = item;
|
||||
}
|
||||
|
||||
return results.Values;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
@ -38,10 +36,10 @@ namespace Emby.Server.Implementations.Localization
|
|||
private readonly ConcurrentDictionary<string, Dictionary<string, string>> _dictionaries =
|
||||
new ConcurrentDictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private List<CultureDto> _cultures;
|
||||
|
||||
private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options;
|
||||
|
||||
private List<CultureDto> _cultures = new List<CultureDto>();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LocalizationManager" /> class.
|
||||
/// </summary>
|
||||
|
@ -72,8 +70,8 @@ namespace Emby.Server.Implementations.Localization
|
|||
string countryCode = resource.Substring(RatingsPath.Length, 2);
|
||||
var dict = new Dictionary<string, ParentalRating>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
await using var str = _assembly.GetManifestResourceStream(resource);
|
||||
using var reader = new StreamReader(str);
|
||||
await using var stream = _assembly.GetManifestResourceStream(resource);
|
||||
using var reader = new StreamReader(stream!); // shouldn't be null here, we just got the resource path from Assembly.GetManifestResourceNames()
|
||||
await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
|
@ -113,7 +111,8 @@ namespace Emby.Server.Implementations.Localization
|
|||
{
|
||||
List<CultureDto> list = new List<CultureDto>();
|
||||
|
||||
await using var stream = _assembly.GetManifestResourceStream(CulturesPath);
|
||||
await using var stream = _assembly.GetManifestResourceStream(CulturesPath)
|
||||
?? throw new InvalidOperationException($"Invalid resource path: '{CulturesPath}'");
|
||||
using var reader = new StreamReader(stream);
|
||||
await foreach (var line in reader.ReadAllLinesAsync().ConfigureAwait(false))
|
||||
{
|
||||
|
@ -162,7 +161,7 @@ namespace Emby.Server.Implementations.Localization
|
|||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public CultureDto FindLanguageInfo(string language)
|
||||
public CultureDto? FindLanguageInfo(string language)
|
||||
{
|
||||
// TODO language should ideally be a ReadOnlySpan but moq cannot mock ref structs
|
||||
for (var i = 0; i < _cultures.Count; i++)
|
||||
|
@ -183,9 +182,10 @@ namespace Emby.Server.Implementations.Localization
|
|||
/// <inheritdoc />
|
||||
public IEnumerable<CountryInfo> GetCountries()
|
||||
{
|
||||
using StreamReader reader = new StreamReader(_assembly.GetManifestResourceStream(CountriesPath));
|
||||
|
||||
return JsonSerializer.Deserialize<IEnumerable<CountryInfo>>(reader.ReadToEnd(), _jsonOptions);
|
||||
using StreamReader reader = new StreamReader(
|
||||
_assembly.GetManifestResourceStream(CountriesPath) ?? throw new InvalidOperationException($"Invalid resource path: '{CountriesPath}'"));
|
||||
return JsonSerializer.Deserialize<IEnumerable<CountryInfo>>(reader.ReadToEnd(), _jsonOptions)
|
||||
?? throw new InvalidOperationException($"Resource contains invalid data: '{CountriesPath}'");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -205,7 +205,9 @@ namespace Emby.Server.Implementations.Localization
|
|||
countryCode = "us";
|
||||
}
|
||||
|
||||
return GetRatings(countryCode) ?? GetRatings("us");
|
||||
return GetRatings(countryCode)
|
||||
?? GetRatings("us")
|
||||
?? throw new InvalidOperationException($"Invalid resource path: '{CountriesPath}'");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -213,7 +215,7 @@ namespace Emby.Server.Implementations.Localization
|
|||
/// </summary>
|
||||
/// <param name="countryCode">The country code.</param>
|
||||
/// <returns>The ratings.</returns>
|
||||
private Dictionary<string, ParentalRating> GetRatings(string countryCode)
|
||||
private Dictionary<string, ParentalRating>? GetRatings(string countryCode)
|
||||
{
|
||||
_allParentalRatings.TryGetValue(countryCode, out var value);
|
||||
|
||||
|
@ -238,7 +240,7 @@ namespace Emby.Server.Implementations.Localization
|
|||
|
||||
var ratingsDictionary = GetParentalRatingsDictionary();
|
||||
|
||||
if (ratingsDictionary.TryGetValue(rating, out ParentalRating value))
|
||||
if (ratingsDictionary.TryGetValue(rating, out ParentalRating? value))
|
||||
{
|
||||
return value.Value;
|
||||
}
|
||||
|
@ -268,20 +270,6 @@ namespace Emby.Server.Implementations.Localization
|
|||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasUnicodeCategory(string value, UnicodeCategory category)
|
||||
{
|
||||
foreach (var chr in value)
|
||||
{
|
||||
if (char.GetUnicodeCategory(chr) == category)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GetLocalizedString(string phrase)
|
||||
{
|
||||
|
@ -347,18 +335,21 @@ namespace Emby.Server.Implementations.Localization
|
|||
{
|
||||
await using var stream = _assembly.GetManifestResourceStream(resourcePath);
|
||||
// If a Culture doesn't have a translation the stream will be null and it defaults to en-us further up the chain
|
||||
if (stream != null)
|
||||
{
|
||||
var dict = await JsonSerializer.DeserializeAsync<Dictionary<string, string>>(stream, _jsonOptions).ConfigureAwait(false);
|
||||
|
||||
foreach (var key in dict.Keys)
|
||||
{
|
||||
dictionary[key] = dict[key];
|
||||
}
|
||||
}
|
||||
else
|
||||
if (stream == null)
|
||||
{
|
||||
_logger.LogError("Missing translation/culture resource: {ResourcePath}", resourcePath);
|
||||
return;
|
||||
}
|
||||
|
||||
var dict = await JsonSerializer.DeserializeAsync<Dictionary<string, string>>(stream, _jsonOptions).ConfigureAwait(false);
|
||||
if (dict == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Resource contains invalid data: '{stream}'");
|
||||
}
|
||||
|
||||
foreach (var key in dict.Keys)
|
||||
{
|
||||
dictionary[key] = dict[key];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,10 +47,10 @@ namespace MediaBrowser.Common.Plugins
|
|||
var assemblyFilePath = assembly.Location;
|
||||
|
||||
var dataFolderPath = Path.Combine(ApplicationPaths.PluginsPath, Path.GetFileNameWithoutExtension(assemblyFilePath));
|
||||
if (!Directory.Exists(dataFolderPath) && Version != null)
|
||||
if (Version != null && !Directory.Exists(dataFolderPath))
|
||||
{
|
||||
// Try again with the version number appended to the folder name.
|
||||
dataFolderPath = dataFolderPath + "_" + Version.ToString();
|
||||
dataFolderPath += "_" + Version.ToString();
|
||||
}
|
||||
|
||||
SetAttributes(assemblyFilePath, dataFolderPath, assemblyName.Version);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Jellyfin.Extensions;
|
||||
|
@ -16,7 +15,7 @@ namespace MediaBrowser.Controller.BaseItemManager
|
|||
{
|
||||
private readonly IServerConfigurationManager _serverConfigurationManager;
|
||||
|
||||
private int _metadataRefreshConcurrency = 0;
|
||||
private int _metadataRefreshConcurrency;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BaseItemManager"/> class.
|
||||
|
@ -101,7 +100,7 @@ namespace MediaBrowser.Controller.BaseItemManager
|
|||
/// Called when the configuration is updated.
|
||||
/// It will refresh the metadata throttler if the relevant config changed.
|
||||
/// </summary>
|
||||
private void OnConfigurationUpdated(object sender, EventArgs e)
|
||||
private void OnConfigurationUpdated(object? sender, EventArgs e)
|
||||
{
|
||||
int newMetadataRefreshConcurrency = GetMetadataRefreshConcurrency();
|
||||
if (_metadataRefreshConcurrency != newMetadataRefreshConcurrency)
|
||||
|
@ -114,6 +113,7 @@ namespace MediaBrowser.Controller.BaseItemManager
|
|||
/// <summary>
|
||||
/// Creates the metadata refresh throttler.
|
||||
/// </summary>
|
||||
[MemberNotNull(nameof(MetadataRefreshThrottler))]
|
||||
private void SetupMetadataThrottler()
|
||||
{
|
||||
MetadataRefreshThrottler = new SemaphoreSlim(_metadataRefreshConcurrency);
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#nullable disable
|
||||
|
||||
using System.Threading;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
|
@ -34,4 +32,4 @@ namespace MediaBrowser.Controller.BaseItemManager
|
|||
/// <returns><c>true</c> if image fetcher is enabled, else false.</returns>
|
||||
bool IsImageFetcherEnabled(BaseItem baseItem, LibraryOptions libraryOptions, string name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#nullable disable
|
||||
|
||||
#pragma warning disable CA1002, CA2227, CS1591
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace MediaBrowser.Controller.Channels
|
||||
|
@ -10,10 +9,10 @@ namespace MediaBrowser.Controller.Channels
|
|||
{
|
||||
public ChannelItemResult()
|
||||
{
|
||||
Items = new List<ChannelItemInfo>();
|
||||
Items = Array.Empty<ChannelItemInfo>();
|
||||
}
|
||||
|
||||
public List<ChannelItemInfo> Items { get; set; }
|
||||
public IReadOnlyList<ChannelItemInfo> Items { get; set; }
|
||||
|
||||
public int? TotalRecordCount { get; set; }
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#nullable disable
|
||||
|
||||
#pragma warning disable CA2227, CS1591
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
|
@ -16,17 +14,17 @@ namespace MediaBrowser.Controller.Collections
|
|||
/// <summary>
|
||||
/// Occurs when [collection created].
|
||||
/// </summary>
|
||||
event EventHandler<CollectionCreatedEventArgs> CollectionCreated;
|
||||
event EventHandler<CollectionCreatedEventArgs>? CollectionCreated;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [items added to collection].
|
||||
/// </summary>
|
||||
event EventHandler<CollectionModifiedEventArgs> ItemsAddedToCollection;
|
||||
event EventHandler<CollectionModifiedEventArgs>? ItemsAddedToCollection;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when [items removed from collection].
|
||||
/// </summary>
|
||||
event EventHandler<CollectionModifiedEventArgs> ItemsRemovedFromCollection;
|
||||
event EventHandler<CollectionModifiedEventArgs>? ItemsRemovedFromCollection;
|
||||
|
||||
/// <summary>
|
||||
/// Creates the collection.
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
#nullable disable
|
||||
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Model.Configuration;
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ using System.Collections.Generic;
|
|||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
|
@ -16,9 +15,7 @@ using MediaBrowser.Model.Configuration;
|
|||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Dto;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace MediaBrowser.Controller.MediaEncoding
|
||||
{
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#nullable disable
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
@ -56,19 +55,11 @@ namespace MediaBrowser.Model.Globalization
|
|||
/// <returns><see cref="IEnumerable{LocalizatonOption}" />.</returns>
|
||||
IEnumerable<LocalizationOption> GetLocalizationOptions();
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the string contains a character with the specified unicode category.
|
||||
/// </summary>
|
||||
/// <param name="value">The string.</param>
|
||||
/// <param name="category">The unicode category.</param>
|
||||
/// <returns>Wether or not the string contains a character with the specified unicode category.</returns>
|
||||
bool HasUnicodeCategory(string value, UnicodeCategory category);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the correct <see cref="CultureInfo" /> for the given language.
|
||||
/// </summary>
|
||||
/// <param name="language">The language.</param>
|
||||
/// <returns>The correct <see cref="CultureInfo" /> for the given language.</returns>
|
||||
CultureDto FindLanguageInfo(string language);
|
||||
CultureDto? FindLanguageInfo(string language);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -148,80 +148,76 @@ namespace MediaBrowser.XbmcMetadata.Parsers
|
|||
return;
|
||||
}
|
||||
|
||||
using (var fileStream = File.OpenRead(metadataFile))
|
||||
using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
|
||||
item.ResetPeople();
|
||||
|
||||
// Need to handle a url after the xml data
|
||||
// http://kodi.wiki/view/NFO_files/movies
|
||||
|
||||
var xml = File.ReadAllText(metadataFile);
|
||||
|
||||
// Find last closing Tag
|
||||
// Need to do this in two steps to account for random > characters after the closing xml
|
||||
var index = xml.LastIndexOf(@"</", StringComparison.Ordinal);
|
||||
|
||||
// If closing tag exists, move to end of Tag
|
||||
if (index != -1)
|
||||
{
|
||||
item.ResetPeople();
|
||||
index = xml.IndexOf('>', index);
|
||||
}
|
||||
|
||||
// Need to handle a url after the xml data
|
||||
// http://kodi.wiki/view/NFO_files/movies
|
||||
if (index != -1)
|
||||
{
|
||||
var endingXml = xml.AsSpan().Slice(index);
|
||||
|
||||
var xml = streamReader.ReadToEnd();
|
||||
ParseProviderLinks(item.Item, endingXml);
|
||||
|
||||
// Find last closing Tag
|
||||
// Need to do this in two steps to account for random > characters after the closing xml
|
||||
var index = xml.LastIndexOf(@"</", StringComparison.Ordinal);
|
||||
|
||||
// If closing tag exists, move to end of Tag
|
||||
if (index != -1)
|
||||
// If the file is just an imdb url, don't go any further
|
||||
if (index == 0)
|
||||
{
|
||||
index = xml.IndexOf('>', index);
|
||||
}
|
||||
|
||||
if (index != -1)
|
||||
{
|
||||
var endingXml = xml.Substring(index);
|
||||
|
||||
ParseProviderLinks(item.Item, endingXml);
|
||||
|
||||
// If the file is just an imdb url, don't go any further
|
||||
if (index == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
xml = xml.Substring(0, index + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the file is just provider urls, handle that
|
||||
ParseProviderLinks(item.Item, xml);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// These are not going to be valid xml so no sense in causing the provider to fail and spamming the log with exceptions
|
||||
try
|
||||
xml = xml.Substring(0, index + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the file is just provider urls, handle that
|
||||
ParseProviderLinks(item.Item, xml);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// These are not going to be valid xml so no sense in causing the provider to fail and spamming the log with exceptions
|
||||
try
|
||||
{
|
||||
using (var stringReader = new StringReader(xml))
|
||||
using (var reader = XmlReader.Create(stringReader, settings))
|
||||
{
|
||||
using (var stringReader = new StringReader(xml))
|
||||
using (var reader = XmlReader.Create(stringReader, settings))
|
||||
reader.MoveToContent();
|
||||
reader.Read();
|
||||
|
||||
// Loop through each element
|
||||
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
|
||||
{
|
||||
reader.MoveToContent();
|
||||
reader.Read();
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
// Loop through each element
|
||||
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
FetchDataFromXmlNode(reader, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Read();
|
||||
}
|
||||
FetchDataFromXmlNode(reader, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Read();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
}
|
||||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
protected void ParseProviderLinks(T item, string xml)
|
||||
protected void ParseProviderLinks(T item, ReadOnlySpan<char> xml)
|
||||
{
|
||||
if (ProviderIdParsers.TryFindImdbId(xml, out var imdbId))
|
||||
{
|
||||
|
|
|
@ -40,72 +40,68 @@ namespace MediaBrowser.XbmcMetadata.Parsers
|
|||
/// <inheritdoc />
|
||||
protected override void Fetch(MetadataResult<Episode> item, string metadataFile, XmlReaderSettings settings, CancellationToken cancellationToken)
|
||||
{
|
||||
using (var fileStream = File.OpenRead(metadataFile))
|
||||
using (var streamReader = new StreamReader(fileStream, Encoding.UTF8))
|
||||
item.ResetPeople();
|
||||
|
||||
var xmlFile = File.ReadAllText(metadataFile);
|
||||
|
||||
var srch = "</episodedetails>";
|
||||
var index = xmlFile.IndexOf(srch, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var xml = xmlFile;
|
||||
|
||||
if (index != -1)
|
||||
{
|
||||
item.ResetPeople();
|
||||
xml = xmlFile.Substring(0, index + srch.Length);
|
||||
xmlFile = xmlFile.Substring(index + srch.Length);
|
||||
}
|
||||
|
||||
var xmlFile = streamReader.ReadToEnd();
|
||||
// These are not going to be valid xml so no sense in causing the provider to fail and spamming the log with exceptions
|
||||
try
|
||||
{
|
||||
// Extract episode details from the first episodedetails block
|
||||
using (var stringReader = new StringReader(xml))
|
||||
using (var reader = XmlReader.Create(stringReader, settings))
|
||||
{
|
||||
reader.MoveToContent();
|
||||
reader.Read();
|
||||
|
||||
var srch = "</episodedetails>";
|
||||
var index = xmlFile.IndexOf(srch, StringComparison.OrdinalIgnoreCase);
|
||||
// Loop through each element
|
||||
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var xml = xmlFile;
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
FetchDataFromXmlNode(reader, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Read();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (index != -1)
|
||||
// Extract the last episode number from nfo
|
||||
// This is needed because XBMC metadata uses multiple episodedetails blocks instead of episodenumberend tag
|
||||
while ((index = xmlFile.IndexOf(srch, StringComparison.OrdinalIgnoreCase)) != -1)
|
||||
{
|
||||
xml = xmlFile.Substring(0, index + srch.Length);
|
||||
xmlFile = xmlFile.Substring(index + srch.Length);
|
||||
}
|
||||
|
||||
// These are not going to be valid xml so no sense in causing the provider to fail and spamming the log with exceptions
|
||||
try
|
||||
{
|
||||
// Extract episode details from the first episodedetails block
|
||||
using (var stringReader = new StringReader(xml))
|
||||
using (var reader = XmlReader.Create(stringReader, settings))
|
||||
{
|
||||
reader.MoveToContent();
|
||||
reader.Read();
|
||||
|
||||
// Loop through each element
|
||||
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
|
||||
if (reader.ReadToDescendant("episode") && int.TryParse(reader.ReadElementContentAsString(), out var num))
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (reader.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
FetchDataFromXmlNode(reader, item);
|
||||
}
|
||||
else
|
||||
{
|
||||
reader.Read();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the last episode number from nfo
|
||||
// This is needed because XBMC metadata uses multiple episodedetails blocks instead of episodenumberend tag
|
||||
while ((index = xmlFile.IndexOf(srch, StringComparison.OrdinalIgnoreCase)) != -1)
|
||||
{
|
||||
xml = xmlFile.Substring(0, index + srch.Length);
|
||||
xmlFile = xmlFile.Substring(index + srch.Length);
|
||||
|
||||
using (var stringReader = new StringReader(xml))
|
||||
using (var reader = XmlReader.Create(stringReader, settings))
|
||||
{
|
||||
reader.MoveToContent();
|
||||
|
||||
if (reader.ReadToDescendant("episode") && int.TryParse(reader.ReadElementContentAsString(), out var num))
|
||||
{
|
||||
item.Item.IndexNumberEnd = Math.Max(num, item.Item.IndexNumberEnd ?? num);
|
||||
}
|
||||
item.Item.IndexNumberEnd = Math.Max(num, item.Item.IndexNumberEnd ?? num);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
}
|
||||
}
|
||||
catch (XmlException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace Jellyfin.Server.Implementations.Tests.Localization
|
|||
var germany = localizationManager.FindLanguageInfo(identifier);
|
||||
Assert.NotNull(germany);
|
||||
|
||||
Assert.Equal("ger", germany.ThreeLetterISOLanguageName);
|
||||
Assert.Equal("ger", germany!.ThreeLetterISOLanguageName);
|
||||
Assert.Equal("German", germany.DisplayName);
|
||||
Assert.Equal("German", germany.Name);
|
||||
Assert.Contains("deu", germany.ThreeLetterISOLanguageNames);
|
||||
|
|
Loading…
Reference in a new issue