Merge pull request #10366 from goremykin/fix-resharper-warnings

pull/10427/head
Bond-009 8 months ago committed by GitHub
commit 84bbf757fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -927,14 +927,11 @@ namespace Emby.Dlna.PlayTo
var resElement = container.Element(UPnpNamespaces.Res); var resElement = container.Element(UPnpNamespaces.Res);
if (resElement is not null) var info = resElement?.Attribute(UPnpNamespaces.ProtocolInfo);
{
var info = resElement.Attribute(UPnpNamespaces.ProtocolInfo);
if (info is not null && !string.IsNullOrWhiteSpace(info.Value)) if (info is not null && !string.IsNullOrWhiteSpace(info.Value))
{ {
return info.Value.Split(':'); return info.Value.Split(':');
}
} }
return new string[4]; return new string[4];
@ -1139,7 +1136,6 @@ namespace Emby.Dlna.PlayTo
return new Device(deviceProperties, httpClientFactory, logger); return new Device(deviceProperties, httpClientFactory, logger);
} }
#nullable enable
private static DeviceIcon CreateIcon(XElement element) private static DeviceIcon CreateIcon(XElement element)
{ {
ArgumentNullException.ThrowIfNull(element); ArgumentNullException.ThrowIfNull(element);

@ -39,9 +39,9 @@ namespace Emby.Dlna.PlayTo
private readonly IMediaSourceManager _mediaSourceManager; private readonly IMediaSourceManager _mediaSourceManager;
private readonly IMediaEncoder _mediaEncoder; private readonly IMediaEncoder _mediaEncoder;
private readonly SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1);
private readonly CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
private bool _disposed; private bool _disposed;
private SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1);
private CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClientFactory httpClientFactory, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder) public PlayToManager(ILogger logger, ISessionManager sessionManager, ILibraryManager libraryManager, IUserManager userManager, IDlnaManager dlnaManager, IServerApplicationHost appHost, IImageProcessor imageProcessor, IDeviceDiscovery deviceDiscovery, IHttpClientFactory httpClientFactory, IUserDataManager userDataManager, ILocalizationManager localization, IMediaSourceManager mediaSourceManager, IMediaEncoder mediaEncoder)
{ {

@ -318,7 +318,7 @@ namespace Emby.Naming.Common
new EpisodeExpression(@"[\._ -]()[Ee][Pp]_?([0-9]+)([^\\/]*)$"), new EpisodeExpression(@"[\._ -]()[Ee][Pp]_?([0-9]+)([^\\/]*)$"),
// <!-- foo.E01., foo.e01. --> // <!-- foo.E01., foo.e01. -->
new EpisodeExpression(@"[^\\/]*?()\.?[Ee]([0-9]+)\.([^\\/]*)$"), new EpisodeExpression(@"[^\\/]*?()\.?[Ee]([0-9]+)\.([^\\/]*)$"),
new EpisodeExpression(@"(?<year>[0-9]{4})[._ -](?<month>[0-9]{2})[._ -](?<day>[0-9]{2})", true) new EpisodeExpression("(?<year>[0-9]{4})[._ -](?<month>[0-9]{2})[._ -](?<day>[0-9]{2})", true)
{ {
DateTimeFormats = new[] DateTimeFormats = new[]
{ {
@ -328,7 +328,7 @@ namespace Emby.Naming.Common
"yyyy MM dd" "yyyy MM dd"
} }
}, },
new EpisodeExpression(@"(?<day>[0-9]{2})[._ -](?<month>[0-9]{2})[._ -](?<year>[0-9]{4})", true) new EpisodeExpression("(?<day>[0-9]{2})[._ -](?<month>[0-9]{2})[._ -](?<year>[0-9]{4})", true)
{ {
DateTimeFormats = new[] DateTimeFormats = new[]
{ {
@ -376,7 +376,7 @@ namespace Emby.Naming.Common
IsNamed = true, IsNamed = true,
SupportsAbsoluteEpisodeNumbers = false SupportsAbsoluteEpisodeNumbers = false
}, },
new EpisodeExpression("[\\/._ -]p(?:ar)?t[_. -]()([ivx]+|[0-9]+)([._ -][^\\/]*)$") new EpisodeExpression(@"[\/._ -]p(?:ar)?t[_. -]()([ivx]+|[0-9]+)([._ -][^\/]*)$")
{ {
SupportsAbsoluteEpisodeNumbers = true SupportsAbsoluteEpisodeNumbers = true
}, },
@ -417,7 +417,7 @@ namespace Emby.Naming.Common
}, },
// "1-12 episode title" // "1-12 episode title"
new EpisodeExpression(@"([0-9]+)-([0-9]+)"), new EpisodeExpression("([0-9]+)-([0-9]+)"),
// "01 - blah.avi", "01-blah.avi" // "01 - blah.avi", "01-blah.avi"
new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\s?-\s?[^\\\/]*$") new EpisodeExpression(@".*(\\|\/)(?<epnumber>[0-9]{1,3})(-(?<endingepnumber>[0-9]{2,3}))*\s?-\s?[^\\\/]*$")
@ -712,7 +712,7 @@ namespace Emby.Naming.Common
// Chapter is often beginning of filename // Chapter is often beginning of filename
"^(?<chapter>[0-9]+)", "^(?<chapter>[0-9]+)",
// Part if often ending of filename // Part if often ending of filename
@"(?<!ch(?:apter) )(?<part>[0-9]+)$", "(?<!ch(?:apter) )(?<part>[0-9]+)$",
// Sometimes named as 0001_005 (chapter_part) // Sometimes named as 0001_005 (chapter_part)
"(?<chapter>[0-9]+)_(?<part>[0-9]+)", "(?<chapter>[0-9]+)_(?<part>[0-9]+)",
// Some audiobooks are ripped from cd's, and will be named by disk number. // Some audiobooks are ripped from cd's, and will be named by disk number.

@ -10,8 +10,6 @@ namespace Emby.Server.Implementations.AppBase
/// </summary> /// </summary>
public abstract class BaseApplicationPaths : IApplicationPaths public abstract class BaseApplicationPaths : IApplicationPaths
{ {
private string _dataPath;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BaseApplicationPaths"/> class. /// Initializes a new instance of the <see cref="BaseApplicationPaths"/> class.
/// </summary> /// </summary>
@ -33,7 +31,7 @@ namespace Emby.Server.Implementations.AppBase
CachePath = cacheDirectoryPath; CachePath = cacheDirectoryPath;
WebPath = webDirectoryPath; WebPath = webDirectoryPath;
_dataPath = Directory.CreateDirectory(Path.Combine(ProgramDataPath, "data")).FullName; DataPath = Directory.CreateDirectory(Path.Combine(ProgramDataPath, "data")).FullName;
} }
/// <summary> /// <summary>
@ -55,7 +53,7 @@ namespace Emby.Server.Implementations.AppBase
/// Gets the folder path to the data directory. /// Gets the folder path to the data directory.
/// </summary> /// </summary>
/// <value>The data directory.</value> /// <value>The data directory.</value>
public string DataPath => _dataPath; public string DataPath { get; }
/// <inheritdoc /> /// <inheritdoc />
public string VirtualDataPath => "%AppDataPath%"; public string VirtualDataPath => "%AppDataPath%";

@ -1159,7 +1159,7 @@ namespace Emby.Server.Implementations.Channels
if (info.People is not null && info.People.Count > 0) if (info.People is not null && info.People.Count > 0)
{ {
_libraryManager.UpdatePeople(item, info.People); await _libraryManager.UpdatePeopleAsync(item, info.People, cancellationToken).ConfigureAwait(false);
} }
} }
else if (forceUpdate) else if (forceUpdate)

@ -3540,10 +3540,7 @@ namespace Emby.Server.Implementations.Data
.Append(paramName) .Append(paramName)
.Append("))) OR "); .Append("))) OR ");
if (statement is not null) statement?.TryBind(paramName, query.PersonIds[i]);
{
statement.TryBind(paramName, query.PersonIds[i]);
}
} }
clauseBuilder.Length -= Or.Length; clauseBuilder.Length -= Or.Length;
@ -4382,7 +4379,7 @@ namespace Emby.Server.Implementations.Data
foreach (var videoType in query.VideoTypes) foreach (var videoType in query.VideoTypes)
{ {
videoTypes.Add("data like '%\"VideoType\":\"" + videoType.ToString() + "\"%'"); videoTypes.Add("data like '%\"VideoType\":\"" + videoType + "\"%'");
} }
whereClauses.Add("(" + string.Join(" OR ", videoTypes) + ")"); whereClauses.Add("(" + string.Join(" OR ", videoTypes) + ")");

@ -39,9 +39,9 @@ namespace Emby.Server.Implementations.EntryPoints
/// <summary> /// <summary>
/// The UDP server. /// The UDP server.
/// </summary> /// </summary>
private List<UdpServer> _udpServers; private readonly List<UdpServer> _udpServers;
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private bool _disposed = false; private bool _disposed;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="UdpServerEntryPoint" /> class. /// Initializes a new instance of the <see cref="UdpServerEntryPoint" /> class.

@ -12,7 +12,6 @@ using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Net.WebSocketMessages; using MediaBrowser.Controller.Net.WebSocketMessages;
using MediaBrowser.Controller.Net.WebSocketMessages.Outbound; using MediaBrowser.Controller.Net.WebSocketMessages.Outbound;
using MediaBrowser.Model.Session; using MediaBrowser.Model.Session;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.HttpServer namespace Emby.Server.Implementations.HttpServer

@ -210,7 +210,6 @@ namespace Emby.Server.Implementations.IO
DisposeTimer(); DisposeTimer();
_disposed = true; _disposed = true;
GC.SuppressFinalize(this);
} }
} }
} }

@ -91,7 +91,7 @@ namespace Emby.Server.Implementations.IO
} }
// unc path // unc path
if (filePath.StartsWith("\\\\", StringComparison.Ordinal)) if (filePath.StartsWith(@"\\", StringComparison.Ordinal))
{ {
return filePath; return filePath;
} }

@ -2850,7 +2850,7 @@ namespace Emby.Server.Implementations.Library
{ {
var path = Path.Combine(virtualFolderPath, collectionType.ToString().ToLowerInvariant() + ".collection"); var path = Path.Combine(virtualFolderPath, collectionType.ToString().ToLowerInvariant() + ".collection");
File.WriteAllBytes(path, Array.Empty<byte>()); await File.WriteAllBytesAsync(path, Array.Empty<byte>()).ConfigureAwait(false);
} }
CollectionFolder.SaveLibraryOptions(virtualFolderPath, options); CollectionFolder.SaveLibraryOptions(virtualFolderPath, options);

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using Emby.Naming.Common; using Emby.Naming.Common;

@ -62,7 +62,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
var resolver = new Naming.TV.EpisodeResolver(namingOptions); var resolver = new Naming.TV.EpisodeResolver(namingOptions);
var folderName = System.IO.Path.GetFileName(path); var folderName = System.IO.Path.GetFileName(path);
var testPath = "\\\\test\\" + folderName; var testPath = @"\\test\" + folderName;
var episodeInfo = resolver.Resolve(testPath, true); var episodeInfo = resolver.Resolve(testPath, true);

@ -17,7 +17,6 @@ using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Model.Dto; using MediaBrowser.Model.Dto;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.LiveTv;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.TunerHosts namespace Emby.Server.Implementations.LiveTv.TunerHosts

@ -28,7 +28,6 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
using MediaBrowser.Model.Net; using MediaBrowser.Model.Net;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun

@ -44,8 +44,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
StopStreaming(socket).GetAwaiter().GetResult(); StopStreaming(socket).GetAwaiter().GetResult();
} }
} }
GC.SuppressFinalize(this);
} }
public async Task<bool> CheckTunerAvailability(IPAddress remoteIP, int tuner, CancellationToken cancellationToken) public async Task<bool> CheckTunerAvailability(IPAddress remoteIP, int tuner, CancellationToken cancellationToken)

@ -5,7 +5,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Threading; using System.Threading;
@ -22,7 +21,6 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.LiveTv;
using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.MediaInfo;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;

@ -32,7 +32,7 @@ namespace Emby.Server.Implementations.Net
} }
catch catch
{ {
socket?.Dispose(); socket.Dispose();
throw; throw;
} }
@ -59,7 +59,7 @@ namespace Emby.Server.Implementations.Net
} }
catch catch
{ {
socket?.Dispose(); socket.Dispose();
throw; throw;
} }
@ -110,7 +110,7 @@ namespace Emby.Server.Implementations.Net
} }
catch catch
{ {
socket?.Dispose(); socket.Dispose();
throw; throw;
} }

@ -115,7 +115,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
{ {
try try
{ {
previouslyFailedImages = File.ReadAllText(failHistoryPath) previouslyFailedImages = (await File.ReadAllTextAsync(failHistoryPath, cancellationToken).ConfigureAwait(false))
.Split('|', StringSplitOptions.RemoveEmptyEntries) .Split('|', StringSplitOptions.RemoveEmptyEntries)
.ToList(); .ToList();
} }
@ -156,7 +156,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
} }
string text = string.Join('|', previouslyFailedImages); string text = string.Join('|', previouslyFailedImages);
File.WriteAllText(failHistoryPath, text); await File.WriteAllTextAsync(failHistoryPath, text, cancellationToken).ConfigureAwait(false);
} }
numComplete++; numComplete++;

@ -27,9 +27,9 @@ namespace Emby.Server.Implementations.Udp
private readonly byte[] _receiveBuffer = new byte[8192]; private readonly byte[] _receiveBuffer = new byte[8192];
private Socket _udpSocket; private readonly Socket _udpSocket;
private IPEndPoint _endpoint; private readonly IPEndPoint _endpoint;
private bool _disposed = false; private bool _disposed;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="UdpServer" /> class. /// Initializes a new instance of the <see cref="UdpServer" /> class.
@ -130,9 +130,8 @@ namespace Emby.Server.Implementations.Udp
return; return;
} }
_udpSocket?.Dispose(); _udpSocket.Dispose();
_disposed = true;
GC.SuppressFinalize(this);
} }
} }
} }

@ -294,8 +294,8 @@ public class LibraryController : BaseJellyfinApiController
return new AllThemeMediaResult return new AllThemeMediaResult
{ {
ThemeSongsResult = themeSongs?.Value, ThemeSongsResult = themeSongs.Value,
ThemeVideosResult = themeVideos?.Value, ThemeVideosResult = themeVideos.Value,
SoundtrackSongsResult = new ThemeMediaResult() SoundtrackSongsResult = new ThemeMediaResult()
}; };
} }
@ -490,7 +490,7 @@ public class LibraryController : BaseJellyfinApiController
baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, dtoOptions, user)); baseItemDtos.Add(_dtoService.GetBaseItemDto(parent, dtoOptions, user));
parent = parent?.GetParent(); parent = parent.GetParent();
} }
return baseItemDtos; return baseItemDtos;

