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

pull/10427/head
Bond-009 7 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);
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))
{
return info.Value.Split(':');
}
if (info is not null && !string.IsNullOrWhiteSpace(info.Value))
{
return info.Value.Split(':');
}
return new string[4];
@ -1139,7 +1136,6 @@ namespace Emby.Dlna.PlayTo
return new Device(deviceProperties, httpClientFactory, logger);
}
#nullable enable
private static DeviceIcon CreateIcon(XElement element)
{
ArgumentNullException.ThrowIfNull(element);

@ -39,9 +39,9 @@ namespace Emby.Dlna.PlayTo
private readonly IMediaSourceManager _mediaSourceManager;
private readonly IMediaEncoder _mediaEncoder;
private readonly SemaphoreSlim _sessionLock = new SemaphoreSlim(1, 1);
private readonly CancellationTokenSource _disposeCancellationTokenSource = new CancellationTokenSource();
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)
{

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

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

@ -1159,7 +1159,7 @@ namespace Emby.Server.Implementations.Channels
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)

@ -3540,10 +3540,7 @@ namespace Emby.Server.Implementations.Data
.Append(paramName)
.Append("))) OR ");
if (statement is not null)
{
statement.TryBind(paramName, query.PersonIds[i]);
}
statement?.TryBind(paramName, query.PersonIds[i]);
}
clauseBuilder.Length -= Or.Length;
@ -4382,7 +4379,7 @@ namespace Emby.Server.Implementations.Data
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) + ")");

@ -39,9 +39,9 @@ namespace Emby.Server.Implementations.EntryPoints
/// <summary>
/// The UDP server.
/// </summary>
private List<UdpServer> _udpServers;
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private bool _disposed = false;
private readonly List<UdpServer> _udpServers;
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private bool _disposed;
/// <summary>
/// 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.Outbound;
using MediaBrowser.Model.Session;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.HttpServer

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

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

@ -2850,7 +2850,7 @@ namespace Emby.Server.Implementations.Library
{
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);

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

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

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

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

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

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

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

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

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

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

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

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text.RegularExpressions;
@ -204,7 +203,7 @@ public static partial class NetworkExtensions
{
var ipBlock = splitString.Current;
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;
}

@ -1,7 +1,6 @@
using System.Globalization;
using System.Threading.Tasks;
using Jellyfin.Data.Entities;
using Jellyfin.Data.Events;
using MediaBrowser.Controller.Events;
using MediaBrowser.Controller.Events.Authentication;
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.Server.Implementations.Events.Consumers.Library;
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 @
// 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 ( )
[GeneratedRegex("^[\\w\\ \\-'._@]+$")]
[GeneratedRegex(@"^[\w\ \-'._@]+$")]
private static partial Regex ValidUsernameRegex();
/// <inheritdoc/>

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

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

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

@ -95,10 +95,7 @@ namespace MediaBrowser.Controller.Entities
}
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++)
{
await actionBlock.SendAsync(i).ConfigureAwait(false);
await actionBlock.SendAsync(i, cancellationToken).ConfigureAwait(false);
}
actionBlock.Complete();

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

