Merge branch 'master' into comparisons

This commit is contained in:
Cody Robibero
2021-12-24 02:41:50 +00:00
committed by GitHub
980 changed files with 22838 additions and 16047 deletions

View File

@@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using MediaBrowser.Common.Extensions;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Providers;

View File

@@ -1,7 +1,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Providers;
@@ -15,22 +14,18 @@ namespace MediaBrowser.LocalMetadata.Images
/// </summary>
public class InternalMetadataFolderImageProvider : ILocalImageProvider, IHasOrder
{
private readonly IServerConfigurationManager _config;
private readonly IFileSystem _fileSystem;
private readonly ILogger<InternalMetadataFolderImageProvider> _logger;
/// <summary>
/// Initializes a new instance of the <see cref="InternalMetadataFolderImageProvider"/> class.
/// </summary>
/// <param name="config">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
/// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
/// <param name="logger">Instance of the <see cref="ILogger{InternalMetadataFolderImageProvider}"/> interface.</param>
public InternalMetadataFolderImageProvider(
IServerConfigurationManager config,
IFileSystem fileSystem,
ILogger<InternalMetadataFolderImageProvider> logger)
{
_config = config;
_fileSystem = fileSystem;
_logger = logger;
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.Movies;
@@ -60,8 +61,6 @@ namespace MediaBrowser.LocalMetadata.Images
private readonly IFileSystem _fileSystem;
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
/// <summary>
/// Initializes a new instance of the <see cref="LocalImageProvider"/> class.
/// </summary>
@@ -119,16 +118,10 @@ namespace MediaBrowser.LocalMetadata.Images
return Enumerable.Empty<FileSystemMetadata>();
}
if (includeDirectories)
{
return directoryService.GetFileSystemEntries(path)
.Where(i => BaseItem.SupportedImageExtensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase) || i.IsDirectory)
.OrderBy(i => Array.IndexOf(BaseItem.SupportedImageExtensions, i.Extension ?? string.Empty));
}
return directoryService.GetFiles(path)
.Where(i => BaseItem.SupportedImageExtensions.Contains(i.Extension, StringComparer.OrdinalIgnoreCase))
return directoryService.GetFileSystemEntries(path)
.Where(i =>
(includeDirectories && i.IsDirectory)
|| BaseItem.SupportedImageExtensions.Contains(i.Extension, StringComparison.OrdinalIgnoreCase))
.OrderBy(i => Array.IndexOf(BaseItem.SupportedImageExtensions, i.Extension ?? string.Empty));
}
@@ -258,11 +251,6 @@ namespace MediaBrowser.LocalMetadata.Images
{
PopulateBackdrops(item, images, files, imagePrefix, isInMixedFolder);
}
if (item is IHasScreenshots)
{
PopulateScreenshots(images, files, imagePrefix, isInMixedFolder);
}
}
private void PopulatePrimaryImages(BaseItem item, List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, bool isInMixedFolder)
@@ -283,7 +271,7 @@ namespace MediaBrowser.LocalMetadata.Images
{
imageFileNames = _seriesImageFileNames;
}
else if (item is Video && !(item is Episode))
else if (item is Video && item is not Episode)
{
imageFileNames = _videoImageFileNames;
}
@@ -365,11 +353,6 @@ namespace MediaBrowser.LocalMetadata.Images
}));
}
private void PopulateScreenshots(List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, bool isInMixedFolder)
{
PopulateBackdrops(images, files, imagePrefix, "screenshot", "screenshot", isInMixedFolder, ImageType.Screenshot);
}
private void PopulateBackdrops(List<LocalImageInfo> images, List<FileSystemMetadata> files, string imagePrefix, string firstFileName, string subsequentFileNamePrefix, bool isInMixedFolder, ImageType type)
{
AddImage(files, images, imagePrefix + firstFileName, type);
@@ -434,7 +417,7 @@ namespace MediaBrowser.LocalMetadata.Images
var seasonMarker = seasonNumber.Value == 0
? "-specials"
: seasonNumber.Value.ToString("00", _usCulture);
: seasonNumber.Value.ToString("00", CultureInfo.InvariantCulture);
// Get this one directly from the file system since we have to go up a level
if (!string.Equals(prefix, seasonMarker, StringComparison.OrdinalIgnoreCase))

View File

@@ -11,13 +11,9 @@
</ItemGroup>
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Nullable>enable</Nullable>
<AnalysisMode>AllEnabledByDefault</AnalysisMode>
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>

View File

@@ -6,6 +6,7 @@ using System.Linq;
using System.Text;
using System.Threading;
using System.Xml;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
@@ -20,8 +21,6 @@ namespace MediaBrowser.LocalMetadata.Parsers
public class BaseItemXmlParser<T>
where T : BaseItem
{
private readonly CultureInfo _usCulture = new CultureInfo("en-US");
private Dictionary<string, string>? _validProviderIds;
/// <summary>
@@ -81,7 +80,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
var id = info.Key + "Id";
if (!_validProviderIds.ContainsKey(id))
{
_validProviderIds.Add(id, info.Key!);
_validProviderIds.Add(id, info.Key);
}
}
@@ -144,13 +143,13 @@ namespace MediaBrowser.LocalMetadata.Parsers
if (!string.IsNullOrWhiteSpace(val))
{
if (DateTime.TryParse(val, out var added))
if (DateTime.TryParse(val, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out var added))
{
item.DateCreated = added.ToUniversalTime();
item.DateCreated = added;
}
else
{
Logger.LogWarning("Invalid Added value found: " + val);
Logger.LogWarning("Invalid Added value found: {Value}", val);
}
}
@@ -179,7 +178,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
if (!string.IsNullOrEmpty(text))
{
if (float.TryParse(text, NumberStyles.Any, _usCulture, out var value))
if (float.TryParse(text, NumberStyles.Any, CultureInfo.InvariantCulture, out var value))
{
item.CriticRating = value;
}
@@ -331,7 +330,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
if (!string.IsNullOrWhiteSpace(text))
{
if (int.TryParse(text.Split(' ')[0], NumberStyles.Integer, _usCulture, out var runtime))
if (int.TryParse(text.AsSpan().LeftPart(' '), NumberStyles.Integer, CultureInfo.InvariantCulture, out var runtime))
{
item.RunTimeTicks = TimeSpan.FromMinutes(runtime).Ticks;
}
@@ -413,7 +412,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
{
var actors = reader.ReadInnerXml();
if (actors.Contains("<", StringComparison.Ordinal))
if (actors.Contains('<', StringComparison.Ordinal))
{
// This is one of the mis-named "Actors" full nodes created by MB2
// Create a reader and pass it to the persons node processor
@@ -534,9 +533,9 @@ namespace MediaBrowser.LocalMetadata.Parsers
if (!string.IsNullOrWhiteSpace(firstAired))
{
if (DateTime.TryParseExact(firstAired, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var airDate) && airDate.Year > 1850)
if (DateTime.TryParseExact(firstAired, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal | DateTimeStyles.AdjustToUniversal, out var airDate) && airDate.Year > 1850)
{
item.PremiereDate = airDate.ToUniversalTime();
item.PremiereDate = airDate;
item.ProductionYear = airDate.Year;
}
}
@@ -551,9 +550,9 @@ namespace MediaBrowser.LocalMetadata.Parsers
if (!string.IsNullOrWhiteSpace(firstAired))
{
if (DateTime.TryParseExact(firstAired, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out var airDate) && airDate.Year > 1850)
if (DateTime.TryParseExact(firstAired, "yyyy-MM-dd", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal | DateTimeStyles.AdjustToUniversal, out var airDate) && airDate.Year > 1850)
{
item.EndDate = airDate.ToUniversalTime();
item.EndDate = airDate;
}
}
@@ -750,46 +749,6 @@ namespace MediaBrowser.LocalMetadata.Parsers
item.Shares = list.ToArray();
}
private Share GetShareFromNode(XmlReader reader)
{
var share = new Share();
reader.MoveToContent();
reader.Read();
// Loop through each element
while (!reader.EOF && reader.ReadState == ReadState.Interactive)
{
if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "UserId":
{
share.UserId = reader.ReadElementContentAsString();
break;
}
case "CanEdit":
{
share.CanEdit = string.Equals(reader.ReadElementContentAsString(), true.ToString(CultureInfo.InvariantCulture), StringComparison.OrdinalIgnoreCase);
break;
}
default:
reader.Skip();
break;
}
}
else
{
reader.Read();
}
}
return share;
}
private void FetchFromCountriesNode(XmlReader reader)
{
reader.MoveToContent();
@@ -1101,7 +1060,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
switch (reader.Name)
{
case "Name":
name = reader.ReadElementContentAsString() ?? string.Empty;
name = reader.ReadElementContentAsString();
break;
case "Type":
@@ -1134,7 +1093,7 @@ namespace MediaBrowser.LocalMetadata.Parsers
if (!string.IsNullOrWhiteSpace(val))
{
if (int.TryParse(val, NumberStyles.Integer, _usCulture, out var intVal))
if (int.TryParse(val, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intVal))
{
sortOrder = intVal;
}
@@ -1270,8 +1229,6 @@ namespace MediaBrowser.LocalMetadata.Parsers
/// <returns>IEnumerable{System.String}.</returns>
private IEnumerable<string> SplitNames(string value)
{
value ??= string.Empty;
// Only split by comma if there is no pipe in the string
// We have to be careful to not split names like Matthew, Jr.
var separator = !value.Contains('|', StringComparison.Ordinal)

View File

@@ -25,24 +25,18 @@ namespace MediaBrowser.LocalMetadata.Savers
/// </summary>
public const string DateAddedFormat = "yyyy-MM-dd HH:mm:ss";
private static readonly CultureInfo _usCulture = new CultureInfo("en-US");
/// <summary>
/// Initializes a new instance of the <see cref="BaseXmlSaver"/> class.
/// </summary>
/// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
/// <param name="configurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
/// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
/// <param name="logger">Instance of the <see cref="ILogger{BaseXmlSaver}"/> interface.</param>
protected BaseXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger<BaseXmlSaver> logger)
protected BaseXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ILogger<BaseXmlSaver> logger)
{
FileSystem = fileSystem;
ConfigurationManager = configurationManager;
LibraryManager = libraryManager;
UserManager = userManager;
UserDataManager = userDataManager;
Logger = logger;
}
@@ -61,16 +55,6 @@ namespace MediaBrowser.LocalMetadata.Savers
/// </summary>
protected ILibraryManager LibraryManager { get; private set; }
/// <summary>
/// Gets the user manager.
/// </summary>
protected IUserManager UserManager { get; private set; }
/// <summary>
/// Gets the user data manager.
/// </summary>
protected IUserDataManager UserDataManager { get; private set; }
/// <summary>
/// Gets the logger.
/// </summary>
@@ -129,11 +113,19 @@ namespace MediaBrowser.LocalMetadata.Savers
{
var directory = Path.GetDirectoryName(path) ?? throw new ArgumentException($"Provided path ({path}) is not valid.", nameof(path));
Directory.CreateDirectory(directory);
// On Windows, savint the file will fail if the file is hidden or readonly
FileSystem.SetAttributes(path, false, false);
// use FileShare.None as this bypasses dotnet bug dotnet/runtime#42790 .
using (var filestream = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None))
var fileStreamOptions = new FileStreamOptions()
{
Mode = FileMode.Create,
Access = FileAccess.Write,
Share = FileShare.None,
PreallocationSize = stream.Length
};
using (var filestream = new FileStream(path, fileStreamOptions))
{
stream.CopyTo(filestream);
}
@@ -152,7 +144,7 @@ namespace MediaBrowser.LocalMetadata.Savers
}
catch (Exception ex)
{
Logger.LogError(ex, "Error setting hidden attribute on {path}", path);
Logger.LogError(ex, "Error setting hidden attribute on {Path}", path);
}
}
@@ -219,7 +211,7 @@ namespace MediaBrowser.LocalMetadata.Savers
if (item.CriticRating.HasValue)
{
writer.WriteElementString("CriticRating", item.CriticRating.Value.ToString(_usCulture));
writer.WriteElementString("CriticRating", item.CriticRating.Value.ToString(CultureInfo.InvariantCulture));
}
if (!string.IsNullOrEmpty(item.Overview))
@@ -237,7 +229,7 @@ namespace MediaBrowser.LocalMetadata.Savers
writer.WriteElementString("CustomRating", item.CustomRating);
}
if (!string.IsNullOrEmpty(item.Name) && !(item is Episode))
if (!string.IsNullOrEmpty(item.Name) && item is not Episode)
{
writer.WriteElementString("LocalTitle", item.Name);
}
@@ -254,7 +246,7 @@ namespace MediaBrowser.LocalMetadata.Savers
{
writer.WriteElementString("BirthDate", item.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
}
else if (!(item is Episode))
else if (item is not Episode)
{
writer.WriteElementString("PremiereDate", item.PremiereDate.Value.ToLocalTime().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
}
@@ -266,7 +258,7 @@ namespace MediaBrowser.LocalMetadata.Savers
{
writer.WriteElementString("DeathDate", item.EndDate.Value.ToLocalTime().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
}
else if (!(item is Episode))
else if (item is not Episode)
{
writer.WriteElementString("EndDate", item.EndDate.Value.ToLocalTime().ToString("yyyy-MM-dd", CultureInfo.InvariantCulture));
}
@@ -303,12 +295,12 @@ namespace MediaBrowser.LocalMetadata.Savers
if (item.CommunityRating.HasValue)
{
writer.WriteElementString("Rating", item.CommunityRating.Value.ToString(_usCulture));
writer.WriteElementString("Rating", item.CommunityRating.Value.ToString(CultureInfo.InvariantCulture));
}
if (item.ProductionYear.HasValue && !(item is Person))
if (item.ProductionYear.HasValue && item is not Person)
{
writer.WriteElementString("ProductionYear", item.ProductionYear.Value.ToString(_usCulture));
writer.WriteElementString("ProductionYear", item.ProductionYear.Value.ToString(CultureInfo.InvariantCulture));
}
if (item is IHasAspectRatio hasAspectRatio)
@@ -334,9 +326,9 @@ namespace MediaBrowser.LocalMetadata.Savers
if (runTimeTicks.HasValue)
{
var timespan = TimeSpan.FromTicks(runTimeTicks!.Value);
var timespan = TimeSpan.FromTicks(runTimeTicks.Value);
writer.WriteElementString("RunningTime", Math.Floor(timespan.TotalMinutes).ToString(_usCulture));
writer.WriteElementString("RunningTime", Math.Floor(timespan.TotalMinutes).ToString(CultureInfo.InvariantCulture));
}
if (item.ProviderIds != null)
@@ -409,7 +401,7 @@ namespace MediaBrowser.LocalMetadata.Savers
if (person.SortOrder.HasValue)
{
writer.WriteElementString("SortOrder", person.SortOrder.Value.ToString(_usCulture));
writer.WriteElementString("SortOrder", person.SortOrder.Value.ToString(CultureInfo.InvariantCulture));
}
writer.WriteEndElement();

View File

@@ -20,11 +20,9 @@ namespace MediaBrowser.LocalMetadata.Savers
/// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
/// <param name="configurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
/// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
/// <param name="logger">Instance of the <see cref="ILogger{BoxSetXmlSaver}"/> interface.</param>
public BoxSetXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger<BoxSetXmlSaver> logger)
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
public BoxSetXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ILogger<BoxSetXmlSaver> logger)
: base(fileSystem, configurationManager, libraryManager, logger)
{
}

View File

@@ -25,11 +25,9 @@ namespace MediaBrowser.LocalMetadata.Savers
/// <param name="fileSystem">Instance of the <see cref="IFileSystem"/> interface.</param>
/// <param name="configurationManager">Instance of the <see cref="IServerConfigurationManager"/> interface.</param>
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
/// <param name="userDataManager">Instance of the <see cref="IUserDataManager"/> interface.</param>
/// <param name="logger">Instance of the <see cref="ILogger{PlaylistXmlSaver}"/> interface.</param>
public PlaylistXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger<PlaylistXmlSaver> logger)
: base(fileSystem, configurationManager, libraryManager, userManager, userDataManager, logger)
public PlaylistXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, ILogger<PlaylistXmlSaver> logger)
: base(fileSystem, configurationManager, libraryManager, logger)
{
}