@ -122,17 +122,17 @@ public class ExceptionMiddleware
private static int GetStatusCode(Exception ex) private static int GetStatusCode(Exception ex)
{ {
switch (ex) return ex switch
{ {
case ArgumentException _: return StatusCodes.Status400BadRequest; ArgumentException => StatusCodes.Status400BadRequest,
case AuthenticationException _: return StatusCodes.Status401Unauthorized; AuthenticationException => StatusCodes.Status401Unauthorized,
case SecurityException _: return StatusCodes.Status403Forbidden; SecurityException => StatusCodes.Status403Forbidden,
case DirectoryNotFoundException _: DirectoryNotFoundException => StatusCodes.Status404NotFound,
case FileNotFoundException _: FileNotFoundException => StatusCodes.Status404NotFound,
case ResourceNotFoundException _: return StatusCodes.Status404NotFound; ResourceNotFoundException => StatusCodes.Status404NotFound,
case MethodNotAllowedException _: return StatusCodes.Status405MethodNotAllowed; MethodNotAllowedException => StatusCodes.Status405MethodNotAllowed,
default: return StatusCodes.Status500InternalServerError; _ => StatusCodes.Status500InternalServerError
} };
} }
private string NormalizeExceptionMessage(string msg) private string NormalizeExceptionMessage(string msg)

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -204,7 +203,7 @@ public static partial class NetworkExtensions
{ {
var ipBlock = splitString.Current; var ipBlock = splitString.Current;
var address = IPAddress.None; var address = IPAddress.None;
if (negated && ipBlock.StartsWith<char>("!") && IPAddress.TryParse(ipBlock[1..], out var tmpAddress)) if (negated && ipBlock.StartsWith("!") && IPAddress.TryParse(ipBlock[1..], out var tmpAddress))
{ {
address = tmpAddress; address = tmpAddress;
} }

@ -1,7 +1,6 @@
using System.Globalization; using System.Globalization;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
using Jellyfin.Data.Events;
using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events;
using MediaBrowser.Controller.Events.Authentication; using MediaBrowser.Controller.Events.Authentication;
using MediaBrowser.Model.Activity; using MediaBrowser.Model.Activity;

@ -1,5 +1,4 @@
using Jellyfin.Data.Events; using Jellyfin.Data.Events.System;
using Jellyfin.Data.Events.System;
using Jellyfin.Data.Events.Users; using Jellyfin.Data.Events.Users;
using Jellyfin.Server.Implementations.Events.Consumers.Library; using Jellyfin.Server.Implementations.Events.Consumers.Library;
using Jellyfin.Server.Implementations.Events.Consumers.Security; using Jellyfin.Server.Implementations.Events.Consumers.Security;

@ -108,7 +108,7 @@ namespace Jellyfin.Server.Implementations.Users
// This is some regex that matches only on unicode "word" characters, as well as -, _ and @ // 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 // 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 ( ) // Usernames can contain letters (a-z + whatever else unicode is cool with), numbers (0-9), at-signs (@), dashes (-), underscores (_), apostrophes ('), periods (.) and spaces ( )
[GeneratedRegex("^[\\w\\ \\-'._@]+$")] [GeneratedRegex(@"^[\w\ \-'._@]+$")]
private static partial Regex ValidUsernameRegex(); private static partial Regex ValidUsernameRegex();
/// <inheritdoc/> /// <inheritdoc/>

@ -3,7 +3,6 @@ using System.Globalization;
using System.IO; using System.IO;
using Emby.Server.Implementations.Data; using Emby.Server.Implementations.Data;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Globalization;
using Microsoft.Data.Sqlite; using Microsoft.Data.Sqlite;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;

@ -1,5 +1,4 @@
using System; using System;
using System.Linq;
using Jellyfin.Extensions; using Jellyfin.Extensions;
using MediaBrowser.Controller.Channels; using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;

@ -1,4 +1,3 @@
using System.Threading;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;

@ -95,10 +95,7 @@ namespace MediaBrowser.Controller.Entities
} }
var p = destProps.Find(x => x.Name == sourceProp.Name); var p = destProps.Find(x => x.Name == sourceProp.Name);
if (p is not null) p?.SetValue(dest, v);
{
p.SetValue(dest, v);
}
} }
} }

@ -598,7 +598,7 @@ namespace MediaBrowser.Controller.Entities
for (var i = 0; i < childrenCount; i++) for (var i = 0; i < childrenCount; i++)
{ {
await actionBlock.SendAsync(i).ConfigureAwait(false); await actionBlock.SendAsync(i, cancellationToken).ConfigureAwait(false);
} }
actionBlock.Complete(); actionBlock.Complete();

@ -20,7 +20,7 @@ namespace MediaBrowser.Controller.LiveTv
{ {
public class LiveTvProgram : BaseItem, IHasLookupInfo<ItemLookupInfo>, IHasStartDate, IHasProgramAttributes public class LiveTvProgram : BaseItem, IHasLookupInfo<ItemLookupInfo>, IHasStartDate, IHasProgramAttributes
{ {
private static string EmbyServiceName = "Emby"; private const string EmbyServiceName = "Emby";
public LiveTvProgram() public LiveTvProgram()
{ {

@ -1745,11 +1745,9 @@ namespace MediaBrowser.Controller.MediaEncoding
// Values 0-3, 0 being highest quality but slower // Values 0-3, 0 being highest quality but slower
var profileScore = 0; var profileScore = 0;
string crf;
var qmin = "0"; var qmin = "0";
var qmax = "50"; var qmax = "50";
var crf = "10";
crf = "10";
if (isVc1) if (isVc1)
{ {
@ -2947,7 +2945,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return string.Format( return string.Format(
CultureInfo.InvariantCulture, CultureInfo.InvariantCulture,
"scale=trunc(min(max(iw\\,ih*a)\\,min({0}\\,{1}*a))/{2})*{2}:trunc(min(max(iw/a\\,ih)\\,min({0}/a\\,{1}))/2)*2", @"scale=trunc(min(max(iw\,ih*a)\,min({0}\,{1}*a))/{2})*{2}:trunc(min(max(iw/a\,ih)\,min({0}/a\,{1}))/2)*2",
maxWidthParam, maxWidthParam,
maxHeightParam, maxHeightParam,
scaleVal); scaleVal);
@ -2989,7 +2987,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return string.Format( return string.Format(
CultureInfo.InvariantCulture, CultureInfo.InvariantCulture,
"scale=trunc(min(max(iw\\,ih*a)\\,{0})/{1})*{1}:trunc(ow/a/2)*2", @"scale=trunc(min(max(iw\,ih*a)\,{0})/{1})*{1}:trunc(ow/a/2)*2",
maxWidthParam, maxWidthParam,
scaleVal); scaleVal);
} }
@ -3001,7 +2999,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return string.Format( return string.Format(
CultureInfo.InvariantCulture, CultureInfo.InvariantCulture,
"scale=trunc(oh*a/{1})*{1}:min(max(iw/a\\,ih)\\,{0})", @"scale=trunc(oh*a/{1})*{1}:min(max(iw/a\,ih)\,{0})",
maxHeightParam, maxHeightParam,
scaleVal); scaleVal);
} }
@ -3021,19 +3019,19 @@ namespace MediaBrowser.Controller.MediaEncoding
switch (threedFormat.Value) switch (threedFormat.Value)
{ {
case Video3DFormat.HalfSideBySide: case Video3DFormat.HalfSideBySide:
filter = "crop=iw/2:ih:0:0,scale=(iw*2):ih,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale={0}:trunc({0}/dar/2)*2"; filter = @"crop=iw/2:ih:0:0,scale=(iw*2):ih,setdar=dar=a,crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,setsar=sar=1,scale={0}:trunc({0}/dar/2)*2";
// hsbs crop width in half,scale to correct size, set the display aspect,crop out any black bars we may have made the scale width to requestedWidth. Work out the correct height based on the display aspect it will maintain the aspect where -1 in this case (3d) may not. // hsbs crop width in half,scale to correct size, set the display aspect,crop out any black bars we may have made the scale width to requestedWidth. Work out the correct height based on the display aspect it will maintain the aspect where -1 in this case (3d) may not.
break; break;
case Video3DFormat.FullSideBySide: case Video3DFormat.FullSideBySide:
filter = "crop=iw/2:ih:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale={0}:trunc({0}/dar/2)*2"; filter = @"crop=iw/2:ih:0:0,setdar=dar=a,crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,setsar=sar=1,scale={0}:trunc({0}/dar/2)*2";
// fsbs crop width in half,set the display aspect,crop out any black bars we may have made the scale width to requestedWidth. // fsbs crop width in half,set the display aspect,crop out any black bars we may have made the scale width to requestedWidth.
break; break;
case Video3DFormat.HalfTopAndBottom: case Video3DFormat.HalfTopAndBottom:
filter = "crop=iw:ih/2:0:0,scale=(iw*2):ih),setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale={0}:trunc({0}/dar/2)*2"; filter = @"crop=iw:ih/2:0:0,scale=(iw*2):ih),setdar=dar=a,crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,setsar=sar=1,scale={0}:trunc({0}/dar/2)*2";
// htab crop height in half,scale to correct size, set the display aspect,crop out any black bars we may have made the scale width to requestedWidth // htab crop height in half,scale to correct size, set the display aspect,crop out any black bars we may have made the scale width to requestedWidth
break; break;
case Video3DFormat.FullTopAndBottom: case Video3DFormat.FullTopAndBottom:
filter = "crop=iw:ih/2:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1,scale={0}:trunc({0}/dar/2)*2"; filter = @"crop=iw:ih/2:0:0,setdar=dar=a,crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,setsar=sar=1,scale={0}:trunc({0}/dar/2)*2";
// ftab crop height in half, set the display aspect,crop out any black bars we may have made the scale width to requestedWidth // ftab crop height in half, set the display aspect,crop out any black bars we may have made the scale width to requestedWidth
break; break;
default: default:

@ -34,7 +34,7 @@ namespace MediaBrowser.Controller.Net
/// <summary> /// <summary>
/// The logger. /// The logger.
/// </summary> /// </summary>
protected ILogger<BasePeriodicWebSocketListener<TReturnDataType, TStateType>> Logger; protected readonly ILogger<BasePeriodicWebSocketListener<TReturnDataType, TStateType>> Logger;
protected BasePeriodicWebSocketListener(ILogger<BasePeriodicWebSocketListener<TReturnDataType, TStateType>> logger) protected BasePeriodicWebSocketListener(ILogger<BasePeriodicWebSocketListener<TReturnDataType, TStateType>> logger)
{ {

@ -5,7 +5,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net.Http;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Data.Events; using Jellyfin.Data.Events;

@ -8,7 +8,7 @@ namespace MediaBrowser.MediaEncoding.BdInfo;
/// </summary> /// </summary>
public class BdInfoFileInfo : BDInfo.IO.IFileInfo public class BdInfoFileInfo : BDInfo.IO.IFileInfo
{ {
private FileSystemMetadata _impl; private readonly FileSystemMetadata _impl;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BdInfoFileInfo" /> class. /// Initializes a new instance of the <see cref="BdInfoFileInfo" /> class.

@ -499,8 +499,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
var required = codec == Codec.Encoder ? _requiredEncoders : _requiredDecoders; var required = codec == Codec.Encoder ? _requiredEncoders : _requiredDecoders;
var found = Regex var found = CodecRegex()
.Matches(output, @"^\s\S{6}\s(?<codec>[\w|-]+)\s+.+$", RegexOptions.Multiline) .Matches(output)
.Select(x => x.Groups["codec"].Value) .Select(x => x.Groups["codec"].Value)
.Where(x => required.Contains(x)); .Where(x => required.Contains(x));
@ -527,8 +527,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
return Enumerable.Empty<string>(); return Enumerable.Empty<string>();
} }
var found = Regex var found = FilterRegex()
.Matches(output, @"^\s\S{3}\s(?<filter>[\w|-]+)\s+.+$", RegexOptions.Multiline) .Matches(output)
.Select(x => x.Groups["filter"].Value) .Select(x => x.Groups["filter"].Value)
.Where(x => _requiredFilters.Contains(x)); .Where(x => _requiredFilters.Contains(x));
@ -582,5 +582,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
return reader.ReadToEnd(); return reader.ReadToEnd();
} }
} }
[GeneratedRegex("^\\s\\S{6}\\s(?<codec>[\\w|-]+)\\s+.+$", RegexOptions.Multiline)]
private static partial Regex CodecRegex();
[GeneratedRegex("^\\s\\S{3}\\s(?<filter>[\\w|-]+)\\s+.+$", RegexOptions.Multiline)]
private static partial Regex FilterRegex();
} }
} }