@ -1745,11 +1745,9 @@ namespace MediaBrowser.Controller.MediaEncoding
// Values 0-3, 0 being highest quality but slower
var profileScore = 0;
string crf;
var qmin = "0";
var qmax = "50";
crf = "10";
var crf = "10";
if (isVc1)
{
@ -2947,7 +2945,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return string.Format(
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,
maxHeightParam,
scaleVal);
@ -2989,7 +2987,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return string.Format(
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,
scaleVal);
}
@ -3001,7 +2999,7 @@ namespace MediaBrowser.Controller.MediaEncoding
return string.Format(
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,
scaleVal);
}
@ -3021,19 +3019,19 @@ namespace MediaBrowser.Controller.MediaEncoding
switch (threedFormat.Value)
{
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.
break;
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.
break;
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
break;
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
break;
default:

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

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

@ -8,7 +8,7 @@ namespace MediaBrowser.MediaEncoding.BdInfo;
/// </summary>
public class BdInfoFileInfo : BDInfo.IO.IFileInfo
{
private FileSystemMetadata _impl;
private readonly FileSystemMetadata _impl;
/// <summary>
/// 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 found = Regex
.Matches(output, @"^\s\S{6}\s(?<codec>[\w|-]+)\s+.+$", RegexOptions.Multiline)
var found = CodecRegex()
.Matches(output)
.Select(x => x.Groups["codec"].Value)
.Where(x => required.Contains(x));
@ -527,8 +527,8 @@ namespace MediaBrowser.MediaEncoding.Encoder
return Enumerable.Empty<string>();
}
var found = Regex
.Matches(output, @"^\s\S{3}\s(?<filter>[\w|-]+)\s+.+$", RegexOptions.Multiline)
var found = FilterRegex()
.Matches(output)
.Select(x => x.Groups["filter"].Value)
.Where(x => _requiredFilters.Contains(x));
@ -582,5 +582,11 @@ namespace MediaBrowser.MediaEncoding.Encoder
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)
{
// 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
var validator = new EncoderValidator(_logger, _ffmpegPath);
@ -422,7 +422,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
if (request.MediaSource.AnalyzeDurationMs > 0)
{
analyzeDuration = "-analyzeduration " + (request.MediaSource.AnalyzeDurationMs * 1000).ToString();
analyzeDuration = "-analyzeduration " + (request.MediaSource.AnalyzeDurationMs * 1000);
}
else if (!string.IsNullOrEmpty(ffmpegAnalyzeDuration))
{
@ -623,9 +623,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
private string GetImageResolutionParameter()
{
string imageResolutionParameter;
imageResolutionParameter = _serverConfig.Configuration.ChapterImageResolution switch
var imageResolutionParameter = _serverConfig.Configuration.ChapterImageResolution switch
{
ImageResolution.P144 => "256x144",
ImageResolution.P240 => "426x240",
@ -670,13 +668,13 @@ namespace MediaBrowser.MediaEncoding.Encoder
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.
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
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
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
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"
};
@ -852,7 +850,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
// https://ffmpeg.org/ffmpeg-filters.html#Notes-on-filtergraph-escaping
// We need to double escape
return path.Replace('\\', '/').Replace(":", "\\:", StringComparison.Ordinal).Replace("'", "'\\\\\\''", StringComparison.Ordinal);
return path.Replace('\\', '/').Replace(":", "\\:", StringComparison.Ordinal).Replace("'", @"'\\\''", StringComparison.Ordinal);
}
/// <inheritdoc />

@ -22,7 +22,7 @@ namespace MediaBrowser.MediaEncoding.Probing
/// <summary>
/// Class responsible for normalizing FFprobe output.
/// </summary>
public class ProbeResultNormalizer
public partial class ProbeResultNormalizer
{
// When extracting subtitles, the maximum length to consider (to avoid invalid filenames)
private const int MaxSubtitleDescriptionExtractionLength = 100;
@ -31,8 +31,6 @@ namespace MediaBrowser.MediaEncoding.Probing
private readonly char[] _nameDelimiters = { '/', '|', ';', '\\' };
private static readonly Regex _performerPattern = new(@"(?<name>.*) \((?<instrument>.*)\)");
private readonly ILogger _logger;
private readonly ILocalizationManager _localization;
@ -1215,7 +1213,7 @@ namespace MediaBrowser.MediaEncoding.Probing
{
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 (match.Success)
@ -1654,5 +1652,8 @@ namespace MediaBrowser.MediaEncoding.Probing
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 audioStreamFailureReasons = AggregateFailureConditions(mediaSource, profile, "VideoAudioCodecProfile", audioFailureConditions);
if (audioStream?.IsExternal == true)
if (audioStream.IsExternal == true)
{
audioStreamFailureReasons |= TranscodeReason.AudioIsExternal;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -419,7 +419,7 @@ namespace Rssdp.Infrastructure
{
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)
{
@ -508,22 +508,16 @@ namespace Rssdp.Infrastructure
}
var handlers = RequestReceived;
if (handlers is not null)
{
handlers(this, new RequestReceivedEventArgs(data, remoteEndPoint, receivedOnlocalIPAddress));
}
handlers?.Invoke(this, new RequestReceivedEventArgs(data, remoteEndPoint, receivedOnlocalIPAddress));
}
private void OnResponseReceived(HttpResponseMessage data, IPEndPoint endPoint, IPAddress localIPAddress)
{
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)
{
var handlers = this.DeviceAdded;
if (handlers != null)
{
handlers(this, new DeviceEventArgs(device));
}
handlers?.Invoke(this, new DeviceEventArgs(device));
}
/// <summary>
@ -352,10 +349,7 @@ namespace Rssdp
protected virtual void OnDeviceRemoved(SsdpEmbeddedDevice device)
{
var handlers = this.DeviceRemoved;
if (handlers != null)
{
handlers(this, new DeviceEventArgs(device));
}
handlers?.Invoke(this, new DeviceEventArgs(device));
}
}
}

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

@ -243,7 +243,7 @@ namespace Rssdp.Infrastructure
}
// 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.
IEnumerable<SsdpDevice> devices = null;
@ -281,7 +281,7 @@ namespace Rssdp.Infrastructure
}
}
}
});
}, cancellationToken);
}
private IEnumerable<SsdpDevice> GetAllDevicesAsFlatEnumerable()
@ -530,10 +530,7 @@ namespace Rssdp.Infrastructure
{
var timer = _RebroadcastAliveNotificationsTimer;
_RebroadcastAliveNotificationsTimer = null;
if (timer is not null)
{
timer.Dispose();
}
timer?.Dispose();
}
private TimeSpan GetMinimumNonZeroCacheLifetime()
@ -567,10 +564,7 @@ namespace Rssdp.Infrastructure
private void WriteTrace(string text)
{
if (LogFunction is not null)
{
LogFunction(text);
}
LogFunction?.Invoke(text);
// System.Diagnostics.Debug.WriteLine(text, "SSDP Publisher");
}