@ -177,7 +177,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (_ffmpegPath is not null) if (_ffmpegPath is not null)
{ {
// Determine a probe path from the mpeg path // Determine a probe path from the mpeg path
_ffprobePath = FfprobePathRegex().Replace(_ffmpegPath, @"ffprobe$1"); _ffprobePath = FfprobePathRegex().Replace(_ffmpegPath, "ffprobe$1");
// Interrogate to understand what coders are supported // Interrogate to understand what coders are supported
var validator = new EncoderValidator(_logger, _ffmpegPath); var validator = new EncoderValidator(_logger, _ffmpegPath);
@ -422,7 +422,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (request.MediaSource.AnalyzeDurationMs > 0) if (request.MediaSource.AnalyzeDurationMs > 0)
{ {
analyzeDuration = "-analyzeduration " + (request.MediaSource.AnalyzeDurationMs * 1000).ToString(); analyzeDuration = "-analyzeduration " + (request.MediaSource.AnalyzeDurationMs * 1000);
} }
else if (!string.IsNullOrEmpty(ffmpegAnalyzeDuration)) else if (!string.IsNullOrEmpty(ffmpegAnalyzeDuration))
{ {
@ -623,9 +623,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
private string GetImageResolutionParameter() private string GetImageResolutionParameter()
{ {
string imageResolutionParameter; var imageResolutionParameter = _serverConfig.Configuration.ChapterImageResolution switch
imageResolutionParameter = _serverConfig.Configuration.ChapterImageResolution switch
{ {
ImageResolution.P144 => "256x144", ImageResolution.P144 => "256x144",
ImageResolution.P240 => "426x240", ImageResolution.P240 => "426x240",
@ -670,13 +668,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
var scaler = threedFormat switch var scaler = threedFormat switch
{ {
// hsbs crop width in half,scale to correct size, set the display aspect,crop out any black bars we may have made. Work out the correct height based on the display aspect it will maintain the aspect where -1 in this case (3d) may not. // hsbs crop width in half,scale to correct size, set the display aspect,crop out any black bars we may have made. Work out the correct height based on the display aspect it will maintain the aspect where -1 in this case (3d) may not.
Video3DFormat.HalfSideBySide => "crop=iw/2:ih:0:0,scale=(iw*2):ih,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1", Video3DFormat.HalfSideBySide => @"crop=iw/2:ih:0:0,scale=(iw*2):ih,setdar=dar=a,crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,setsar=sar=1",
// fsbs crop width in half,set the display aspect,crop out any black bars we may have made // fsbs crop width in half,set the display aspect,crop out any black bars we may have made
Video3DFormat.FullSideBySide => "crop=iw/2:ih:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1", Video3DFormat.FullSideBySide => @"crop=iw/2:ih:0:0,setdar=dar=a,crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,setsar=sar=1",
// htab crop height in half,scale to correct size, set the display aspect,crop out any black bars we may have made // htab crop height in half,scale to correct size, set the display aspect,crop out any black bars we may have made
Video3DFormat.HalfTopAndBottom => "crop=iw:ih/2:0:0,scale=(iw*2):ih),setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1", Video3DFormat.HalfTopAndBottom => @"crop=iw:ih/2:0:0,scale=(iw*2):ih),setdar=dar=a,crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,setsar=sar=1",
// ftab crop height in half, set the display aspect,crop out any black bars we may have made // ftab crop height in half, set the display aspect,crop out any black bars we may have made
Video3DFormat.FullTopAndBottom => "crop=iw:ih/2:0:0,setdar=dar=a,crop=min(iw\\,ih*dar):min(ih\\,iw/dar):(iw-min(iw\\,iw*sar))/2:(ih - min (ih\\,ih/sar))/2,setsar=sar=1", Video3DFormat.FullTopAndBottom => @"crop=iw:ih/2:0:0,setdar=dar=a,crop=min(iw\,ih*dar):min(ih\,iw/dar):(iw-min(iw\,iw*sar))/2:(ih - min (ih\,ih/sar))/2,setsar=sar=1",
_ => "scale=trunc(iw*sar):ih" _ => "scale=trunc(iw*sar):ih"
}; };
@ -852,7 +850,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
// https://ffmpeg.org/ffmpeg-filters.html#Notes-on-filtergraph-escaping // https://ffmpeg.org/ffmpeg-filters.html#Notes-on-filtergraph-escaping
// We need to double escape // We need to double escape
return path.Replace('\\', '/').Replace(":", "\\:", StringComparison.Ordinal).Replace("'", "'\\\\\\''", StringComparison.Ordinal); return path.Replace('\\', '/').Replace(":", "\\:", StringComparison.Ordinal).Replace("'", @"'\\\''", StringComparison.Ordinal);
} }
/// <inheritdoc /> /// <inheritdoc />

@ -22,7 +22,7 @@ namespace MediaBrowser.MediaEncoding.Probing
/// <summary> /// <summary>
/// Class responsible for normalizing FFprobe output. /// Class responsible for normalizing FFprobe output.
/// </summary> /// </summary>
public class ProbeResultNormalizer public partial class ProbeResultNormalizer
{ {
// When extracting subtitles, the maximum length to consider (to avoid invalid filenames) // When extracting subtitles, the maximum length to consider (to avoid invalid filenames)
private const int MaxSubtitleDescriptionExtractionLength = 100; private const int MaxSubtitleDescriptionExtractionLength = 100;
@ -31,8 +31,6 @@ namespace MediaBrowser.MediaEncoding.Probing
private readonly char[] _nameDelimiters = { '/', '|', ';', '\\' }; private readonly char[] _nameDelimiters = { '/', '|', ';', '\\' };
private static readonly Regex _performerPattern = new(@"(?<name>.*) \((?<instrument>.*)\)");
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly ILocalizationManager _localization; private readonly ILocalizationManager _localization;
@ -1215,7 +1213,7 @@ namespace MediaBrowser.MediaEncoding.Probing
{ {
foreach (var person in Split(performer, false)) foreach (var person in Split(performer, false))
{ {
Match match = _performerPattern.Match(person); Match match = PerformerRegex().Match(person);
// If the performer doesn't have any instrument/role associated, it won't match. In that case, chances are it's simply a band name, so we skip it. // If the performer doesn't have any instrument/role associated, it won't match. In that case, chances are it's simply a band name, so we skip it.
if (match.Success) if (match.Success)
@ -1654,5 +1652,8 @@ namespace MediaBrowser.MediaEncoding.Probing
return TransportStreamTimestamp.Valid; return TransportStreamTimestamp.Valid;
} }
[GeneratedRegex("(?<name>.*) \\((?<instrument>.*)\\)")]
private static partial Regex PerformerRegex();
} }
} }

@ -1313,7 +1313,7 @@ namespace MediaBrowser.Model.Dlna
var audioFailureConditions = GetProfileConditionsForVideoAudio(profile.CodecProfiles, container, audioStream.Codec, audioStream.Channels, audioStream.BitRate, audioStream.SampleRate, audioStream.BitDepth, audioStream.Profile, mediaSource.IsSecondaryAudio(audioStream)); var audioFailureConditions = GetProfileConditionsForVideoAudio(profile.CodecProfiles, container, audioStream.Codec, audioStream.Channels, audioStream.BitRate, audioStream.SampleRate, audioStream.BitDepth, audioStream.Profile, mediaSource.IsSecondaryAudio(audioStream));
var audioStreamFailureReasons = AggregateFailureConditions(mediaSource, profile, "VideoAudioCodecProfile", audioFailureConditions); var audioStreamFailureReasons = AggregateFailureConditions(mediaSource, profile, "VideoAudioCodecProfile", audioFailureConditions);
if (audioStream?.IsExternal == true) if (audioStream.IsExternal == true)
{ {
audioStreamFailureReasons |= TranscodeReason.AudioIsExternal; audioStreamFailureReasons |= TranscodeReason.AudioIsExternal;
} }

@ -12,7 +12,6 @@ using Jellyfin.Extensions;
using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;

@ -58,7 +58,7 @@ namespace MediaBrowser.Providers.MediaInfo
_mediaSourceManager = mediaSourceManager; _mediaSourceManager = mediaSourceManager;
} }
[GeneratedRegex("I:\\s+(.*?)\\s+LUFS")] [GeneratedRegex(@"I:\s+(.*?)\s+LUFS")]
private static partial Regex LUFSRegex(); private static partial Regex LUFSRegex();
/// <summary> /// <summary>
@ -107,7 +107,6 @@ namespace MediaBrowser.Providers.MediaInfo
if (libraryOptions.EnableLUFSScan) if (libraryOptions.EnableLUFSScan)
{ {
string output;
using (var process = new Process() using (var process = new Process()
{ {
StartInfo = new ProcessStartInfo StartInfo = new ProcessStartInfo
@ -131,7 +130,7 @@ namespace MediaBrowser.Providers.MediaInfo
} }
using var reader = process.StandardError; using var reader = process.StandardError;
output = await reader.ReadToEndAsync(cancellationToken).ConfigureAwait(false); var output = await reader.ReadToEndAsync(cancellationToken).ConfigureAwait(false);
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
MatchCollection split = LUFSRegex().Matches(output); MatchCollection split = LUFSRegex().Matches(output);

@ -22,7 +22,7 @@ namespace MediaBrowser.Providers.Movies
public ExternalIdMediaType? Type => null; public ExternalIdMediaType? Type => null;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => "https://www.imdb.com/title/{0}"; public string UrlFormatString => "https://www.imdb.com/title/{0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) public bool Supports(IHasProviderIds item)

@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Movies
public ExternalIdMediaType? Type => ExternalIdMediaType.Person; public ExternalIdMediaType? Type => ExternalIdMediaType.Person;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => "https://www.imdb.com/name/{0}"; public string UrlFormatString => "https://www.imdb.com/name/{0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Person; public bool Supports(IHasProviderIds item) => item is Person;

@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
public ExternalIdMediaType? Type => null; public ExternalIdMediaType? Type => null;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => "https://www.theaudiodb.com/album/{0}"; public string UrlFormatString => "https://www.theaudiodb.com/album/{0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is MusicAlbum; public bool Supports(IHasProviderIds item) => item is MusicAlbum;

@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
public ExternalIdMediaType? Type => ExternalIdMediaType.Artist; public ExternalIdMediaType? Type => ExternalIdMediaType.Artist;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => "https://www.theaudiodb.com/artist/{0}"; public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is MusicArtist; public bool Supports(IHasProviderIds item) => item is MusicArtist;

@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
public ExternalIdMediaType? Type => ExternalIdMediaType.Album; public ExternalIdMediaType? Type => ExternalIdMediaType.Album;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => "https://www.theaudiodb.com/album/{0}"; public string UrlFormatString => "https://www.theaudiodb.com/album/{0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio; public bool Supports(IHasProviderIds item) => item is Audio;

@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.Plugins.AudioDb
public ExternalIdMediaType? Type => ExternalIdMediaType.OtherArtist; public ExternalIdMediaType? Type => ExternalIdMediaType.OtherArtist;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => "https://www.theaudiodb.com/artist/{0}"; public string UrlFormatString => "https://www.theaudiodb.com/artist/{0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio || item is MusicAlbum; public bool Supports(IHasProviderIds item) => item is Audio || item is MusicAlbum;

@ -20,7 +20,7 @@ public class MusicBrainzAlbumArtistExternalId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.AlbumArtist; public ExternalIdMediaType? Type => ExternalIdMediaType.AlbumArtist;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}"; public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio; public bool Supports(IHasProviderIds item) => item is Audio;

@ -20,7 +20,7 @@ public class MusicBrainzAlbumExternalId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.Album; public ExternalIdMediaType? Type => ExternalIdMediaType.Album;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => Plugin.Instance!.Configuration.Server + "/release/{0}"; public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/release/{0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio || item is MusicAlbum; public bool Supports(IHasProviderIds item) => item is Audio || item is MusicAlbum;

@ -20,7 +20,7 @@ public class MusicBrainzArtistExternalId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.Artist; public ExternalIdMediaType? Type => ExternalIdMediaType.Artist;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}"; public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is MusicArtist; public bool Supports(IHasProviderIds item) => item is MusicArtist;

@ -20,7 +20,7 @@ public class MusicBrainzOtherArtistExternalId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.OtherArtist; public ExternalIdMediaType? Type => ExternalIdMediaType.OtherArtist;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}"; public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/artist/{0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio or MusicAlbum; public bool Supports(IHasProviderIds item) => item is Audio or MusicAlbum;

@ -20,7 +20,7 @@ public class MusicBrainzReleaseGroupExternalId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.ReleaseGroup; public ExternalIdMediaType? Type => ExternalIdMediaType.ReleaseGroup;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => Plugin.Instance!.Configuration.Server + "/release-group/{0}"; public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/release-group/{0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio or MusicAlbum; public bool Supports(IHasProviderIds item) => item is Audio or MusicAlbum;

@ -20,7 +20,7 @@ public class MusicBrainzTrackId : IExternalId
public ExternalIdMediaType? Type => ExternalIdMediaType.Track; public ExternalIdMediaType? Type => ExternalIdMediaType.Track;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => Plugin.Instance!.Configuration.Server + "/track/{0}"; public string UrlFormatString => Plugin.Instance!.Configuration.Server + "/track/{0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Audio; public bool Supports(IHasProviderIds item) => item is Audio;

@ -21,7 +21,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.BoxSets
public ExternalIdMediaType? Type => ExternalIdMediaType.BoxSet; public ExternalIdMediaType? Type => ExternalIdMediaType.BoxSet;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => TmdbUtils.BaseTmdbUrl + "collection/{0}"; public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "collection/{0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) public bool Supports(IHasProviderIds item)

@ -21,7 +21,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.Movies
public ExternalIdMediaType? Type => ExternalIdMediaType.Movie; public ExternalIdMediaType? Type => ExternalIdMediaType.Movie;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => TmdbUtils.BaseTmdbUrl + "movie/{0}"; public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "movie/{0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) public bool Supports(IHasProviderIds item)

@ -20,7 +20,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.People
public ExternalIdMediaType? Type => ExternalIdMediaType.Person; public ExternalIdMediaType? Type => ExternalIdMediaType.Person;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => TmdbUtils.BaseTmdbUrl + "person/{0}"; public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "person/{0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) public bool Supports(IHasProviderIds item)

@ -20,7 +20,7 @@ namespace MediaBrowser.Providers.Plugins.Tmdb.TV
public ExternalIdMediaType? Type => ExternalIdMediaType.Series; public ExternalIdMediaType? Type => ExternalIdMediaType.Series;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => TmdbUtils.BaseTmdbUrl + "tv/{0}"; public string UrlFormatString => TmdbUtils.BaseTmdbUrl + "tv/{0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) public bool Supports(IHasProviderIds item)

@ -19,7 +19,7 @@ namespace MediaBrowser.Providers.TV
public ExternalIdMediaType? Type => null; public ExternalIdMediaType? Type => null;
/// <inheritdoc /> /// <inheritdoc />
public string? UrlFormatString => "http://tvlistings.zap2it.com/overview.html?programSeriesId={0}"; public string UrlFormatString => "http://tvlistings.zap2it.com/overview.html?programSeriesId={0}";
/// <inheritdoc /> /// <inheritdoc />
public bool Supports(IHasProviderIds item) => item is Series; public bool Supports(IHasProviderIds item) => item is Series;

@ -160,7 +160,7 @@ namespace MediaBrowser.XbmcMetadata.Parsers
// Find last closing Tag // Find last closing Tag
// Need to do this in two steps to account for random > characters after the closing xml // Need to do this in two steps to account for random > characters after the closing xml
var index = xml.LastIndexOf(@"</", StringComparison.Ordinal); var index = xml.LastIndexOf("</", StringComparison.Ordinal);
// If closing tag exists, move to end of Tag // If closing tag exists, move to end of Tag
if (index != -1) if (index != -1)

@ -13,7 +13,7 @@ namespace MediaBrowser.XbmcMetadata.Providers
public abstract class BaseNfoProvider<T> : ILocalMetadataProvider<T>, IHasItemChangeMonitor public abstract class BaseNfoProvider<T> : ILocalMetadataProvider<T>, IHasItemChangeMonitor
where T : BaseItem, new() where T : BaseItem, new()
{ {
private IFileSystem _fileSystem; private readonly IFileSystem _fileSystem;
protected BaseNfoProvider(IFileSystem fileSystem) protected BaseNfoProvider(IFileSystem fileSystem)
{ {

@ -33,10 +33,7 @@ namespace Rssdp.Infrastructure
} }
finally finally
{ {
if (retVal != null) retVal?.Dispose();
{
retVal.Dispose();
}
} }
} }

@ -33,10 +33,7 @@ namespace Rssdp.Infrastructure
} }
catch catch
{ {
if (retVal != null) retVal?.Dispose();
{
retVal.Dispose();
}
throw; throw;
} }

@ -419,7 +419,7 @@ namespace Rssdp.Infrastructure
{ {
try try
{ {
var result = await socket.ReceiveMessageFromAsync(receiveBuffer, new IPEndPoint(IPAddress.Any, _LocalPort), CancellationToken.None).ConfigureAwait(false);; var result = await socket.ReceiveMessageFromAsync(receiveBuffer, new IPEndPoint(IPAddress.Any, _LocalPort), CancellationToken.None).ConfigureAwait(false);
if (result.ReceivedBytes > 0) if (result.ReceivedBytes > 0)
{ {
@ -508,22 +508,16 @@ namespace Rssdp.Infrastructure
} }
var handlers = RequestReceived; var handlers = RequestReceived;
if (handlers is not null) handlers?.Invoke(this, new RequestReceivedEventArgs(data, remoteEndPoint, receivedOnlocalIPAddress));
{
handlers(this, new RequestReceivedEventArgs(data, remoteEndPoint, receivedOnlocalIPAddress));
}
} }
private void OnResponseReceived(HttpResponseMessage data, IPEndPoint endPoint, IPAddress localIPAddress) private void OnResponseReceived(HttpResponseMessage data, IPEndPoint endPoint, IPAddress localIPAddress)
{ {
var handlers = ResponseReceived; var handlers = ResponseReceived;
if (handlers is not null) handlers?.Invoke(this, new ResponseReceivedEventArgs(data, endPoint)
{ {
handlers(this, new ResponseReceivedEventArgs(data, endPoint) LocalIPAddress = localIPAddress
{ });
LocalIPAddress = localIPAddress
});
}
} }
} }
} }

@ -337,10 +337,7 @@ namespace Rssdp
protected virtual void OnDeviceAdded(SsdpEmbeddedDevice device) protected virtual void OnDeviceAdded(SsdpEmbeddedDevice device)
{ {
var handlers = this.DeviceAdded; var handlers = this.DeviceAdded;
if (handlers != null) handlers?.Invoke(this, new DeviceEventArgs(device));
{
handlers(this, new DeviceEventArgs(device));
}
} }
/// <summary> /// <summary>
@ -352,10 +349,7 @@ namespace Rssdp
protected virtual void OnDeviceRemoved(SsdpEmbeddedDevice device) protected virtual void OnDeviceRemoved(SsdpEmbeddedDevice device)
{ {
var handlers = this.DeviceRemoved; var handlers = this.DeviceRemoved;
if (handlers != null) handlers?.Invoke(this, new DeviceEventArgs(device));
{
handlers(this, new DeviceEventArgs(device));
}
} }
} }
} }

@ -227,13 +227,10 @@ namespace Rssdp.Infrastructure
} }
var handlers = DeviceAvailable; var handlers = DeviceAvailable;
if (handlers is not null) handlers?.Invoke(this, new DeviceAvailableEventArgs(device, isNewDevice)
{ {
handlers(this, new DeviceAvailableEventArgs(device, isNewDevice) RemoteIPAddress = IPAddress
{ });
RemoteIPAddress = IPAddress
});
}
} }
/// <summary> /// <summary>
@ -250,10 +247,7 @@ namespace Rssdp.Infrastructure
} }
var handlers = DeviceUnavailable; var handlers = DeviceUnavailable;
if (handlers is not null) handlers?.Invoke(this, new DeviceUnavailableEventArgs(device, expired));
{
handlers(this, new DeviceUnavailableEventArgs(device, expired));
}
} }
/// <summary> /// <summary>

@ -243,7 +243,7 @@ namespace Rssdp.Infrastructure
} }
// Do not block synchronously as that may tie up a threadpool thread for several seconds. // Do not block synchronously as that may tie up a threadpool thread for several seconds.
Task.Delay(_Random.Next(16, maxWaitInterval * 1000)).ContinueWith((parentTask) => Task.Delay(_Random.Next(16, maxWaitInterval * 1000), cancellationToken).ContinueWith((parentTask) =>
{ {
// Copying devices to local array here to avoid threading issues/enumerator exceptions. // Copying devices to local array here to avoid threading issues/enumerator exceptions.
IEnumerable<SsdpDevice> devices = null; IEnumerable<SsdpDevice> devices = null;
@ -281,7 +281,7 @@ namespace Rssdp.Infrastructure
} }
} }
} }
}); }, cancellationToken);
} }
private IEnumerable<SsdpDevice> GetAllDevicesAsFlatEnumerable() private IEnumerable<SsdpDevice> GetAllDevicesAsFlatEnumerable()
@ -530,10 +530,7 @@ namespace Rssdp.Infrastructure
{ {
var timer = _RebroadcastAliveNotificationsTimer; var timer = _RebroadcastAliveNotificationsTimer;
_RebroadcastAliveNotificationsTimer = null; _RebroadcastAliveNotificationsTimer = null;
if (timer is not null) timer?.Dispose();
{
timer.Dispose();
}
} }
private TimeSpan GetMinimumNonZeroCacheLifetime() private TimeSpan GetMinimumNonZeroCacheLifetime()
@ -567,10 +564,7 @@ namespace Rssdp.Infrastructure
private void WriteTrace(string text) private void WriteTrace(string text)
{ {
if (LogFunction is not null) LogFunction?.Invoke(text);
{
LogFunction(text);
}
// System.Diagnostics.Debug.WriteLine(text, "SSDP Publisher"); // System.Diagnostics.Debug.WriteLine(text, "SSDP Publisher");
} }

@ -14,18 +14,18 @@ namespace Jellyfin.Naming.Tests.AudioBook
data.Add( data.Add(
new AudioBookFileInfo( new AudioBookFileInfo(
@"/server/AudioBooks/Larry Potter/Larry Potter.mp3", "/server/AudioBooks/Larry Potter/Larry Potter.mp3",
"mp3")); "mp3"));
data.Add( data.Add(
new AudioBookFileInfo( new AudioBookFileInfo(
@"/server/AudioBooks/Berry Potter/Chapter 1 .ogg", "/server/AudioBooks/Berry Potter/Chapter 1 .ogg",
"ogg", "ogg",
chapterNumber: 1)); chapterNumber: 1));
data.Add( data.Add(
new AudioBookFileInfo( new AudioBookFileInfo(
@"/server/AudioBooks/Nerry Potter/Part 3 - Chapter 2.mp3", "/server/AudioBooks/Nerry Potter/Part 3 - Chapter 2.mp3",
"mp3", "mp3",
chapterNumber: 2, chapterNumber: 2,
partNumber: 3)); partNumber: 3));
@ -49,7 +49,7 @@ namespace Jellyfin.Naming.Tests.AudioBook
[Fact] [Fact]
public void Resolve_InvalidExtension() public void Resolve_InvalidExtension()
{ {
var result = new AudioBookResolver(_namingOptions).Resolve(@"/server/AudioBooks/Larry Potter/Larry Potter.mp9"); var result = new AudioBookResolver(_namingOptions).Resolve("/server/AudioBooks/Larry Potter/Larry Potter.mp9");
Assert.Null(result); Assert.Null(result);
} }

@ -20,11 +20,11 @@ public class ExternalPathParserTests
var hindiCultureDto = new CultureDto("Hindi", "Hindi", "hi", new[] { "hin" }); var hindiCultureDto = new CultureDto("Hindi", "Hindi", "hi", new[] { "hin" });
var localizationManager = new Mock<ILocalizationManager>(MockBehavior.Loose); var localizationManager = new Mock<ILocalizationManager>(MockBehavior.Loose);
localizationManager.Setup(lm => lm.FindLanguageInfo(It.IsRegex(@"en.*", RegexOptions.IgnoreCase))) localizationManager.Setup(lm => lm.FindLanguageInfo(It.IsRegex("en.*", RegexOptions.IgnoreCase)))
.Returns(englishCultureDto); .Returns(englishCultureDto);
localizationManager.Setup(lm => lm.FindLanguageInfo(It.IsRegex(@"fr.*", RegexOptions.IgnoreCase))) localizationManager.Setup(lm => lm.FindLanguageInfo(It.IsRegex("fr.*", RegexOptions.IgnoreCase)))
.Returns(frenchCultureDto); .Returns(frenchCultureDto);
localizationManager.Setup(lm => lm.FindLanguageInfo(It.IsRegex(@"hi.*", RegexOptions.IgnoreCase))) localizationManager.Setup(lm => lm.FindLanguageInfo(It.IsRegex("hi.*", RegexOptions.IgnoreCase)))
.Returns(hindiCultureDto); .Returns(hindiCultureDto);
_audioPathParser = new ExternalPathParser(new NamingOptions(), localizationManager.Object, DlnaProfileType.Audio); _audioPathParser = new ExternalPathParser(new NamingOptions(), localizationManager.Object, DlnaProfileType.Audio);