@ -14,18 +14,18 @@ namespace Jellyfin.Naming.Tests.AudioBook
data.Add(
new AudioBookFileInfo(
@"/server/AudioBooks/Larry Potter/Larry Potter.mp3",
"/server/AudioBooks/Larry Potter/Larry Potter.mp3",
"mp3"));
data.Add(
new AudioBookFileInfo(
@"/server/AudioBooks/Berry Potter/Chapter 1 .ogg",
"/server/AudioBooks/Berry Potter/Chapter 1 .ogg",
"ogg",
chapterNumber: 1));
data.Add(
new AudioBookFileInfo(
@"/server/AudioBooks/Nerry Potter/Part 3 - Chapter 2.mp3",
"/server/AudioBooks/Nerry Potter/Part 3 - Chapter 2.mp3",
"mp3",
chapterNumber: 2,
partNumber: 3));
@ -49,7 +49,7 @@ namespace Jellyfin.Naming.Tests.AudioBook
[Fact]
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);
}

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

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

@ -9,11 +9,11 @@ namespace Jellyfin.Naming.Tests.TV
private readonly EpisodeResolver _resolver = new EpisodeResolver(new NamingOptions());
[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/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/Jeopardy 2023 07 14 HDTV x264 AC3.mkv", "Jeopardy", 2023, 07, 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/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)]
// 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/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());
[Theory]
[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/02.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/The Simpsons - 02.avi")]
[InlineData(2, @"The Simpsons/The Simpsons - 02 Ep Name.avi")]
[InlineData(7, @"GJ Club (2013)/GJ Club - 07.mkv")]
[InlineData(17, @"Case Closed (1996-2007)/Case Closed - 317.mkv")]
[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/02.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/The Simpsons - 02.avi")]
[InlineData(2, "The Simpsons/The Simpsons - 02 Ep Name.avi")]
[InlineData(7, "GJ Club (2013)/GJ Club - 07.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(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/Foo s01x01", true, "Foo", 1, 1)]
[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 - S04E011", true, "Foo", 4, 11)]
[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\Foo-S01E01", true, "Foo", 1, 1)]
[InlineData(@"D:\media\Foo - S04E011", true, "Foo", 4, 11)]
[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("/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("/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());
[Theory]
[InlineData(@"Season 1/4x01 20 Hours in America (1).mkv", null)]
[InlineData(@"Season 1/01x02 blah.avi", null)]
[InlineData(@"Season 1/S01x02 blah.avi", null)]
[InlineData(@"Season 1/S01E02 blah.avi", null)]
[InlineData(@"Season 1/S01xE02 blah.avi", null)]
[InlineData(@"Season 1/seriesname 01x02 blah.avi", null)]
[InlineData(@"Season 1/seriesname S01x02 blah.avi", null)]
[InlineData(@"Season 1/seriesname S01E02 blah.avi", null)]
[InlineData(@"Season 1/seriesname S01xE02 blah.avi", 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/Elementary - 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/Elementary - 02x03-04-15 - 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/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/Elementary - 02x03x04x15 - Ep Name.mp4", 15)]
[InlineData(@"Season 1/Elementary - S01E23-E24-E26 - The Woman.mp4", 26)]
[InlineData(@"Season 1/S01E23-E24-E26 - The Woman.mp4", 26)]
[InlineData("Season 1/4x01 20 Hours in America (1).mkv", null)]
[InlineData("Season 1/01x02 blah.avi", null)]
[InlineData("Season 1/S01x02 blah.avi", null)]
[InlineData("Season 1/S01E02 blah.avi", null)]
[InlineData("Season 1/S01xE02 blah.avi", null)]
[InlineData("Season 1/seriesname 01x02 blah.avi", null)]
[InlineData("Season 1/seriesname S01x02 blah.avi", null)]
[InlineData("Season 1/seriesname S01E02 blah.avi", null)]
[InlineData("Season 1/seriesname S01xE02 blah.avi", 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/Elementary - 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/Elementary - 02x03-04-15 - 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/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/Elementary - 02x03x04x15 - Ep Name.mp4", 15)]
[InlineData("Season 1/Elementary - S01E23-E24-E26 - The Woman.mp4", 26)]
[InlineData("Season 1/S01E23-E24-E26 - The Woman.mp4", 26)]
// Four Digits seasons
[InlineData(@"Season 2009/2009x02 blah.avi", null)]
[InlineData(@"Season 2009/S2009x02 blah.avi", null)]
[InlineData(@"Season 2009/S2009E02 blah.avi", null)]
[InlineData(@"Season 2009/S2009xE02 blah.avi", null)]
[InlineData(@"Season 2009/seriesname 2009x02 blah.avi", null)]
[InlineData(@"Season 2009/seriesname S2009x02 blah.avi", null)]
[InlineData(@"Season 2009/seriesname S2009E02 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/2009x03 - 2009x04 - 2009x15 - 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/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/Elementary - 2009x03 - x04 - x15 - 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 - S2009E23-E24-E26 - The Woman.mp4", 26)]
[InlineData(@"Season 2009/S2009E23-E24-E26 - The Woman.mp4", 26)]
[InlineData("Season 2009/2009x02 blah.avi", null)]
[InlineData("Season 2009/S2009x02 blah.avi", null)]
[InlineData("Season 2009/S2009E02 blah.avi", null)]
[InlineData("Season 2009/S2009xE02 blah.avi", null)]
[InlineData("Season 2009/seriesname 2009x02 blah.avi", null)]
[InlineData("Season 2009/seriesname S2009x02 blah.avi", null)]
[InlineData("Season 2009/seriesname S2009E02 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/2009x03 - 2009x04 - 2009x15 - 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/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/Elementary - 2009x03 - x04 - x15 - 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 - S2009E23-E24-E26 - The Woman.mp4", 26)]
[InlineData("Season 2009/S2009E23-E24-E26 - The Woman.mp4", 26)]
// Without season number
[InlineData(@"Season 1/02 - blah.avi", null)]
[InlineData(@"Season 2/02 - blah 14 blah.avi", null)]
[InlineData(@"Season 1/02 - blah-02 a.avi", null)]
[InlineData(@"Season 2/02.avi", null)]
[InlineData(@"Season 1/02-03 - blah.avi", 3)]
[InlineData(@"Season 2/02-04 - blah 14 blah.avi", 4)]
[InlineData(@"Season 1/02-05 - blah-02 a.avi", 5)]
[InlineData(@"Season 2/02-04.avi", 4)]
[InlineData(@"Season 2 /[HorribleSubs] Hunter X Hunter - 136[720p].mkv", null)]
[InlineData("Season 1/02 - blah.avi", null)]
[InlineData("Season 2/02 - blah 14 blah.avi", null)]
[InlineData("Season 1/02 - blah-02 a.avi", null)]
[InlineData("Season 2/02.avi", null)]
[InlineData("Season 1/02-03 - blah.avi", 3)]
[InlineData("Season 2/02-04 - blah 14 blah.avi", 4)]
[InlineData("Season 1/02-05 - blah-02 a.avi", 5)]
[InlineData("Season 2/02-04.avi", 4)]
[InlineData("Season 2 /[HorribleSubs] Hunter X Hunter - 136[720p].mkv", null)]
// 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-720p.mkv", null)]
[InlineData(@"Season 1/series-s09e14-720i.mkv", null)]
[InlineData(@"Season 1/MOONLIGHTING_s01e01-e04.mkv", 4)]
[InlineData(@"Season 1/MOONLIGHTING_s01e01-e04", 4)]
[InlineData("Season 1/series-s09e14-1080p.mkv", null)]
[InlineData("Season 1/series-s09e14-720p.mkv", null)]
[InlineData("Season 1/series-s09e14-720i.mkv", null)]
[InlineData("Season 1/MOONLIGHTING_s01e01-e04.mkv", 4)]
[InlineData("Season 1/MOONLIGHTING_s01e01-e04", 4)]
public void TestGetEndingEpisodeNumberFromFile(string filename, int? endingEpisodeNumber)
{
var result = _episodePathParser.Parse(filename, false);

@ -6,23 +6,23 @@ namespace Jellyfin.Naming.Tests.TV
public class SeasonFolderTests
{
[Theory]
[InlineData(@"/Drive/Season 1", 1, true)]
[InlineData(@"/Drive/Season 2", 2, true)]
[InlineData(@"/Drive/Season 02", 2, true)]
[InlineData(@"/Drive/Seinfeld/S02", 2, true)]
[InlineData(@"/Drive/Seinfeld/2", 2, true)]
[InlineData(@"/Drive/Season 2009", 2009, true)]
[InlineData(@"/Drive/Season1", 1, true)]
[InlineData(@"The Wonder Years/The.Wonder.Years.S04.PDTV.x264-JCH", 4, true)]
[InlineData(@"/Drive/Season 7 (2016)", 7, false)]
[InlineData(@"/Drive/Staffel 7 (2016)", 7, false)]
[InlineData(@"/Drive/Stagione 7 (2016)", 7, false)]
[InlineData(@"/Drive/Season (8)", null, false)]
[InlineData(@"/Drive/3.Staffel", 3, 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/extras", 0, true)]
[InlineData(@"/Drive/specials", 0, true)]
[InlineData("/Drive/Season 1", 1, true)]
[InlineData("/Drive/Season 2", 2, true)]
[InlineData("/Drive/Season 02", 2, true)]
[InlineData("/Drive/Seinfeld/S02", 2, true)]
[InlineData("/Drive/Seinfeld/2", 2, true)]
[InlineData("/Drive/Season 2009", 2009, true)]
[InlineData("/Drive/Season1", 1, true)]
[InlineData("The Wonder Years/The.Wonder.Years.S04.PDTV.x264-JCH", 4, true)]
[InlineData("/Drive/Season 7 (2016)", 7, false)]
[InlineData("/Drive/Staffel 7 (2016)", 7, false)]
[InlineData("/Drive/Stagione 7 (2016)", 7, false)]
[InlineData("/Drive/Season (8)", null, false)]
[InlineData("/Drive/3.Staffel", 3, 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/extras", 0, true)]
[InlineData("/Drive/specials", 0, true)]
public void GetSeasonNumberFromPathTest(string path, int? seasonNumber, bool isSeasonDirectory)
{
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/S2009E23-E24-E26 - The Woman.mp4", 2009)]
[InlineData("Series/1-12 - The Woman.mp4", 1)]
[InlineData(@"Running Man/Running Man S2017E368.mkv", 2017)]
[InlineData(@"Case Closed (1996-2007)/Case Closed - 317.mkv", 3)]
[InlineData("Running Man/Running Man S2017E368.mkv", 2017)]
[InlineData("Case Closed (1996-2007)/Case Closed - 317.mkv", 3)]
// TODO: [InlineData(@"Seinfeld/Seinfeld 0807 The Checks.avi", 8)]
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/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(@"/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("/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("[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("Series/4-12 - The Woman.mp4", "", 4, 12, 12)]

@ -10,34 +10,34 @@ namespace Jellyfin.Naming.Tests.Video
private readonly NamingOptions _namingOptions = new NamingOptions();
[Theory]
[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 2001 (2013).mkv", "The Wolf of Wall Street 2001", 2013)]
[InlineData(@"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 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.2160p.bluray.x264-rough", "curse.of.chucky", 2013)]
[InlineData(@"/server/Movies/300 (2007)/300 (2006).bluray.disc", "300", 2006)]
[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 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(@"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 2001 (2006)", "300 2001", 2006)]
[InlineData(@"/server/Movies/300 (2007)/300 (2006)", "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(@"[rec].mkv", "[rec].mkv", null)]
[InlineData(@"St. Vincent (2014)", "St. Vincent", 2014)]
[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 2001 (2013).mkv", "The Wolf of Wall Street 2001", 2013)]
[InlineData("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 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.2160p.bluray.x264-rough", "curse.of.chucky", 2013)]
[InlineData("/server/Movies/300 (2007)/300 (2006).bluray.disc", "300", 2006)]
[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 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("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 2001 (2006)", "300 2001", 2006)]
[InlineData("/server/Movies/300 (2007)/300 (2006)", "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("[rec].mkv", "[rec].mkv", null)]
[InlineData("St. Vincent (2014)", "St. Vincent", 2014)]
[InlineData("Super movie(2009).mp4", "Super movie", 2009)]
[InlineData("Drug War 2013.mp4", "Drug War", 2013)]
[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("Maximum Ride - 2016 - WEBDL-1080p - x264 AC3.mkv", "Maximum Ride", 2016)]
// 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(@"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 20131209", "My Movie 20131209", null)]

@ -22,7 +22,7 @@ namespace Jellyfin.Naming.Tests.Video
[Fact]
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("Oblivion", result?.Name);

@ -15,10 +15,10 @@ namespace Jellyfin.Naming.Tests.Video
{
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-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 - 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 - [hsbs].mkv",
"/movies/X-Men Days of Future Past/X-Men Days of Future Past [hsbs].mkv"
};
var result = VideoListResolver.Resolve(
@ -34,10 +34,10 @@ namespace Jellyfin.Naming.Tests.Video
{
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-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].mp4"
"/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 - banana.mkv",
"/movies/X-Men Days of Future Past/X-Men Days of Future Past [banana].mp4"
};
var result = VideoListResolver.Resolve(
@ -54,8 +54,8 @@ namespace Jellyfin.Naming.Tests.Video
{
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) - 1929 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"
};
var result = VideoListResolver.Resolve(
@ -71,13 +71,13 @@ namespace Jellyfin.Naming.Tests.Video
{
var files = new[]
{
@"/movies/M/Movie 1.mkv",
@"/movies/M/Movie 2.mkv",
@"/movies/M/Movie 3.mkv",
@"/movies/M/Movie 4.mkv",
@"/movies/M/Movie 5.mkv",
@"/movies/M/Movie 6.mkv",
@"/movies/M/Movie 7.mkv"
"/movies/M/Movie 1.mkv",
"/movies/M/Movie 2.mkv",
"/movies/M/Movie 3.mkv",
"/movies/M/Movie 4.mkv",
"/movies/M/Movie 5.mkv",
"/movies/M/Movie 6.mkv",
"/movies/M/Movie 7.mkv"
};
var result = VideoListResolver.Resolve(
@ -93,14 +93,14 @@ namespace Jellyfin.Naming.Tests.Video
{
var files = new[]
{
@"/movies/Movie/Movie.mkv",
@"/movies/Movie/Movie-2.mkv",
@"/movies/Movie/Movie-3.mkv",
@"/movies/Movie/Movie-4.mkv",
@"/movies/Movie/Movie-5.mkv",
@"/movies/Movie/Movie-6.mkv",
@"/movies/Movie/Movie-7.mkv",
@"/movies/Movie/Movie-8.mkv"
"/movies/Movie/Movie.mkv",
"/movies/Movie/Movie-2.mkv",
"/movies/Movie/Movie-3.mkv",
"/movies/Movie/Movie-4.mkv",
"/movies/Movie/Movie-5.mkv",
"/movies/Movie/Movie-6.mkv",
"/movies/Movie/Movie-7.mkv",
"/movies/Movie/Movie-8.mkv"
};
var result = VideoListResolver.Resolve(
@ -116,15 +116,15 @@ namespace Jellyfin.Naming.Tests.Video
{
var files = new[]
{
@"/movies/Mo/Movie 1.mkv",
@"/movies/Mo/Movie 2.mkv",
@"/movies/Mo/Movie 3.mkv",
@"/movies/Mo/Movie 4.mkv",
@"/movies/Mo/Movie 5.mkv",
@"/movies/Mo/Movie 6.mkv",
@"/movies/Mo/Movie 7.mkv",
@"/movies/Mo/Movie 8.mkv",
@"/movies/Mo/Movie 9.mkv"
"/movies/Mo/Movie 1.mkv",
"/movies/Mo/Movie 2.mkv",
"/movies/Mo/Movie 3.mkv",
"/movies/Mo/Movie 4.mkv",
"/movies/Mo/Movie 5.mkv",
"/movies/Mo/Movie 6.mkv",
"/movies/Mo/Movie 7.mkv",
"/movies/Mo/Movie 8.mkv",
"/movies/Mo/Movie 9.mkv"
};
var result = VideoListResolver.Resolve(
@ -140,11 +140,11 @@ namespace Jellyfin.Naming.Tests.Video
{
var files = new[]
{
@"/movies/Movie/Movie 1.mkv",
@"/movies/Movie/Movie 2.mkv",
@"/movies/Movie/Movie 3.mkv",
@"/movies/Movie/Movie 4.mkv",
@"/movies/Movie/Movie 5.mkv"
"/movies/Movie/Movie 1.mkv",
"/movies/Movie/Movie 2.mkv",
"/movies/Movie/Movie 3.mkv",
"/movies/Movie/Movie 4.mkv",
"/movies/Movie/Movie 5.mkv"
};
var result = VideoListResolver.Resolve(
@ -162,11 +162,11 @@ namespace Jellyfin.Naming.Tests.Video
var files = new[]
{
@"/movies/Iron Man/Iron Man.mkv",
@"/movies/Iron Man/Iron Man (2008).mkv",
@"/movies/Iron Man/Iron Man (2009).mkv",
@"/movies/Iron Man/Iron Man (2010).mkv",
@"/movies/Iron Man/Iron Man (2011).mkv"
"/movies/Iron Man/Iron Man.mkv",
"/movies/Iron Man/Iron Man (2008).mkv",
"/movies/Iron Man/Iron Man (2009).mkv",
"/movies/Iron Man/Iron Man (2010).mkv",
"/movies/Iron Man/Iron Man (2011).mkv"
};
var result = VideoListResolver.Resolve(
@ -182,13 +182,13 @@ namespace Jellyfin.Naming.Tests.Video
{
var files = new[]
{
@"/movies/Iron Man/Iron Man.mkv",
@"/movies/Iron Man/Iron Man-720p.mkv",
@"/movies/Iron Man/Iron Man-test.mkv",
@"/movies/Iron Man/Iron Man-bluray.mkv",
@"/movies/Iron Man/Iron Man-3d.mkv",
@"/movies/Iron Man/Iron Man-3d-hsbs.mkv",
@"/movies/Iron Man/Iron Man[test].mkv"
"/movies/Iron Man/Iron Man.mkv",
"/movies/Iron Man/Iron Man-720p.mkv",
"/movies/Iron Man/Iron Man-test.mkv",
"/movies/Iron Man/Iron Man-bluray.mkv",
"/movies/Iron Man/Iron Man-3d.mkv",
"/movies/Iron Man/Iron Man-3d-hsbs.mkv",
"/movies/Iron Man/Iron Man[test].mkv"
};
var result = VideoListResolver.Resolve(
@ -211,13 +211,13 @@ namespace Jellyfin.Naming.Tests.Video
{
var files = new[]
{
@"/movies/Iron Man/Iron Man.mkv",
@"/movies/Iron Man/Iron Man - 720p.mkv",
@"/movies/Iron Man/Iron Man - test.mkv",
@"/movies/Iron Man/Iron Man - bluray.mkv",
@"/movies/Iron Man/Iron Man - 3d.mkv",
@"/movies/Iron Man/Iron Man - 3d-hsbs.mkv",
@"/movies/Iron Man/Iron Man [test].mkv"
"/movies/Iron Man/Iron Man.mkv",
"/movies/Iron Man/Iron Man - 720p.mkv",
"/movies/Iron Man/Iron Man - test.mkv",
"/movies/Iron Man/Iron Man - bluray.mkv",
"/movies/Iron Man/Iron Man - 3d.mkv",
"/movies/Iron Man/Iron Man - 3d-hsbs.mkv",
"/movies/Iron Man/Iron Man [test].mkv"
};
var result = VideoListResolver.Resolve(
@ -240,8 +240,8 @@ namespace Jellyfin.Naming.Tests.Video
{
var files = new[]
{
@"/movies/Iron Man/Iron Man - B (2006).mkv",
@"/movies/Iron Man/Iron Man - C (2007).mkv"
"/movies/Iron Man/Iron Man - B (2006).mkv",
"/movies/Iron Man/Iron Man - C (2007).mkv"
};
var result = VideoListResolver.Resolve(
@ -256,13 +256,13 @@ namespace Jellyfin.Naming.Tests.Video
{
var files = new[]
{
@"/movies/Iron Man/Iron Man.mkv",
@"/movies/Iron Man/Iron Man_720p.mkv",
@"/movies/Iron Man/Iron Man_test.mkv",
@"/movies/Iron Man/Iron Man_bluray.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.mkv",
"/movies/Iron Man/Iron Man_720p.mkv",
"/movies/Iron Man/Iron Man_test.mkv",
"/movies/Iron Man/Iron Man_bluray.mkv",
"/movies/Iron Man/Iron Man_3d.mkv",
"/movies/Iron Man/Iron Man_3d-hsbs.mkv",
"/movies/Iron Man/Iron Man_3d.hsbs.mkv"
};
var result = VideoListResolver.Resolve(
@ -280,11 +280,11 @@ namespace Jellyfin.Naming.Tests.Video
var files = new[]
{
@"/movies/Iron Man/Iron Man (2007).mkv",
@"/movies/Iron Man/Iron Man (2008).mkv",
@"/movies/Iron Man/Iron Man (2009).mkv",
@"/movies/Iron Man/Iron Man (2010).mkv",
@"/movies/Iron Man/Iron Man (2011).mkv"
"/movies/Iron Man/Iron Man (2007).mkv",
"/movies/Iron Man/Iron Man (2008).mkv",
"/movies/Iron Man/Iron Man (2009).mkv",
"/movies/Iron Man/Iron Man (2010).mkv",
"/movies/Iron Man/Iron Man (2011).mkv"
};
var result = VideoListResolver.Resolve(
@ -300,8 +300,8 @@ namespace Jellyfin.Naming.Tests.Video
{
var files = new[]
{
@"/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) [Final Cut] [1080p HEVC AAC].mkv",
"/movies/Blade Runner (1982)/Blade Runner (1982) [EE by ADM] [480p HEVC AAC,AAC,AAC].mkv"
};
var result = VideoListResolver.Resolve(
@ -317,8 +317,8 @@ namespace Jellyfin.Naming.Tests.Video
{
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) [2160p] Blu-ray.x265.AAC.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"
};
var result = VideoListResolver.Resolve(
@ -334,12 +334,12 @@ namespace Jellyfin.Naming.Tests.Video
{
var files = new[]
{
@"/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) - 1080p.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).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) - 1080p.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).mkv",
};
var result = VideoListResolver.Resolve(
@ -361,8 +361,8 @@ namespace Jellyfin.Naming.Tests.Video
{
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 2.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"
};
var result = VideoListResolver.Resolve(
@ -378,8 +378,8 @@ namespace Jellyfin.Naming.Tests.Video
{
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 2.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"
};
var result = VideoListResolver.Resolve(

@ -384,8 +384,8 @@ namespace Jellyfin.Naming.Tests.Video
// No stacking here because there is no part/disc/etc
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 02)"
"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)"
};
var result = StackResolver.ResolveDirectories(files, _namingOptions).ToList();

@ -29,7 +29,7 @@ namespace Jellyfin.Naming.Tests.Video
[Fact]
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);
}

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

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

@ -352,11 +352,11 @@ namespace Jellyfin.Providers.Tests.Manager
{
if (forceRefresh)
{
Assert.Matches(@"image url [0-9]", image.Path);
Assert.Matches("image url [0-9]", image.Path);
}
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 VideoDirectoryRegex = @"Test Data[/\\]Video";
public const string MetadataDirectoryPath = "library/00/00000000000000000000000000000000";
public const string MetadataDirectoryRegex = @"library.*";
public const string MetadataDirectoryRegex = "library.*";
private readonly ILocalizationManager _localizationManager;
private readonly MediaInfoResolver _subtitleResolver;
@ -49,7 +49,7 @@ public class MediaInfoResolverTests
var englishCultureDto = new CultureDto("English", "English", "en", new[] { "eng" });
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);
_localizationManager = localizationManager.Object;
@ -79,7 +79,7 @@ public class MediaInfoResolverTests
{
// need a media source manager capable of returning something other than file protocol
var mediaSourceManager = new Mock<IMediaSourceManager>();
mediaSourceManager.Setup(m => m.GetPathProtocol(It.IsRegex(@"http.*")))
mediaSourceManager.Setup(m => m.GetPathProtocol(It.IsRegex("http.*")))
.Returns(MediaProtocol.Http);
BaseItem.MediaSourceManager = mediaSourceManager.Object;
@ -186,7 +186,7 @@ public class MediaInfoResolverTests
{
// need a media source manager capable of returning something other than file protocol
var mediaSourceManager = new Mock<IMediaSourceManager>();
mediaSourceManager.Setup(m => m.GetPathProtocol(It.IsRegex(@"http.*")))
mediaSourceManager.Setup(m => m.GetPathProtocol(It.IsRegex("http.*")))
.Returns(MediaProtocol.Http);
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("/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/", "/", "/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("/o", "/o", "/s", "/s")] // regression test for #5977
public void TryReplaceSubPath_ValidArgs_Correct(string path, string subPath, string newSubPath, string? expectedResult)
{
@ -78,10 +78,10 @@ namespace Jellyfin.Server.Implementations.Tests.Library
[Theory]
[InlineData(null, '/', null)]
[InlineData(null, '\\', null)]
[InlineData("/home/jeff/myfile.mkv", '\\', "\\home\\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(@"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("", '/', "")]
public void NormalizePath_SpecifyingSeparator_Normalizes(string path, char separator, string expectedPath)
{
@ -90,8 +90,8 @@ namespace Jellyfin.Server.Implementations.Tests.Library
[Theory]
[InlineData("/home/jeff/myfile.mkv")]
[InlineData("C:\\Users\\Jeff\\myfile.mkv")]
[InlineData("\\home/jeff\\myfile.mkv")]
[InlineData(@"C:\Users\Jeff\myfile.mkv")]
[InlineData(@"\home/jeff\myfile.mkv")]
public void NormalizePath_NoArgs_UsesDirectorySeparatorChar(string path)
{
var separator = Path.DirectorySeparatorChar;
@ -101,8 +101,8 @@ namespace Jellyfin.Server.Implementations.Tests.Library
[Theory]
[InlineData("/home/jeff/myfile.mkv", '/')]
[InlineData("C:\\Users\\Jeff\\myfile.mkv", '\\')]
[InlineData("\\home/jeff\\myfile.mkv", '/')]
[InlineData(@"C:\Users\Jeff\myfile.mkv", '\\')]
[InlineData(@"\home/jeff\myfile.mkv", '/')]
public void NormalizePath_OutVar_Correct(string path, char expectedSeparator)
{
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("test.txt")] // Not a DLL
[InlineData(".././.././../some.dll")] // Traversal with current and parent
[InlineData("..\\.\\..\\.\\..\\some.dll")] // Windows traversal with current and parent
[InlineData("\\\\network\\resource.dll")] // UNC Path
[InlineData(@"..\.\..\.\..\some.dll")] // Windows traversal with current and parent
[InlineData(@"\\network\resource.dll")] // UNC Path
[InlineData("https://jellyfin.org/some.dll")] // URL
[InlineData("~/some.dll")] // Tilde poses a shell expansion risk, but is a valid path character.
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");
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));
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);
Assert.NotNull(result);
@ -231,7 +231,7 @@ namespace Jellyfin.Server.Implementations.Tests.Plugins
await pluginManager.PopulateManifest(packageInfo, new Version(1, 0), _pluginPath, PluginStatus.Active);
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);
Assert.NotNull(result);
@ -251,13 +251,13 @@ namespace Jellyfin.Server.Implementations.Tests.Plugins
};
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));
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);
Assert.NotNull(result);
@ -277,13 +277,13 @@ namespace Jellyfin.Server.Implementations.Tests.Plugins
};
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));
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);
Assert.NotNull(result);

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

Loading…
Cancel
Save