@ -12,34 +12,34 @@ namespace Jellyfin.Naming.Tests.Music
[InlineData("", false)] [InlineData("", false)]
[InlineData("C:/", false)] [InlineData("C:/", false)]
[InlineData("/home/", false)] [InlineData("/home/", false)]
[InlineData(@"blah blah", false)] [InlineData("blah blah", false)]
[InlineData(@"D:/music/weezer/03 Pinkerton", false)] [InlineData("D:/music/weezer/03 Pinkerton", false)]
[InlineData(@"D:/music/michael jackson/Bad (2012 Remaster)", false)] [InlineData("D:/music/michael jackson/Bad (2012 Remaster)", false)]
[InlineData(@"cd1", true)] [InlineData("cd1", true)]
[InlineData(@"disc18", true)] [InlineData("disc18", true)]
[InlineData(@"disk10", true)] [InlineData("disk10", true)]
[InlineData(@"vol7", true)] [InlineData("vol7", true)]
[InlineData(@"volume1", true)] [InlineData("volume1", true)]
[InlineData(@"cd 1", true)] [InlineData("cd 1", true)]
[InlineData(@"disc 1", true)] [InlineData("disc 1", true)]
[InlineData(@"disk 1", true)] [InlineData("disk 1", true)]
[InlineData(@"disk", false)] [InlineData("disk", false)]
[InlineData(@"disk ·", false)] [InlineData("disk ·", false)]
[InlineData(@"disk a", false)] [InlineData("disk a", false)]
[InlineData(@"disk volume", false)] [InlineData("disk volume", false)]
[InlineData(@"disc disc", false)] [InlineData("disc disc", false)]
[InlineData(@"disk disc 6", false)] [InlineData("disk disc 6", false)]
[InlineData(@"cd - 1", true)] [InlineData("cd - 1", true)]
[InlineData(@"disc- 1", true)] [InlineData("disc- 1", true)]
[InlineData(@"disk - 1", true)] [InlineData("disk - 1", true)]
[InlineData(@"Disc 01 (Hugo Wolf · 24 Lieder)", true)] [InlineData("Disc 01 (Hugo Wolf · 24 Lieder)", true)]
[InlineData(@"Disc 04 (Encores and Folk Songs)", true)] [InlineData("Disc 04 (Encores and Folk Songs)", true)]
[InlineData(@"Disc04 (Encores and Folk Songs)", true)] [InlineData("Disc04 (Encores and Folk Songs)", true)]
[InlineData(@"Disc 04(Encores and Folk Songs)", true)] [InlineData("Disc 04(Encores and Folk Songs)", true)]
[InlineData(@"Disc04(Encores and Folk Songs)", true)] [InlineData("Disc04(Encores and Folk Songs)", true)]
[InlineData(@"D:/Video/MBTestLibrary/VideoTest/music/.38 special/anth/Disc 2", true)] [InlineData("D:/Video/MBTestLibrary/VideoTest/music/.38 special/anth/Disc 2", true)]
[InlineData(@"[1985] Opportunities (Let's make lots of money) (1985)", false)] [InlineData("[1985] Opportunities (Let's make lots of money) (1985)", false)]
[InlineData(@"Blah 04(Encores and Folk Songs)", false)] [InlineData("Blah 04(Encores and Folk Songs)", false)]
public void AlbumParser_MultidiscPath_Identifies(string path, bool result) public void AlbumParser_MultidiscPath_Identifies(string path, bool result)
{ {
var parser = new AlbumParser(_namingOptions); var parser = new AlbumParser(_namingOptions);

@ -9,11 +9,11 @@ namespace Jellyfin.Naming.Tests.TV
private readonly EpisodeResolver _resolver = new EpisodeResolver(new NamingOptions()); private readonly EpisodeResolver _resolver = new EpisodeResolver(new NamingOptions());
[Theory] [Theory]
[InlineData(@"/server/anything_1996.11.14.mp4", "anything", 1996, 11, 14)] [InlineData("/server/anything_1996.11.14.mp4", "anything", 1996, 11, 14)]
[InlineData(@"/server/anything_1996-11-14.mp4", "anything", 1996, 11, 14)] [InlineData("/server/anything_1996-11-14.mp4", "anything", 1996, 11, 14)]
[InlineData(@"/server/james.corden.2017.04.20.anne.hathaway.720p.hdtv.x264-crooks.mkv", "james.corden", 2017, 04, 20)] [InlineData("/server/james.corden.2017.04.20.anne.hathaway.720p.hdtv.x264-crooks.mkv", "james.corden", 2017, 04, 20)]
[InlineData(@"/server/ABC News 2018_03_24_19_00_00.mkv", "ABC News", 2018, 03, 24)] [InlineData("/server/ABC News 2018_03_24_19_00_00.mkv", "ABC News", 2018, 03, 24)]
[InlineData(@"/server/Jeopardy 2023 07 14 HDTV x264 AC3.mkv", "Jeopardy", 2023, 07, 14)] [InlineData("/server/Jeopardy 2023 07 14 HDTV x264 AC3.mkv", "Jeopardy", 2023, 07, 14)]
// TODO: [InlineData(@"/server/anything_14.11.1996.mp4", "anything", 1996, 11, 14)] // TODO: [InlineData(@"/server/anything_14.11.1996.mp4", "anything", 1996, 11, 14)]
// TODO: [InlineData(@"/server/A Daily Show - (2015-01-15) - Episode Name - [720p].mkv", "A Daily Show", 2015, 01, 15)] // TODO: [InlineData(@"/server/A Daily Show - (2015-01-15) - Episode Name - [720p].mkv", "A Daily Show", 2015, 01, 15)]
// TODO: [InlineData(@"/server/Last Man Standing_KTLADT_2018_05_25_01_28_00.wtv", "Last Man Standing", 2018, 05, 25)] // TODO: [InlineData(@"/server/Last Man Standing_KTLADT_2018_05_25_01_28_00.wtv", "Last Man Standing", 2018, 05, 25)]

@ -9,16 +9,16 @@ namespace Jellyfin.Naming.Tests.TV
private readonly EpisodeResolver _resolver = new EpisodeResolver(new NamingOptions()); private readonly EpisodeResolver _resolver = new EpisodeResolver(new NamingOptions());
[Theory] [Theory]
[InlineData(8, @"The Simpsons/The Simpsons.S25E08.Steal this episode.mp4")] [InlineData(8, "The Simpsons/The Simpsons.S25E08.Steal this episode.mp4")]
[InlineData(2, @"The Simpsons/The Simpsons - 02 - Ep Name.avi")] [InlineData(2, "The Simpsons/The Simpsons - 02 - Ep Name.avi")]
[InlineData(2, @"The Simpsons/02.avi")] [InlineData(2, "The Simpsons/02.avi")]
[InlineData(2, @"The Simpsons/02 - Ep Name.avi")] [InlineData(2, "The Simpsons/02 - Ep Name.avi")]
[InlineData(2, @"The Simpsons/02-Ep Name.avi")] [InlineData(2, "The Simpsons/02-Ep Name.avi")]
[InlineData(2, @"The Simpsons/02.EpName.avi")] [InlineData(2, "The Simpsons/02.EpName.avi")]
[InlineData(2, @"The Simpsons/The Simpsons - 02.avi")] [InlineData(2, "The Simpsons/The Simpsons - 02.avi")]
[InlineData(2, @"The Simpsons/The Simpsons - 02 Ep Name.avi")] [InlineData(2, "The Simpsons/The Simpsons - 02 Ep Name.avi")]
[InlineData(7, @"GJ Club (2013)/GJ Club - 07.mkv")] [InlineData(7, "GJ Club (2013)/GJ Club - 07.mkv")]
[InlineData(17, @"Case Closed (1996-2007)/Case Closed - 317.mkv")] [InlineData(17, "Case Closed (1996-2007)/Case Closed - 317.mkv")]
// TODO: [InlineData(2, @"The Simpsons/The Simpsons 5 - 02 - Ep Name.avi")] // TODO: [InlineData(2, @"The Simpsons/The Simpsons 5 - 02 - Ep Name.avi")]
// TODO: [InlineData(2, @"The Simpsons/The Simpsons 5 - 02 Ep Name.avi")] // TODO: [InlineData(2, @"The Simpsons/The Simpsons 5 - 02 Ep Name.avi")]
// TODO: [InlineData(7, @"Seinfeld/Seinfeld 0807 The Checks.avi")] // TODO: [InlineData(7, @"Seinfeld/Seinfeld 0807 The Checks.avi")]

@ -13,10 +13,10 @@ namespace Jellyfin.Naming.Tests.TV
[InlineData("/media/Foo - S04E011", true, "Foo", 4, 11)] [InlineData("/media/Foo - S04E011", true, "Foo", 4, 11)]
[InlineData("/media/Foo/Foo s01x01", true, "Foo", 1, 1)] [InlineData("/media/Foo/Foo s01x01", true, "Foo", 1, 1)]
[InlineData("/media/Foo (2019)/Season 4/Foo (2019).S04E03", true, "Foo (2019)", 4, 3)] [InlineData("/media/Foo (2019)/Season 4/Foo (2019).S04E03", true, "Foo (2019)", 4, 3)]
[InlineData("D:\\media\\Foo\\Foo-S01E01", true, "Foo", 1, 1)] [InlineData(@"D:\media\Foo\Foo-S01E01", true, "Foo", 1, 1)]
[InlineData("D:\\media\\Foo - S04E011", true, "Foo", 4, 11)] [InlineData(@"D:\media\Foo - S04E011", true, "Foo", 4, 11)]
[InlineData("D:\\media\\Foo\\Foo s01x01", true, "Foo", 1, 1)] [InlineData(@"D:\media\Foo\Foo s01x01", true, "Foo", 1, 1)]
[InlineData("D:\\media\\Foo (2019)\\Season 4\\Foo (2019).S04E03", true, "Foo (2019)", 4, 3)] [InlineData(@"D:\media\Foo (2019)\Season 4\Foo (2019).S04E03", true, "Foo (2019)", 4, 3)]
[InlineData("/Season 2/Elementary - 02x03-04-15 - Ep Name.mp4", false, "Elementary", 2, 3)] [InlineData("/Season 2/Elementary - 02x03-04-15 - Ep Name.mp4", false, "Elementary", 2, 3)]
[InlineData("/Season 1/seriesname S01E02 blah.avi", false, "seriesname", 1, 2)] [InlineData("/Season 1/seriesname S01E02 blah.avi", false, "seriesname", 1, 2)]
[InlineData("/Running Man/Running Man S2017E368.mkv", false, "Running Man", 2017, 368)] [InlineData("/Running Man/Running Man S2017E368.mkv", false, "Running Man", 2017, 368)]

@ -9,66 +9,66 @@ namespace Jellyfin.Naming.Tests.TV
private readonly EpisodePathParser _episodePathParser = new EpisodePathParser(new NamingOptions()); private readonly EpisodePathParser _episodePathParser = new EpisodePathParser(new NamingOptions());
[Theory] [Theory]
[InlineData(@"Season 1/4x01 20 Hours in America (1).mkv", null)] [InlineData("Season 1/4x01 20 Hours in America (1).mkv", null)]
[InlineData(@"Season 1/01x02 blah.avi", null)] [InlineData("Season 1/01x02 blah.avi", null)]
[InlineData(@"Season 1/S01x02 blah.avi", null)] [InlineData("Season 1/S01x02 blah.avi", null)]
[InlineData(@"Season 1/S01E02 blah.avi", null)] [InlineData("Season 1/S01E02 blah.avi", null)]
[InlineData(@"Season 1/S01xE02 blah.avi", null)] [InlineData("Season 1/S01xE02 blah.avi", null)]
[InlineData(@"Season 1/seriesname 01x02 blah.avi", null)] [InlineData("Season 1/seriesname 01x02 blah.avi", null)]
[InlineData(@"Season 1/seriesname S01x02 blah.avi", null)] [InlineData("Season 1/seriesname S01x02 blah.avi", null)]
[InlineData(@"Season 1/seriesname S01E02 blah.avi", null)] [InlineData("Season 1/seriesname S01E02 blah.avi", null)]
[InlineData(@"Season 1/seriesname S01xE02 blah.avi", null)] [InlineData("Season 1/seriesname S01xE02 blah.avi", null)]
[InlineData(@"Season 2/02x03 - 04 Ep Name.mp4", null)] [InlineData("Season 2/02x03 - 04 Ep Name.mp4", null)]
[InlineData(@"Season 2/My show name 02x03 - 04 Ep Name.mp4", null)] [InlineData("Season 2/My show name 02x03 - 04 Ep Name.mp4", null)]
[InlineData(@"Season 2/Elementary - 02x03 - 02x04 - 02x15 - Ep Name.mp4", 15)] [InlineData("Season 2/Elementary - 02x03 - 02x04 - 02x15 - Ep Name.mp4", 15)]
[InlineData(@"Season 2/02x03 - 02x04 - 02x15 - Ep Name.mp4", 15)] [InlineData("Season 2/02x03 - 02x04 - 02x15 - Ep Name.mp4", 15)]
[InlineData(@"Season 2/02x03-04-15 - Ep Name.mp4", 15)] [InlineData("Season 2/02x03-04-15 - Ep Name.mp4", 15)]
[InlineData(@"Season 2/Elementary - 02x03-04-15 - Ep Name.mp4", 15)] [InlineData("Season 2/Elementary - 02x03-04-15 - Ep Name.mp4", 15)]
[InlineData(@"Season 02/02x03-E15 - Ep Name.mp4", 15)] [InlineData("Season 02/02x03-E15 - Ep Name.mp4", 15)]
[InlineData(@"Season 02/Elementary - 02x03-E15 - Ep Name.mp4", 15)] [InlineData("Season 02/Elementary - 02x03-E15 - Ep Name.mp4", 15)]
[InlineData(@"Season 02/02x03 - x04 - x15 - Ep Name.mp4", 15)] [InlineData("Season 02/02x03 - x04 - x15 - Ep Name.mp4", 15)]
[InlineData(@"Season 02/Elementary - 02x03 - x04 - x15 - Ep Name.mp4", 15)] [InlineData("Season 02/Elementary - 02x03 - x04 - x15 - Ep Name.mp4", 15)]
[InlineData(@"Season 02/02x03x04x15 - Ep Name.mp4", 15)] [InlineData("Season 02/02x03x04x15 - Ep Name.mp4", 15)]
[InlineData(@"Season 02/Elementary - 02x03x04x15 - Ep Name.mp4", 15)] [InlineData("Season 02/Elementary - 02x03x04x15 - Ep Name.mp4", 15)]
[InlineData(@"Season 1/Elementary - S01E23-E24-E26 - The Woman.mp4", 26)] [InlineData("Season 1/Elementary - S01E23-E24-E26 - The Woman.mp4", 26)]
[InlineData(@"Season 1/S01E23-E24-E26 - The Woman.mp4", 26)] [InlineData("Season 1/S01E23-E24-E26 - The Woman.mp4", 26)]
// Four Digits seasons // Four Digits seasons
[InlineData(@"Season 2009/2009x02 blah.avi", null)] [InlineData("Season 2009/2009x02 blah.avi", null)]
[InlineData(@"Season 2009/S2009x02 blah.avi", null)] [InlineData("Season 2009/S2009x02 blah.avi", null)]
[InlineData(@"Season 2009/S2009E02 blah.avi", null)] [InlineData("Season 2009/S2009E02 blah.avi", null)]
[InlineData(@"Season 2009/S2009xE02 blah.avi", null)] [InlineData("Season 2009/S2009xE02 blah.avi", null)]
[InlineData(@"Season 2009/seriesname 2009x02 blah.avi", null)] [InlineData("Season 2009/seriesname 2009x02 blah.avi", null)]
[InlineData(@"Season 2009/seriesname S2009x02 blah.avi", null)] [InlineData("Season 2009/seriesname S2009x02 blah.avi", null)]
[InlineData(@"Season 2009/seriesname S2009E02 blah.avi", null)] [InlineData("Season 2009/seriesname S2009E02 blah.avi", null)]
[InlineData(@"Season 2009/seriesname S2009xE02 blah.avi", null)] [InlineData("Season 2009/seriesname S2009xE02 blah.avi", null)]
[InlineData(@"Season 2009/Elementary - 2009x03 - 2009x04 - 2009x15 - Ep Name.mp4", 15)] [InlineData("Season 2009/Elementary - 2009x03 - 2009x04 - 2009x15 - Ep Name.mp4", 15)]
[InlineData(@"Season 2009/2009x03 - 2009x04 - 2009x15 - Ep Name.mp4", 15)] [InlineData("Season 2009/2009x03 - 2009x04 - 2009x15 - Ep Name.mp4", 15)]
[InlineData(@"Season 2009/2009x03-04-15 - Ep Name.mp4", 15)] [InlineData("Season 2009/2009x03-04-15 - Ep Name.mp4", 15)]
[InlineData(@"Season 2009/Elementary - 2009x03-04-15 - Ep Name.mp4", 15)] [InlineData("Season 2009/Elementary - 2009x03-04-15 - Ep Name.mp4", 15)]
[InlineData(@"Season 2009/2009x03-E15 - Ep Name.mp4", 15)] [InlineData("Season 2009/2009x03-E15 - Ep Name.mp4", 15)]
[InlineData(@"Season 2009/Elementary - 2009x03-E15 - Ep Name.mp4", 15)] [InlineData("Season 2009/Elementary - 2009x03-E15 - Ep Name.mp4", 15)]
[InlineData(@"Season 2009/2009x03 - x04 - x15 - Ep Name.mp4", 15)] [InlineData("Season 2009/2009x03 - x04 - x15 - Ep Name.mp4", 15)]
[InlineData(@"Season 2009/Elementary - 2009x03 - x04 - x15 - Ep Name.mp4", 15)] [InlineData("Season 2009/Elementary - 2009x03 - x04 - x15 - Ep Name.mp4", 15)]
[InlineData(@"Season 2009/2009x03x04x15 - Ep Name.mp4", 15)] [InlineData("Season 2009/2009x03x04x15 - Ep Name.mp4", 15)]
[InlineData(@"Season 2009/Elementary - 2009x03x04x15 - Ep Name.mp4", 15)] [InlineData("Season 2009/Elementary - 2009x03x04x15 - Ep Name.mp4", 15)]
[InlineData(@"Season 2009/Elementary - S2009E23-E24-E26 - The Woman.mp4", 26)] [InlineData("Season 2009/Elementary - S2009E23-E24-E26 - The Woman.mp4", 26)]
[InlineData(@"Season 2009/S2009E23-E24-E26 - The Woman.mp4", 26)] [InlineData("Season 2009/S2009E23-E24-E26 - The Woman.mp4", 26)]
// Without season number // Without season number
[InlineData(@"Season 1/02 - blah.avi", null)] [InlineData("Season 1/02 - blah.avi", null)]
[InlineData(@"Season 2/02 - blah 14 blah.avi", null)] [InlineData("Season 2/02 - blah 14 blah.avi", null)]
[InlineData(@"Season 1/02 - blah-02 a.avi", null)] [InlineData("Season 1/02 - blah-02 a.avi", null)]
[InlineData(@"Season 2/02.avi", null)] [InlineData("Season 2/02.avi", null)]
[InlineData(@"Season 1/02-03 - blah.avi", 3)] [InlineData("Season 1/02-03 - blah.avi", 3)]
[InlineData(@"Season 2/02-04 - blah 14 blah.avi", 4)] [InlineData("Season 2/02-04 - blah 14 blah.avi", 4)]
[InlineData(@"Season 1/02-05 - blah-02 a.avi", 5)] [InlineData("Season 1/02-05 - blah-02 a.avi", 5)]
[InlineData(@"Season 2/02-04.avi", 4)] [InlineData("Season 2/02-04.avi", 4)]
[InlineData(@"Season 2 /[HorribleSubs] Hunter X Hunter - 136[720p].mkv", null)] [InlineData("Season 2 /[HorribleSubs] Hunter X Hunter - 136[720p].mkv", null)]
// With format specification that must not be detected as ending episode number // With format specification that must not be detected as ending episode number
[InlineData(@"Season 1/series-s09e14-1080p.mkv", null)] [InlineData("Season 1/series-s09e14-1080p.mkv", null)]
[InlineData(@"Season 1/series-s09e14-720p.mkv", null)] [InlineData("Season 1/series-s09e14-720p.mkv", null)]
[InlineData(@"Season 1/series-s09e14-720i.mkv", null)] [InlineData("Season 1/series-s09e14-720i.mkv", null)]
[InlineData(@"Season 1/MOONLIGHTING_s01e01-e04.mkv", 4)] [InlineData("Season 1/MOONLIGHTING_s01e01-e04.mkv", 4)]
[InlineData(@"Season 1/MOONLIGHTING_s01e01-e04", 4)] [InlineData("Season 1/MOONLIGHTING_s01e01-e04", 4)]
public void TestGetEndingEpisodeNumberFromFile(string filename, int? endingEpisodeNumber) public void TestGetEndingEpisodeNumberFromFile(string filename, int? endingEpisodeNumber)
{ {
var result = _episodePathParser.Parse(filename, false); var result = _episodePathParser.Parse(filename, false);

@ -6,23 +6,23 @@ namespace Jellyfin.Naming.Tests.TV
public class SeasonFolderTests public class SeasonFolderTests
{ {
[Theory] [Theory]
[InlineData(@"/Drive/Season 1", 1, true)] [InlineData("/Drive/Season 1", 1, true)]
[InlineData(@"/Drive/Season 2", 2, true)] [InlineData("/Drive/Season 2", 2, true)]
[InlineData(@"/Drive/Season 02", 2, true)] [InlineData("/Drive/Season 02", 2, true)]
[InlineData(@"/Drive/Seinfeld/S02", 2, true)] [InlineData("/Drive/Seinfeld/S02", 2, true)]
[InlineData(@"/Drive/Seinfeld/2", 2, true)] [InlineData("/Drive/Seinfeld/2", 2, true)]
[InlineData(@"/Drive/Season 2009", 2009, true)] [InlineData("/Drive/Season 2009", 2009, true)]
[InlineData(@"/Drive/Season1", 1, true)] [InlineData("/Drive/Season1", 1, true)]
[InlineData(@"The Wonder Years/The.Wonder.Years.S04.PDTV.x264-JCH", 4, true)] [InlineData("The Wonder Years/The.Wonder.Years.S04.PDTV.x264-JCH", 4, true)]
[InlineData(@"/Drive/Season 7 (2016)", 7, false)] [InlineData("/Drive/Season 7 (2016)", 7, false)]
[InlineData(@"/Drive/Staffel 7 (2016)", 7, false)] [InlineData("/Drive/Staffel 7 (2016)", 7, false)]
[InlineData(@"/Drive/Stagione 7 (2016)", 7, false)] [InlineData("/Drive/Stagione 7 (2016)", 7, false)]
[InlineData(@"/Drive/Season (8)", null, false)] [InlineData("/Drive/Season (8)", null, false)]
[InlineData(@"/Drive/3.Staffel", 3, false)] [InlineData("/Drive/3.Staffel", 3, false)]
[InlineData(@"/Drive/s06e05", null, false)] [InlineData("/Drive/s06e05", null, false)]
[InlineData(@"/Drive/The.Legend.of.Condor.Heroes.2017.V2.web-dl.1080p.h264.aac-hdctv", null, false)] [InlineData("/Drive/The.Legend.of.Condor.Heroes.2017.V2.web-dl.1080p.h264.aac-hdctv", null, false)]
[InlineData(@"/Drive/extras", 0, true)] [InlineData("/Drive/extras", 0, true)]
[InlineData(@"/Drive/specials", 0, true)] [InlineData("/Drive/specials", 0, true)]
public void GetSeasonNumberFromPathTest(string path, int? seasonNumber, bool isSeasonDirectory) public void GetSeasonNumberFromPathTest(string path, int? seasonNumber, bool isSeasonDirectory)
{ {
var result = SeasonPathParser.Parse(path, true, true); var result = SeasonPathParser.Parse(path, true, true);

@ -51,8 +51,8 @@ namespace Jellyfin.Naming.Tests.TV
[InlineData("Season 2009/Elementary - S2009E23-E24-E26 - The Woman.mp4", 2009)] [InlineData("Season 2009/Elementary - S2009E23-E24-E26 - The Woman.mp4", 2009)]
[InlineData("Season 2009/S2009E23-E24-E26 - The Woman.mp4", 2009)] [InlineData("Season 2009/S2009E23-E24-E26 - The Woman.mp4", 2009)]
[InlineData("Series/1-12 - The Woman.mp4", 1)] [InlineData("Series/1-12 - The Woman.mp4", 1)]
[InlineData(@"Running Man/Running Man S2017E368.mkv", 2017)] [InlineData("Running Man/Running Man S2017E368.mkv", 2017)]
[InlineData(@"Case Closed (1996-2007)/Case Closed - 317.mkv", 3)] [InlineData("Case Closed (1996-2007)/Case Closed - 317.mkv", 3)]
// TODO: [InlineData(@"Seinfeld/Seinfeld 0807 The Checks.avi", 8)] // TODO: [InlineData(@"Seinfeld/Seinfeld 0807 The Checks.avi", 8)]
public void GetSeasonNumberFromEpisodeFileTest(string path, int? expected) public void GetSeasonNumberFromEpisodeFileTest(string path, int? expected)
{ {

@ -21,8 +21,8 @@ namespace Jellyfin.Naming.Tests.TV
[InlineData("Series/4x12 - The Woman.mp4", "", 4, 12)] [InlineData("Series/4x12 - The Woman.mp4", "", 4, 12)]
[InlineData("Series/LA X, Pt. 1_s06e32.mp4", "LA X, Pt. 1", 6, 32)] [InlineData("Series/LA X, Pt. 1_s06e32.mp4", "LA X, Pt. 1", 6, 32)]
[InlineData("[Baz-Bar]Foo - [1080p][Multiple Subtitle]/[Baz-Bar] Foo - 05 [1080p][Multiple Subtitle].mkv", "Foo", null, 5)] [InlineData("[Baz-Bar]Foo - [1080p][Multiple Subtitle]/[Baz-Bar] Foo - 05 [1080p][Multiple Subtitle].mkv", "Foo", null, 5)]
[InlineData(@"/Foo/The.Series.Name.S01E04.WEBRip.x264-Baz[Bar]/the.series.name.s01e04.webrip.x264-Baz[Bar].mkv", "The.Series.Name", 1, 4)] [InlineData("/Foo/The.Series.Name.S01E04.WEBRip.x264-Baz[Bar]/the.series.name.s01e04.webrip.x264-Baz[Bar].mkv", "The.Series.Name", 1, 4)]
[InlineData(@"Love.Death.and.Robots.S01.1080p.NF.WEB-DL.DDP5.1.x264-NTG/Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv", "Love.Death.and.Robots", 1, 1)] [InlineData("Love.Death.and.Robots.S01.1080p.NF.WEB-DL.DDP5.1.x264-NTG/Love.Death.and.Robots.S01E01.Sonnies.Edge.1080p.NF.WEB-DL.DDP5.1.x264-NTG.mkv", "Love.Death.and.Robots", 1, 1)]
[InlineData("[YuiSubs] Tensura Nikki - Tensei Shitara Slime Datta Ken/[YuiSubs] Tensura Nikki - Tensei Shitara Slime Datta Ken - 12 (NVENC H.265 1080p).mkv", "Tensura Nikki - Tensei Shitara Slime Datta Ken", null, 12)] [InlineData("[YuiSubs] Tensura Nikki - Tensei Shitara Slime Datta Ken/[YuiSubs] Tensura Nikki - Tensei Shitara Slime Datta Ken - 12 (NVENC H.265 1080p).mkv", "Tensura Nikki - Tensei Shitara Slime Datta Ken", null, 12)]
[InlineData("[Baz-Bar]Foo - 01 - 12[1080p][Multiple Subtitle]/[Baz-Bar] Foo - 05 [1080p][Multiple Subtitle].mkv", "Foo", null, 5)] [InlineData("[Baz-Bar]Foo - 01 - 12[1080p][Multiple Subtitle]/[Baz-Bar] Foo - 05 [1080p][Multiple Subtitle].mkv", "Foo", null, 5)]
[InlineData("Series/4-12 - The Woman.mp4", "", 4, 12, 12)] [InlineData("Series/4-12 - The Woman.mp4", "", 4, 12, 12)]

@ -10,34 +10,34 @@ namespace Jellyfin.Naming.Tests.Video
private readonly NamingOptions _namingOptions = new NamingOptions(); private readonly NamingOptions _namingOptions = new NamingOptions();
[Theory] [Theory]
[InlineData(@"The Wolf of Wall Street (2013).mkv", "The Wolf of Wall Street", 2013)] [InlineData("The Wolf of Wall Street (2013).mkv", "The Wolf of Wall Street", 2013)]
[InlineData(@"The Wolf of Wall Street 2 (2013).mkv", "The Wolf of Wall Street 2", 2013)] [InlineData("The Wolf of Wall Street 2 (2013).mkv", "The Wolf of Wall Street 2", 2013)]
[InlineData(@"The Wolf of Wall Street - 2 (2013).mkv", "The Wolf of Wall Street - 2", 2013)] [InlineData("The Wolf of Wall Street - 2 (2013).mkv", "The Wolf of Wall Street - 2", 2013)]
[InlineData(@"The Wolf of Wall Street 2001 (2013).mkv", "The Wolf of Wall Street 2001", 2013)] [InlineData("The Wolf of Wall Street 2001 (2013).mkv", "The Wolf of Wall Street 2001", 2013)]
[InlineData(@"300 (2006).mkv", "300", 2006)] [InlineData("300 (2006).mkv", "300", 2006)]
[InlineData(@"d:/movies/300 (2006).mkv", "300", 2006)] [InlineData("d:/movies/300 (2006).mkv", "300", 2006)]
[InlineData(@"300 2 (2006).mkv", "300 2", 2006)] [InlineData("300 2 (2006).mkv", "300 2", 2006)]
[InlineData(@"300 - 2 (2006).mkv", "300 - 2", 2006)] [InlineData("300 - 2 (2006).mkv", "300 - 2", 2006)]
[InlineData(@"300 2001 (2006).mkv", "300 2001", 2006)] [InlineData("300 2001 (2006).mkv", "300 2001", 2006)]
[InlineData(@"curse.of.chucky.2013.stv.unrated.multi.1080p.bluray.x264-rough", "curse.of.chucky", 2013)] [InlineData("curse.of.chucky.2013.stv.unrated.multi.1080p.bluray.x264-rough", "curse.of.chucky", 2013)]
[InlineData(@"curse.of.chucky.2013.stv.unrated.multi.2160p.bluray.x264-rough", "curse.of.chucky", 2013)] [InlineData("curse.of.chucky.2013.stv.unrated.multi.2160p.bluray.x264-rough", "curse.of.chucky", 2013)]
[InlineData(@"/server/Movies/300 (2007)/300 (2006).bluray.disc", "300", 2006)] [InlineData("/server/Movies/300 (2007)/300 (2006).bluray.disc", "300", 2006)]
[InlineData(@"Arrival.2016.2160p.Blu-Ray.HEVC.mkv", "Arrival", 2016)] [InlineData("Arrival.2016.2160p.Blu-Ray.HEVC.mkv", "Arrival", 2016)]
[InlineData(@"The Wolf of Wall Street (2013)", "The Wolf of Wall Street", 2013)] [InlineData("The Wolf of Wall Street (2013)", "The Wolf of Wall Street", 2013)]
[InlineData(@"The Wolf of Wall Street 2 (2013)", "The Wolf of Wall Street 2", 2013)] [InlineData("The Wolf of Wall Street 2 (2013)", "The Wolf of Wall Street 2", 2013)]
[InlineData(@"The Wolf of Wall Street - 2 (2013)", "The Wolf of Wall Street - 2", 2013)] [InlineData("The Wolf of Wall Street - 2 (2013)", "The Wolf of Wall Street - 2", 2013)]
[InlineData(@"The Wolf of Wall Street 2001 (2013)", "The Wolf of Wall Street 2001", 2013)] [InlineData("The Wolf of Wall Street 2001 (2013)", "The Wolf of Wall Street 2001", 2013)]
[InlineData(@"300 (2006)", "300", 2006)] [InlineData("300 (2006)", "300", 2006)]
[InlineData(@"d:/movies/300 (2006)", "300", 2006)] [InlineData("d:/movies/300 (2006)", "300", 2006)]
[InlineData(@"300 2 (2006)", "300 2", 2006)] [InlineData("300 2 (2006)", "300 2", 2006)]
[InlineData(@"300 - 2 (2006)", "300 - 2", 2006)] [InlineData("300 - 2 (2006)", "300 - 2", 2006)]
[InlineData(@"300 2001 (2006)", "300 2001", 2006)] [InlineData("300 2001 (2006)", "300 2001", 2006)]
[InlineData(@"/server/Movies/300 (2007)/300 (2006)", "300", 2006)] [InlineData("/server/Movies/300 (2007)/300 (2006)", "300", 2006)]
[InlineData(@"/server/Movies/300 (2007)/300 (2006).mkv", "300", 2006)] [InlineData("/server/Movies/300 (2007)/300 (2006).mkv", "300", 2006)]
[InlineData(@"American.Psycho.mkv", "American.Psycho.mkv", null)] [InlineData("American.Psycho.mkv", "American.Psycho.mkv", null)]
[InlineData(@"American Psycho.mkv", "American Psycho.mkv", null)] [InlineData("American Psycho.mkv", "American Psycho.mkv", null)]
[InlineData(@"[rec].mkv", "[rec].mkv", null)] [InlineData("[rec].mkv", "[rec].mkv", null)]
[InlineData(@"St. Vincent (2014)", "St. Vincent", 2014)] [InlineData("St. Vincent (2014)", "St. Vincent", 2014)]
[InlineData("Super movie(2009).mp4", "Super movie", 2009)] [InlineData("Super movie(2009).mp4", "Super movie", 2009)]
[InlineData("Drug War 2013.mp4", "Drug War", 2013)] [InlineData("Drug War 2013.mp4", "Drug War", 2013)]
[InlineData("My Movie (1997) - GreatestReleaseGroup 2019.mp4", "My Movie", 1997)] [InlineData("My Movie (1997) - GreatestReleaseGroup 2019.mp4", "My Movie", 1997)]
@ -45,9 +45,9 @@ namespace Jellyfin.Naming.Tests.Video
[InlineData("First Man (2018) 1080p.mkv", "First Man", 2018)] [InlineData("First Man (2018) 1080p.mkv", "First Man", 2018)]
[InlineData("Maximum Ride - 2016 - WEBDL-1080p - x264 AC3.mkv", "Maximum Ride", 2016)] [InlineData("Maximum Ride - 2016 - WEBDL-1080p - x264 AC3.mkv", "Maximum Ride", 2016)]
// FIXME: [InlineData("Robin Hood [Multi-Subs] [2018].mkv", "Robin Hood", 2018)] // FIXME: [InlineData("Robin Hood [Multi-Subs] [2018].mkv", "Robin Hood", 2018)]
[InlineData(@"3.Days.to.Kill.2014.720p.BluRay.x264.YIFY.mkv", "3.Days.to.Kill", 2014)] // In this test case, running CleanDateTime first produces no date, so it will attempt to run CleanString first and then CleanDateTime again [InlineData("3.Days.to.Kill.2014.720p.BluRay.x264.YIFY.mkv", "3.Days.to.Kill", 2014)] // In this test case, running CleanDateTime first produces no date, so it will attempt to run CleanString first and then CleanDateTime again
[InlineData("3 days to kill (2005).mkv", "3 days to kill", 2005)] [InlineData("3 days to kill (2005).mkv", "3 days to kill", 2005)]
[InlineData(@"Rain Man 1988 REMASTERED 1080p BluRay x264 AAC - Ozlem.mp4", "Rain Man", 1988)] [InlineData("Rain Man 1988 REMASTERED 1080p BluRay x264 AAC - Ozlem.mp4", "Rain Man", 1988)]
[InlineData("My Movie 2013.12.09", "My Movie 2013.12.09", null)] [InlineData("My Movie 2013.12.09", "My Movie 2013.12.09", null)]
[InlineData("My Movie 2013-12-09", "My Movie 2013-12-09", null)] [InlineData("My Movie 2013-12-09", "My Movie 2013-12-09", null)]
[InlineData("My Movie 20131209", "My Movie 20131209", null)] [InlineData("My Movie 20131209", "My Movie 20131209", null)]

@ -22,7 +22,7 @@ namespace Jellyfin.Naming.Tests.Video
[Fact] [Fact]
public void Test3DName() public void Test3DName()
{ {
var result = VideoResolver.ResolveFile(@"C:/Users/media/Desktop/Video Test/Movies/Oblivion/Oblivion.3d.hsbs.mkv", _namingOptions); var result = VideoResolver.ResolveFile("C:/Users/media/Desktop/Video Test/Movies/Oblivion/Oblivion.3d.hsbs.mkv", _namingOptions);
Assert.Equal("hsbs", result?.Format3D); Assert.Equal("hsbs", result?.Format3D);
Assert.Equal("Oblivion", result?.Name); Assert.Equal("Oblivion", result?.Name);

@ -15,10 +15,10 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/movies/X-Men Days of Future Past/X-Men Days of Future Past - 1080p.mkv", "/movies/X-Men Days of Future Past/X-Men Days of Future Past - 1080p.mkv",
@"/movies/X-Men Days of Future Past/X-Men Days of Future Past-trailer.mp4", "/movies/X-Men Days of Future Past/X-Men Days of Future Past-trailer.mp4",
@"/movies/X-Men Days of Future Past/X-Men Days of Future Past - [hsbs].mkv", "/movies/X-Men Days of Future Past/X-Men Days of Future Past - [hsbs].mkv",
@"/movies/X-Men Days of Future Past/X-Men Days of Future Past [hsbs].mkv" "/movies/X-Men Days of Future Past/X-Men Days of Future Past [hsbs].mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -34,10 +34,10 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/movies/X-Men Days of Future Past/X-Men Days of Future Past - apple.mkv", "/movies/X-Men Days of Future Past/X-Men Days of Future Past - apple.mkv",
@"/movies/X-Men Days of Future Past/X-Men Days of Future Past-trailer.mp4", "/movies/X-Men Days of Future Past/X-Men Days of Future Past-trailer.mp4",
@"/movies/X-Men Days of Future Past/X-Men Days of Future Past - banana.mkv", "/movies/X-Men Days of Future Past/X-Men Days of Future Past - banana.mkv",
@"/movies/X-Men Days of Future Past/X-Men Days of Future Past [banana].mp4" "/movies/X-Men Days of Future Past/X-Men Days of Future Past [banana].mp4"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -54,8 +54,8 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/movies/The Phantom of the Opera (1925)/The Phantom of the Opera (1925) - 1925 version.mkv", "/movies/The Phantom of the Opera (1925)/The Phantom of the Opera (1925) - 1925 version.mkv",
@"/movies/The Phantom of the Opera (1925)/The Phantom of the Opera (1925) - 1929 version.mkv" "/movies/The Phantom of the Opera (1925)/The Phantom of the Opera (1925) - 1929 version.mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -71,13 +71,13 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/movies/M/Movie 1.mkv", "/movies/M/Movie 1.mkv",
@"/movies/M/Movie 2.mkv", "/movies/M/Movie 2.mkv",
@"/movies/M/Movie 3.mkv", "/movies/M/Movie 3.mkv",
@"/movies/M/Movie 4.mkv", "/movies/M/Movie 4.mkv",
@"/movies/M/Movie 5.mkv", "/movies/M/Movie 5.mkv",
@"/movies/M/Movie 6.mkv", "/movies/M/Movie 6.mkv",
@"/movies/M/Movie 7.mkv" "/movies/M/Movie 7.mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -93,14 +93,14 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/movies/Movie/Movie.mkv", "/movies/Movie/Movie.mkv",
@"/movies/Movie/Movie-2.mkv", "/movies/Movie/Movie-2.mkv",
@"/movies/Movie/Movie-3.mkv", "/movies/Movie/Movie-3.mkv",
@"/movies/Movie/Movie-4.mkv", "/movies/Movie/Movie-4.mkv",
@"/movies/Movie/Movie-5.mkv", "/movies/Movie/Movie-5.mkv",
@"/movies/Movie/Movie-6.mkv", "/movies/Movie/Movie-6.mkv",
@"/movies/Movie/Movie-7.mkv", "/movies/Movie/Movie-7.mkv",
@"/movies/Movie/Movie-8.mkv" "/movies/Movie/Movie-8.mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -116,15 +116,15 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/movies/Mo/Movie 1.mkv", "/movies/Mo/Movie 1.mkv",
@"/movies/Mo/Movie 2.mkv", "/movies/Mo/Movie 2.mkv",
@"/movies/Mo/Movie 3.mkv", "/movies/Mo/Movie 3.mkv",
@"/movies/Mo/Movie 4.mkv", "/movies/Mo/Movie 4.mkv",
@"/movies/Mo/Movie 5.mkv", "/movies/Mo/Movie 5.mkv",
@"/movies/Mo/Movie 6.mkv", "/movies/Mo/Movie 6.mkv",
@"/movies/Mo/Movie 7.mkv", "/movies/Mo/Movie 7.mkv",
@"/movies/Mo/Movie 8.mkv", "/movies/Mo/Movie 8.mkv",
@"/movies/Mo/Movie 9.mkv" "/movies/Mo/Movie 9.mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -140,11 +140,11 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/movies/Movie/Movie 1.mkv", "/movies/Movie/Movie 1.mkv",
@"/movies/Movie/Movie 2.mkv", "/movies/Movie/Movie 2.mkv",
@"/movies/Movie/Movie 3.mkv", "/movies/Movie/Movie 3.mkv",
@"/movies/Movie/Movie 4.mkv", "/movies/Movie/Movie 4.mkv",
@"/movies/Movie/Movie 5.mkv" "/movies/Movie/Movie 5.mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -162,11 +162,11 @@ namespace Jellyfin.Naming.Tests.Video
var files = new[] var files = new[]
{ {
@"/movies/Iron Man/Iron Man.mkv", "/movies/Iron Man/Iron Man.mkv",
@"/movies/Iron Man/Iron Man (2008).mkv", "/movies/Iron Man/Iron Man (2008).mkv",
@"/movies/Iron Man/Iron Man (2009).mkv", "/movies/Iron Man/Iron Man (2009).mkv",
@"/movies/Iron Man/Iron Man (2010).mkv", "/movies/Iron Man/Iron Man (2010).mkv",
@"/movies/Iron Man/Iron Man (2011).mkv" "/movies/Iron Man/Iron Man (2011).mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -182,13 +182,13 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/movies/Iron Man/Iron Man.mkv", "/movies/Iron Man/Iron Man.mkv",
@"/movies/Iron Man/Iron Man-720p.mkv", "/movies/Iron Man/Iron Man-720p.mkv",
@"/movies/Iron Man/Iron Man-test.mkv", "/movies/Iron Man/Iron Man-test.mkv",
@"/movies/Iron Man/Iron Man-bluray.mkv", "/movies/Iron Man/Iron Man-bluray.mkv",
@"/movies/Iron Man/Iron Man-3d.mkv", "/movies/Iron Man/Iron Man-3d.mkv",
@"/movies/Iron Man/Iron Man-3d-hsbs.mkv", "/movies/Iron Man/Iron Man-3d-hsbs.mkv",
@"/movies/Iron Man/Iron Man[test].mkv" "/movies/Iron Man/Iron Man[test].mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -211,13 +211,13 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/movies/Iron Man/Iron Man.mkv", "/movies/Iron Man/Iron Man.mkv",
@"/movies/Iron Man/Iron Man - 720p.mkv", "/movies/Iron Man/Iron Man - 720p.mkv",
@"/movies/Iron Man/Iron Man - test.mkv", "/movies/Iron Man/Iron Man - test.mkv",
@"/movies/Iron Man/Iron Man - bluray.mkv", "/movies/Iron Man/Iron Man - bluray.mkv",
@"/movies/Iron Man/Iron Man - 3d.mkv", "/movies/Iron Man/Iron Man - 3d.mkv",
@"/movies/Iron Man/Iron Man - 3d-hsbs.mkv", "/movies/Iron Man/Iron Man - 3d-hsbs.mkv",
@"/movies/Iron Man/Iron Man [test].mkv" "/movies/Iron Man/Iron Man [test].mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -240,8 +240,8 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/movies/Iron Man/Iron Man - B (2006).mkv", "/movies/Iron Man/Iron Man - B (2006).mkv",
@"/movies/Iron Man/Iron Man - C (2007).mkv" "/movies/Iron Man/Iron Man - C (2007).mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -256,13 +256,13 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/movies/Iron Man/Iron Man.mkv", "/movies/Iron Man/Iron Man.mkv",
@"/movies/Iron Man/Iron Man_720p.mkv", "/movies/Iron Man/Iron Man_720p.mkv",
@"/movies/Iron Man/Iron Man_test.mkv", "/movies/Iron Man/Iron Man_test.mkv",
@"/movies/Iron Man/Iron Man_bluray.mkv", "/movies/Iron Man/Iron Man_bluray.mkv",
@"/movies/Iron Man/Iron Man_3d.mkv", "/movies/Iron Man/Iron Man_3d.mkv",
@"/movies/Iron Man/Iron Man_3d-hsbs.mkv", "/movies/Iron Man/Iron Man_3d-hsbs.mkv",
@"/movies/Iron Man/Iron Man_3d.hsbs.mkv" "/movies/Iron Man/Iron Man_3d.hsbs.mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -280,11 +280,11 @@ namespace Jellyfin.Naming.Tests.Video
var files = new[] var files = new[]
{ {
@"/movies/Iron Man/Iron Man (2007).mkv", "/movies/Iron Man/Iron Man (2007).mkv",
@"/movies/Iron Man/Iron Man (2008).mkv", "/movies/Iron Man/Iron Man (2008).mkv",
@"/movies/Iron Man/Iron Man (2009).mkv", "/movies/Iron Man/Iron Man (2009).mkv",
@"/movies/Iron Man/Iron Man (2010).mkv", "/movies/Iron Man/Iron Man (2010).mkv",
@"/movies/Iron Man/Iron Man (2011).mkv" "/movies/Iron Man/Iron Man (2011).mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -300,8 +300,8 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/movies/Blade Runner (1982)/Blade Runner (1982) [Final Cut] [1080p HEVC AAC].mkv", "/movies/Blade Runner (1982)/Blade Runner (1982) [Final Cut] [1080p HEVC AAC].mkv",
@"/movies/Blade Runner (1982)/Blade Runner (1982) [EE by ADM] [480p HEVC AAC,AAC,AAC].mkv" "/movies/Blade Runner (1982)/Blade Runner (1982) [EE by ADM] [480p HEVC AAC,AAC,AAC].mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -317,8 +317,8 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) [1080p] Blu-ray.x264.DTS.mkv", "/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) [1080p] Blu-ray.x264.DTS.mkv",
@"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) [2160p] Blu-ray.x265.AAC.mkv" "/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) [2160p] Blu-ray.x265.AAC.mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -334,12 +334,12 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Theatrical Release.mkv", "/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Theatrical Release.mkv",
@"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Directors Cut.mkv", "/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Directors Cut.mkv",
@"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p.mkv", "/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p.mkv",
@"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 2160p.mkv", "/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 2160p.mkv",
@"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 720p.mkv", "/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 720p.mkv",
@"/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016).mkv", "/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016).mkv",
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -361,8 +361,8 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/movies/John Wick - Kapitel 3 (2019) [imdbid=tt6146586]/John Wick - Kapitel 3 (2019) [imdbid=tt6146586] - Version 1.mkv", "/movies/John Wick - Kapitel 3 (2019) [imdbid=tt6146586]/John Wick - Kapitel 3 (2019) [imdbid=tt6146586] - Version 1.mkv",
@"/movies/John Wick - Kapitel 3 (2019) [imdbid=tt6146586]/John Wick - Kapitel 3 (2019) [imdbid=tt6146586] - Version 2.mkv" "/movies/John Wick - Kapitel 3 (2019) [imdbid=tt6146586]/John Wick - Kapitel 3 (2019) [imdbid=tt6146586] - Version 2.mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -378,8 +378,8 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/movies/John Wick - Chapter 3 (2019)/John Wick - Chapter 3 (2019) [Version 1].mkv", "/movies/John Wick - Chapter 3 (2019)/John Wick - Chapter 3 (2019) [Version 1].mkv",
@"/movies/John Wick - Chapter 3 (2019)/John Wick - Chapter 3 (2019) [Version 2.mkv" "/movies/John Wick - Chapter 3 (2019)/John Wick - Chapter 3 (2019) [Version 2.mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(

@ -384,8 +384,8 @@ namespace Jellyfin.Naming.Tests.Video
// No stacking here because there is no part/disc/etc // No stacking here because there is no part/disc/etc
var files = new[] var files = new[]
{ {
@"M:/Movies (DVD)/Movies (Musical)/The Sound of Music/The Sound of Music (1965) (Disc 01)", "M:/Movies (DVD)/Movies (Musical)/The Sound of Music/The Sound of Music (1965) (Disc 01)",
@"M:/Movies (DVD)/Movies (Musical)/The Sound of Music/The Sound of Music (1965) (Disc 02)" "M:/Movies (DVD)/Movies (Musical)/The Sound of Music/The Sound of Music (1965) (Disc 02)"
}; };
var result = StackResolver.ResolveDirectories(files, _namingOptions).ToList(); var result = StackResolver.ResolveDirectories(files, _namingOptions).ToList();

@ -29,7 +29,7 @@ namespace Jellyfin.Naming.Tests.Video
[Fact] [Fact]
public void TestStubName() public void TestStubName()
{ {
var result = VideoResolver.ResolveFile(@"C:/Users/media/Desktop/Video Test/Movies/Oblivion/Oblivion.dvd.disc", _namingOptions); var result = VideoResolver.ResolveFile("C:/Users/media/Desktop/Video Test/Movies/Oblivion/Oblivion.dvd.disc", _namingOptions);
Assert.Equal("Oblivion", result?.Name); Assert.Equal("Oblivion", result?.Name);
} }

@ -200,8 +200,8 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"M:/Movies (DVD)/Movies (Musical)/Sound of Music (1965)/Sound of Music Disc 1", "M:/Movies (DVD)/Movies (Musical)/Sound of Music (1965)/Sound of Music Disc 1",
@"M:/Movies (DVD)/Movies (Musical)/Sound of Music (1965)/Sound of Music Disc 2" "M:/Movies (DVD)/Movies (Musical)/Sound of Music (1965)/Sound of Music Disc 2"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -217,8 +217,8 @@ namespace Jellyfin.Naming.Tests.Video
// These should be considered separate, unrelated videos // These should be considered separate, unrelated videos
var files = new[] var files = new[]
{ {
@"My movie #1.mp4", "My movie #1.mp4",
@"My movie #2.mp4" "My movie #2.mp4"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -233,10 +233,10 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"No (2012) part1.mp4", "No (2012) part1.mp4",
@"No (2012) part2.mp4", "No (2012) part2.mp4",
@"No (2012) part1-trailer.mp4", "No (2012) part1-trailer.mp4",
@"No (2012)-trailer.mp4" "No (2012)-trailer.mp4"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -254,10 +254,10 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/Movies/Top Gun (1984)/movie.mp4", "/Movies/Top Gun (1984)/movie.mp4",
@"/Movies/Top Gun (1984)/Top Gun (1984)-trailer.mp4", "/Movies/Top Gun (1984)/Top Gun (1984)-trailer.mp4",
@"/Movies/Top Gun (1984)/Top Gun (1984)-trailer2.mp4", "/Movies/Top Gun (1984)/Top Gun (1984)-trailer2.mp4",
@"/Movies/trailer.mp4" "/Movies/trailer.mp4"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -276,10 +276,10 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/MCFAMILY-PC/Private3$/Heterosexual/Breast In Class 2 Counterfeit Racks (2011)/Breast In Class 2 Counterfeit Racks (2011) Disc 1 cd1.avi", "/MCFAMILY-PC/Private3$/Heterosexual/Breast In Class 2 Counterfeit Racks (2011)/Breast In Class 2 Counterfeit Racks (2011) Disc 1 cd1.avi",
@"/MCFAMILY-PC/Private3$/Heterosexual/Breast In Class 2 Counterfeit Racks (2011)/Breast In Class 2 Counterfeit Racks (2011) Disc 1 cd2.avi", "/MCFAMILY-PC/Private3$/Heterosexual/Breast In Class 2 Counterfeit Racks (2011)/Breast In Class 2 Counterfeit Racks (2011) Disc 1 cd2.avi",
@"/MCFAMILY-PC/Private3$/Heterosexual/Breast In Class 2 Counterfeit Racks (2011)/Breast In Class 2 Disc 2 cd1.avi", "/MCFAMILY-PC/Private3$/Heterosexual/Breast In Class 2 Counterfeit Racks (2011)/Breast In Class 2 Disc 2 cd1.avi",
@"/MCFAMILY-PC/Private3$/Heterosexual/Breast In Class 2 Counterfeit Racks (2011)/Breast In Class 2 Disc 2 cd2.avi" "/MCFAMILY-PC/Private3$/Heterosexual/Breast In Class 2 Counterfeit Racks (2011)/Breast In Class 2 Disc 2 cd2.avi"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -294,7 +294,7 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/nas-markrobbo78/Videos/INDEX HTPC/Movies/Watched/3 - ACTION/Argo (2012)/movie.mkv" "/nas-markrobbo78/Videos/INDEX HTPC/Movies/Watched/3 - ACTION/Argo (2012)/movie.mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -309,7 +309,7 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"The Colony.mkv" "The Colony.mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -324,8 +324,8 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"Four Sisters and a Wedding - A.avi", "Four Sisters and a Wedding - A.avi",
@"Four Sisters and a Wedding - B.avi" "Four Sisters and a Wedding - B.avi"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -342,8 +342,8 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"Four Rooms - A.avi", "Four Rooms - A.avi",
@"Four Rooms - A.mp4" "Four Rooms - A.mp4"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -358,8 +358,8 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/Server/Despicable Me/Despicable Me (2010).mkv", "/Server/Despicable Me/Despicable Me (2010).mkv",
@"/Server/Despicable Me/trailer.mkv" "/Server/Despicable Me/trailer.mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -376,8 +376,8 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/Server/Despicable Me/Despicable Me (2010).mkv", "/Server/Despicable Me/Despicable Me (2010).mkv",
@"/Server/Despicable Me/trailers/some title.mkv" "/Server/Despicable Me/trailers/some title.mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(
@ -394,8 +394,8 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var files = new[] var files = new[]
{ {
@"/Movies/Despicable Me/Despicable Me.mkv", "/Movies/Despicable Me/Despicable Me.mkv",
@"/Movies/Despicable Me/trailers/trailer.mkv" "/Movies/Despicable Me/trailers/trailer.mkv"
}; };
var result = VideoListResolver.Resolve( var result = VideoListResolver.Resolve(

@ -15,26 +15,26 @@ namespace Jellyfin.Naming.Tests.Video
var data = new TheoryData<VideoFileInfo>(); var data = new TheoryData<VideoFileInfo>();
data.Add( data.Add(
new VideoFileInfo( new VideoFileInfo(
path: @"/server/Movies/7 Psychos.mkv/7 Psychos.mkv", path: "/server/Movies/7 Psychos.mkv/7 Psychos.mkv",
container: "mkv", container: "mkv",
name: "7 Psychos")); name: "7 Psychos"));
data.Add( data.Add(
new VideoFileInfo( new VideoFileInfo(
path: @"/server/Movies/3 days to kill (2005)/3 days to kill (2005).mkv", path: "/server/Movies/3 days to kill (2005)/3 days to kill (2005).mkv",
container: "mkv", container: "mkv",
name: "3 days to kill", name: "3 days to kill",
year: 2005)); year: 2005));
data.Add( data.Add(
new VideoFileInfo( new VideoFileInfo(
path: @"/server/Movies/American Psycho/American.Psycho.mkv", path: "/server/Movies/American Psycho/American.Psycho.mkv",
container: "mkv", container: "mkv",
name: "American.Psycho")); name: "American.Psycho"));
data.Add( data.Add(
new VideoFileInfo( new VideoFileInfo(
path: @"/server/Movies/brave (2007)/brave (2006).3d.sbs.mkv", path: "/server/Movies/brave (2007)/brave (2006).3d.sbs.mkv",
container: "mkv", container: "mkv",
name: "brave", name: "brave",
year: 2006, year: 2006,
@ -43,14 +43,14 @@ namespace Jellyfin.Naming.Tests.Video
data.Add( data.Add(
new VideoFileInfo( new VideoFileInfo(
path: @"/server/Movies/300 (2007)/300 (2006).3d1.sbas.mkv", path: "/server/Movies/300 (2007)/300 (2006).3d1.sbas.mkv",
container: "mkv", container: "mkv",
name: "300", name: "300",
year: 2006)); year: 2006));
data.Add( data.Add(
new VideoFileInfo( new VideoFileInfo(
path: @"/server/Movies/300 (2007)/300 (2006).3d.sbs.mkv", path: "/server/Movies/300 (2007)/300 (2006).3d.sbs.mkv",
container: "mkv", container: "mkv",
name: "300", name: "300",
year: 2006, year: 2006,
@ -59,7 +59,7 @@ namespace Jellyfin.Naming.Tests.Video
data.Add( data.Add(
new VideoFileInfo( new VideoFileInfo(
path: @"/server/Movies/brave (2007)/brave (2006)-trailer.bluray.disc", path: "/server/Movies/brave (2007)/brave (2006)-trailer.bluray.disc",
container: "disc", container: "disc",
name: "brave", name: "brave",
year: 2006, year: 2006,
@ -68,7 +68,7 @@ namespace Jellyfin.Naming.Tests.Video
data.Add( data.Add(
new VideoFileInfo( new VideoFileInfo(
path: @"/server/Movies/300 (2007)/300 (2006)-trailer.bluray.disc", path: "/server/Movies/300 (2007)/300 (2006)-trailer.bluray.disc",
container: "disc", container: "disc",
name: "300", name: "300",
year: 2006, year: 2006,
@ -77,7 +77,7 @@ namespace Jellyfin.Naming.Tests.Video
data.Add( data.Add(
new VideoFileInfo( new VideoFileInfo(
path: @"/server/Movies/Brave (2007)/Brave (2006).bluray.disc", path: "/server/Movies/Brave (2007)/Brave (2006).bluray.disc",
container: "disc", container: "disc",
name: "Brave", name: "Brave",
year: 2006, year: 2006,
@ -86,7 +86,7 @@ namespace Jellyfin.Naming.Tests.Video
data.Add( data.Add(
new VideoFileInfo( new VideoFileInfo(
path: @"/server/Movies/300 (2007)/300 (2006).bluray.disc", path: "/server/Movies/300 (2007)/300 (2006).bluray.disc",
container: "disc", container: "disc",
name: "300", name: "300",
year: 2006, year: 2006,
@ -95,7 +95,7 @@ namespace Jellyfin.Naming.Tests.Video
data.Add( data.Add(
new VideoFileInfo( new VideoFileInfo(
path: @"/server/Movies/300 (2007)/300 (2006)-trailer.mkv", path: "/server/Movies/300 (2007)/300 (2006)-trailer.mkv",
container: "mkv", container: "mkv",
name: "300", name: "300",
year: 2006, year: 2006,
@ -103,7 +103,7 @@ namespace Jellyfin.Naming.Tests.Video
data.Add( data.Add(
new VideoFileInfo( new VideoFileInfo(
path: @"/server/Movies/Brave (2007)/Brave (2006)-trailer.mkv", path: "/server/Movies/Brave (2007)/Brave (2006)-trailer.mkv",
container: "mkv", container: "mkv",
name: "Brave", name: "Brave",
year: 2006, year: 2006,
@ -111,28 +111,28 @@ namespace Jellyfin.Naming.Tests.Video
data.Add( data.Add(
new VideoFileInfo( new VideoFileInfo(
path: @"/server/Movies/300 (2007)/300 (2006).mkv", path: "/server/Movies/300 (2007)/300 (2006).mkv",
container: "mkv", container: "mkv",
name: "300", name: "300",
year: 2006)); year: 2006));
data.Add( data.Add(
new VideoFileInfo( new VideoFileInfo(
path: @"/server/Movies/Bad Boys (1995)/Bad Boys (1995).mkv", path: "/server/Movies/Bad Boys (1995)/Bad Boys (1995).mkv",
container: "mkv", container: "mkv",
name: "Bad Boys", name: "Bad Boys",
year: 1995)); year: 1995));
data.Add( data.Add(
new VideoFileInfo( new VideoFileInfo(
path: @"/server/Movies/Brave (2007)/Brave (2006).mkv", path: "/server/Movies/Brave (2007)/Brave (2006).mkv",
container: "mkv", container: "mkv",
name: "Brave", name: "Brave",
year: 2006)); year: 2006));
data.Add( data.Add(
new VideoFileInfo( new VideoFileInfo(
path: @"/server/Movies/Rain Man 1988 REMASTERED 1080p BluRay x264 AAC - JEFF/Rain Man 1988 REMASTERED 1080p BluRay x264 AAC - JEFF.mp4", path: "/server/Movies/Rain Man 1988 REMASTERED 1080p BluRay x264 AAC - JEFF/Rain Man 1988 REMASTERED 1080p BluRay x264 AAC - JEFF.mp4",
container: "mp4", container: "mp4",
name: "Rain Man", name: "Rain Man",
year: 1988)); year: 1988));
@ -174,8 +174,8 @@ namespace Jellyfin.Naming.Tests.Video
{ {
var paths = new[] var paths = new[]
{ {
@"/Server/Iron Man", "/Server/Iron Man",
@"Batman", "Batman",
string.Empty string.Empty
}; };

@ -352,11 +352,11 @@ namespace Jellyfin.Providers.Tests.Manager
{ {
if (forceRefresh) if (forceRefresh)
{ {
Assert.Matches(@"image url [0-9]", image.Path); Assert.Matches("image url [0-9]", image.Path);
} }
else else
{ {
Assert.DoesNotMatch(@"image url [0-9]", image.Path); Assert.DoesNotMatch("image url [0-9]", image.Path);
} }
} }
} }

@ -29,7 +29,7 @@ public class MediaInfoResolverTests
public const string VideoDirectoryPath = "Test Data/Video"; public const string VideoDirectoryPath = "Test Data/Video";
public const string VideoDirectoryRegex = @"Test Data[/\\]Video"; public const string VideoDirectoryRegex = @"Test Data[/\\]Video";
public const string MetadataDirectoryPath = "library/00/00000000000000000000000000000000"; public const string MetadataDirectoryPath = "library/00/00000000000000000000000000000000";
public const string MetadataDirectoryRegex = @"library.*"; public const string MetadataDirectoryRegex = "library.*";
private readonly ILocalizationManager _localizationManager; private readonly ILocalizationManager _localizationManager;
private readonly MediaInfoResolver _subtitleResolver; private readonly MediaInfoResolver _subtitleResolver;
@ -49,7 +49,7 @@ public class MediaInfoResolverTests
var englishCultureDto = new CultureDto("English", "English", "en", new[] { "eng" }); var englishCultureDto = new CultureDto("English", "English", "en", new[] { "eng" });
var localizationManager = new Mock<ILocalizationManager>(MockBehavior.Loose); var localizationManager = new Mock<ILocalizationManager>(MockBehavior.Loose);
localizationManager.Setup(lm => lm.FindLanguageInfo(It.IsRegex(@"en.*", RegexOptions.IgnoreCase))) localizationManager.Setup(lm => lm.FindLanguageInfo(It.IsRegex("en.*", RegexOptions.IgnoreCase)))
.Returns(englishCultureDto); .Returns(englishCultureDto);
_localizationManager = localizationManager.Object; _localizationManager = localizationManager.Object;
@ -79,7 +79,7 @@ public class MediaInfoResolverTests
{ {
// need a media source manager capable of returning something other than file protocol // need a media source manager capable of returning something other than file protocol
var mediaSourceManager = new Mock<IMediaSourceManager>(); var mediaSourceManager = new Mock<IMediaSourceManager>();
mediaSourceManager.Setup(m => m.GetPathProtocol(It.IsRegex(@"http.*"))) mediaSourceManager.Setup(m => m.GetPathProtocol(It.IsRegex("http.*")))
.Returns(MediaProtocol.Http); .Returns(MediaProtocol.Http);
BaseItem.MediaSourceManager = mediaSourceManager.Object; BaseItem.MediaSourceManager = mediaSourceManager.Object;
@ -186,7 +186,7 @@ public class MediaInfoResolverTests
{ {
// need a media source manager capable of returning something other than file protocol // need a media source manager capable of returning something other than file protocol
var mediaSourceManager = new Mock<IMediaSourceManager>(); var mediaSourceManager = new Mock<IMediaSourceManager>();
mediaSourceManager.Setup(m => m.GetPathProtocol(It.IsRegex(@"http.*"))) mediaSourceManager.Setup(m => m.GetPathProtocol(It.IsRegex("http.*")))
.Returns(MediaProtocol.Http); .Returns(MediaProtocol.Http);
BaseItem.MediaSourceManager = mediaSourceManager.Object; BaseItem.MediaSourceManager = mediaSourceManager.Object;

@ -48,10 +48,10 @@ namespace Jellyfin.Server.Implementations.Tests.Library
[InlineData("C:/Users/jeff/myfile.mkv", "C:/Users/jeff", "/home/jeff", "/home/jeff/myfile.mkv")] [InlineData("C:/Users/jeff/myfile.mkv", "C:/Users/jeff", "/home/jeff", "/home/jeff/myfile.mkv")]
[InlineData("C:/Users/jeff/myfile.mkv", "C:/Users/jeff/", "/home/jeff", "/home/jeff/myfile.mkv")] [InlineData("C:/Users/jeff/myfile.mkv", "C:/Users/jeff/", "/home/jeff", "/home/jeff/myfile.mkv")]
[InlineData("/home/jeff/music/jeff's band/consistently inconsistent.mp3", "/home/jeff/music/jeff's band", "/home/not jeff", "/home/not jeff/consistently inconsistent.mp3")] [InlineData("/home/jeff/music/jeff's band/consistently inconsistent.mp3", "/home/jeff/music/jeff's band", "/home/not jeff", "/home/not jeff/consistently inconsistent.mp3")]
[InlineData("C:\\Users\\jeff\\myfile.mkv", "C:\\Users/jeff", "/home/jeff", "/home/jeff/myfile.mkv")] [InlineData(@"C:\Users\jeff\myfile.mkv", "C:\\Users/jeff", "/home/jeff", "/home/jeff/myfile.mkv")]
[InlineData("C:\\Users\\jeff\\myfile.mkv", "C:\\Users/jeff", "/home/jeff/", "/home/jeff/myfile.mkv")] [InlineData(@"C:\Users\jeff\myfile.mkv", "C:\\Users/jeff", "/home/jeff/", "/home/jeff/myfile.mkv")]
[InlineData("C:\\Users\\jeff\\myfile.mkv", "C:\\Users/jeff/", "/home/jeff/", "/home/jeff/myfile.mkv")] [InlineData(@"C:\Users\jeff\myfile.mkv", "C:\\Users/jeff/", "/home/jeff/", "/home/jeff/myfile.mkv")]
[InlineData("C:\\Users\\jeff\\myfile.mkv", "C:\\Users/jeff/", "/", "/myfile.mkv")] [InlineData(@"C:\Users\jeff\myfile.mkv", "C:\\Users/jeff/", "/", "/myfile.mkv")]
[InlineData("/o", "/o", "/s", "/s")] // regression test for #5977 [InlineData("/o", "/o", "/s", "/s")] // regression test for #5977
public void TryReplaceSubPath_ValidArgs_Correct(string path, string subPath, string newSubPath, string? expectedResult) public void TryReplaceSubPath_ValidArgs_Correct(string path, string subPath, string newSubPath, string? expectedResult)
{ {
@ -78,10 +78,10 @@ namespace Jellyfin.Server.Implementations.Tests.Library
[Theory] [Theory]
[InlineData(null, '/', null)] [InlineData(null, '/', null)]
[InlineData(null, '\\', null)] [InlineData(null, '\\', null)]
[InlineData("/home/jeff/myfile.mkv", '\\', "\\home\\jeff\\myfile.mkv")] [InlineData("/home/jeff/myfile.mkv", '\\', @"\home\jeff\myfile.mkv")]
[InlineData("C:\\Users\\Jeff\\myfile.mkv", '/', "C:/Users/Jeff/myfile.mkv")] [InlineData(@"C:\Users\Jeff\myfile.mkv", '/', "C:/Users/Jeff/myfile.mkv")]
[InlineData("\\home/jeff\\myfile.mkv", '\\', "\\home\\jeff\\myfile.mkv")] [InlineData(@"\home/jeff\myfile.mkv", '\\', @"\home\jeff\myfile.mkv")]
[InlineData("\\home/jeff\\myfile.mkv", '/', "/home/jeff/myfile.mkv")] [InlineData(@"\home/jeff\myfile.mkv", '/', "/home/jeff/myfile.mkv")]
[InlineData("", '/', "")] [InlineData("", '/', "")]
public void NormalizePath_SpecifyingSeparator_Normalizes(string path, char separator, string expectedPath) public void NormalizePath_SpecifyingSeparator_Normalizes(string path, char separator, string expectedPath)
{ {
@ -90,8 +90,8 @@ namespace Jellyfin.Server.Implementations.Tests.Library
[Theory] [Theory]
[InlineData("/home/jeff/myfile.mkv")] [InlineData("/home/jeff/myfile.mkv")]
[InlineData("C:\\Users\\Jeff\\myfile.mkv")] [InlineData(@"C:\Users\Jeff\myfile.mkv")]
[InlineData("\\home/jeff\\myfile.mkv")] [InlineData(@"\home/jeff\myfile.mkv")]
public void NormalizePath_NoArgs_UsesDirectorySeparatorChar(string path) public void NormalizePath_NoArgs_UsesDirectorySeparatorChar(string path)
{ {
var separator = Path.DirectorySeparatorChar; var separator = Path.DirectorySeparatorChar;
@ -101,8 +101,8 @@ namespace Jellyfin.Server.Implementations.Tests.Library
[Theory] [Theory]
[InlineData("/home/jeff/myfile.mkv", '/')] [InlineData("/home/jeff/myfile.mkv", '/')]
[InlineData("C:\\Users\\Jeff\\myfile.mkv", '\\')] [InlineData(@"C:\Users\Jeff\myfile.mkv", '\\')]
[InlineData("\\home/jeff\\myfile.mkv", '/')] [InlineData(@"\home/jeff\myfile.mkv", '/')]
public void NormalizePath_OutVar_Correct(string path, char expectedSeparator) public void NormalizePath_OutVar_Correct(string path, char expectedSeparator)
{ {
var result = path.NormalizePath(out var separator); var result = path.NormalizePath(out var separator);

@ -119,8 +119,8 @@ namespace Jellyfin.Server.Implementations.Tests.Plugins
[InlineData("C:\\some.dll")] // Windows root path. [InlineData("C:\\some.dll")] // Windows root path.
[InlineData("test.txt")] // Not a DLL [InlineData("test.txt")] // Not a DLL
[InlineData(".././.././../some.dll")] // Traversal with current and parent [InlineData(".././.././../some.dll")] // Traversal with current and parent
[InlineData("..\\.\\..\\.\\..\\some.dll")] // Windows traversal with current and parent [InlineData(@"..\.\..\.\..\some.dll")] // Windows traversal with current and parent
[InlineData("\\\\network\\resource.dll")] // UNC Path [InlineData(@"\\network\resource.dll")] // UNC Path
[InlineData("https://jellyfin.org/some.dll")] // URL [InlineData("https://jellyfin.org/some.dll")] // URL
[InlineData("~/some.dll")] // Tilde poses a shell expansion risk, but is a valid path character. [InlineData("~/some.dll")] // Tilde poses a shell expansion risk, but is a valid path character.
public void Constructor_DiscoversUnsafePluginAssembly_Status_Malfunctioned(string unsafePath) public void Constructor_DiscoversUnsafePluginAssembly_Status_Malfunctioned(string unsafePath)
@ -191,13 +191,13 @@ namespace Jellyfin.Server.Implementations.Tests.Plugins
}; };
var metafilePath = Path.Combine(_pluginPath, "meta.json"); var metafilePath = Path.Combine(_pluginPath, "meta.json");
File.WriteAllText(metafilePath, JsonSerializer.Serialize(partial, _options)); await File.WriteAllTextAsync(metafilePath, JsonSerializer.Serialize(partial, _options));
var pluginManager = new PluginManager(new NullLogger<PluginManager>(), null!, null!, _tempPath, new Version(1, 0)); var pluginManager = new PluginManager(new NullLogger<PluginManager>(), null!, null!, _tempPath, new Version(1, 0));
await pluginManager.PopulateManifest(packageInfo, new Version(1, 0), _pluginPath, PluginStatus.Active); await pluginManager.PopulateManifest(packageInfo, new Version(1, 0), _pluginPath, PluginStatus.Active);
var resultBytes = File.ReadAllBytes(metafilePath); var resultBytes = await File.ReadAllBytesAsync(metafilePath);
var result = JsonSerializer.Deserialize<PluginManifest>(resultBytes, _options); var result = JsonSerializer.Deserialize<PluginManifest>(resultBytes, _options);
Assert.NotNull(result); Assert.NotNull(result);
@ -231,7 +231,7 @@ namespace Jellyfin.Server.Implementations.Tests.Plugins
await pluginManager.PopulateManifest(packageInfo, new Version(1, 0), _pluginPath, PluginStatus.Active); await pluginManager.PopulateManifest(packageInfo, new Version(1, 0), _pluginPath, PluginStatus.Active);
var metafilePath = Path.Combine(_pluginPath, "meta.json"); var metafilePath = Path.Combine(_pluginPath, "meta.json");
var resultBytes = File.ReadAllBytes(metafilePath); var resultBytes = await File.ReadAllBytesAsync(metafilePath);
var result = JsonSerializer.Deserialize<PluginManifest>(resultBytes, _options); var result = JsonSerializer.Deserialize<PluginManifest>(resultBytes, _options);
Assert.NotNull(result); Assert.NotNull(result);
@ -251,13 +251,13 @@ namespace Jellyfin.Server.Implementations.Tests.Plugins
}; };
var metafilePath = Path.Combine(_pluginPath, "meta.json"); var metafilePath = Path.Combine(_pluginPath, "meta.json");
File.WriteAllText(metafilePath, JsonSerializer.Serialize(partial, _options)); await File.WriteAllTextAsync(metafilePath, JsonSerializer.Serialize(partial, _options));
var pluginManager = new PluginManager(new NullLogger<PluginManager>(), null!, null!, _tempPath, new Version(1, 0)); var pluginManager = new PluginManager(new NullLogger<PluginManager>(), null!, null!, _tempPath, new Version(1, 0));
await pluginManager.PopulateManifest(packageInfo, new Version(1, 0), _pluginPath, PluginStatus.Active); await pluginManager.PopulateManifest(packageInfo, new Version(1, 0), _pluginPath, PluginStatus.Active);
var resultBytes = File.ReadAllBytes(metafilePath); var resultBytes = await File.ReadAllBytesAsync(metafilePath);
var result = JsonSerializer.Deserialize<PluginManifest>(resultBytes, _options); var result = JsonSerializer.Deserialize<PluginManifest>(resultBytes, _options);
Assert.NotNull(result); Assert.NotNull(result);
@ -277,13 +277,13 @@ namespace Jellyfin.Server.Implementations.Tests.Plugins
}; };
var metafilePath = Path.Combine(_pluginPath, "meta.json"); var metafilePath = Path.Combine(_pluginPath, "meta.json");
File.WriteAllText(metafilePath, JsonSerializer.Serialize(partial, _options)); await File.WriteAllTextAsync(metafilePath, JsonSerializer.Serialize(partial, _options));
var pluginManager = new PluginManager(new NullLogger<PluginManager>(), null!, null!, _tempPath, new Version(1, 0)); var pluginManager = new PluginManager(new NullLogger<PluginManager>(), null!, null!, _tempPath, new Version(1, 0));
await pluginManager.PopulateManifest(packageInfo, new Version(1, 0), _pluginPath, PluginStatus.Active); await pluginManager.PopulateManifest(packageInfo, new Version(1, 0), _pluginPath, PluginStatus.Active);
var resultBytes = File.ReadAllBytes(metafilePath); var resultBytes = await File.ReadAllBytesAsync(metafilePath);
var result = JsonSerializer.Deserialize<PluginManifest>(resultBytes, _options); var result = JsonSerializer.Deserialize<PluginManifest>(resultBytes, _options);
Assert.NotNull(result); Assert.NotNull(result);

@ -60,7 +60,7 @@ namespace Jellyfin.XbmcMetadata.Tests.Parsers
{ {
Exists = true, Exists = true,
FullName = OperatingSystem.IsWindows() ? FullName = OperatingSystem.IsWindows() ?
"C:\\media\\movies\\Justice League (2017).jpg" @"C:\media\movies\Justice League (2017).jpg"
: "/media/movies/Justice League (2017).jpg" : "/media/movies/Justice League (2017).jpg"
}; };
directoryService.Setup(x => x.GetFile(_localImageFileMetadata.FullName)) directoryService.Setup(x => x.GetFile(_localImageFileMetadata.FullName))

Loading…
Cancel
Save