aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Emby.Server.Implementations/ConfigurationOptions.cs1
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs3
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs63
-rw-r--r--Emby.Server.Implementations/Localization/Core/he.json6
-rw-r--r--Emby.Server.Implementations/Localization/Core/hu.json10
-rw-r--r--Emby.Server.Implementations/Localization/Core/id.json3
-rw-r--r--Emby.Server.Implementations/Localization/Core/mk.json96
-rw-r--r--MediaBrowser.Api/Library/LibraryService.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs1
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs8
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs8
-rw-r--r--MediaBrowser.Controller/Sorting/AlphanumComparator.cs (renamed from Emby.Server.Implementations/Sorting/AlphanumComparator.cs)32
-rw-r--r--MediaBrowser.Controller/Sorting/SortExtensions.cs122
-rw-r--r--MediaBrowser.Controller/Sorting/SortHelper.cs25
-rw-r--r--MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs7
-rw-r--r--MediaBrowser.Model/Configuration/EncodingOptions.cs2
-rw-r--r--MediaBrowser.Model/Configuration/ServerConfiguration.cs2
-rw-r--r--MediaBrowser.Providers/MediaBrowser.Providers.csproj5
-rw-r--r--MediaBrowser.Providers/Music/MusicExternalIds.cs96
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs (renamed from MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs)45
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs (renamed from MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs)19
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/PluginConfiguration.cs44
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/config.html69
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs98
-rw-r--r--MediaBrowser.Providers/Plugins/MusicBrainz/Plugin.cs39
-rw-r--r--tests/Jellyfin.Naming.Tests/TV/AbsoluteEpisodeNumberTests.cs54
-rw-r--r--tests/Jellyfin.Naming.Tests/TV/DailyEpisodeTests.cs53
-rw-r--r--tests/Jellyfin.Naming.Tests/TV/EpisodeNumberWithoutSeasonTests.cs127
-rw-r--r--tests/Jellyfin.Naming.Tests/TV/EpisodePathParserTest.cs37
-rw-r--r--tests/Jellyfin.Naming.Tests/TV/EpisodeWithoutSeasonTests.cs43
-rw-r--r--tests/Jellyfin.Naming.Tests/TV/MultiEpisodeTests.cs153
-rw-r--r--tests/Jellyfin.Naming.Tests/TV/SeasonFolderTests.cs116
-rw-r--r--tests/Jellyfin.Naming.Tests/TV/SeasonNumberTests.cs338
-rw-r--r--tests/Jellyfin.Naming.Tests/TV/SimpleEpisodeTests.cs94
34 files changed, 680 insertions, 1141 deletions
diff --git a/Emby.Server.Implementations/ConfigurationOptions.cs b/Emby.Server.Implementations/ConfigurationOptions.cs
index 2ea7ff6e9..d0f3d6723 100644
--- a/Emby.Server.Implementations/ConfigurationOptions.cs
+++ b/Emby.Server.Implementations/ConfigurationOptions.cs
@@ -8,7 +8,6 @@ namespace Emby.Server.Implementations
public static Dictionary<string, string> Configuration => new Dictionary<string, string>
{
{ "HttpListenerHost:DefaultRedirectPath", "web/index.html" },
- { "MusicBrainz:BaseUrl", "https://www.musicbrainz.org" },
{ FfmpegProbeSizeKey, "1G" },
{ FfmpegAnalyzeDurationKey, "200M" }
};
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 5d16a9050..5f7f5b2f0 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -944,7 +944,6 @@ namespace Emby.Server.Implementations.Library
IncludeItemTypes = new[] { typeof(T).Name },
Name = name,
DtoOptions = options
-
}).Cast<MusicArtist>()
.OrderBy(i => i.IsAccessedByName ? 1 : 0)
.Cast<T>()
@@ -1080,7 +1079,7 @@ namespace Emby.Server.Implementations.Library
var innerProgress = new ActionableProgress<double>();
- innerProgress.RegisterAction(pct => progress.Report(pct * pct * 0.96));
+ innerProgress.RegisterAction(pct => progress.Report(pct * 0.96));
// Validate the entire media library
await RootFolder.ValidateChildren(innerProgress, cancellationToken, new MetadataRefreshOptions(new DirectoryService(_fileSystem)), recursive: true).ConfigureAwait(false);
diff --git a/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs
index 5e672f221..fa6d57466 100644
--- a/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/PlaylistResolver.cs
@@ -1,65 +1,68 @@
-#pragma warning disable CS1591
-#pragma warning disable SA1600
-
using System;
using System.IO;
using System.Linq;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Playlists;
+using MediaBrowser.Controller.Resolvers;
+using MediaBrowser.LocalMetadata.Savers;
using MediaBrowser.Model.Entities;
namespace Emby.Server.Implementations.Library.Resolvers
{
+ /// <summary>
+ /// <see cref="IItemResolver"/> for <see cref="Playlist"/> library items.
+ /// </summary>
public class PlaylistResolver : FolderResolver<Playlist>
{
- private string[] SupportedCollectionTypes = new string[] {
-
+ private string[] _musicPlaylistCollectionTypes = new string[] {
string.Empty,
CollectionType.Music
};
- /// <summary>
- /// Resolves the specified args.
- /// </summary>
- /// <param name="args">The args.</param>
- /// <returns>BoxSet.</returns>
+ /// <inheritdoc/>
protected override Playlist Resolve(ItemResolveArgs args)
{
- // It's a boxset if all of the following conditions are met:
- // Is a Directory
- // Contains [playlist] in the path
if (args.IsDirectory)
{
- var filename = Path.GetFileName(args.Path);
-
- if (string.IsNullOrEmpty(filename))
+ // It's a boxset if the path is a directory with [playlist] in it's the name
+ // TODO: Should this use Path.GetDirectoryName() instead?
+ bool isBoxSet = Path.GetFileName(args.Path)
+ ?.Contains("[playlist]", StringComparison.OrdinalIgnoreCase)
+ ?? false;
+ if (isBoxSet)
{
- return null;
+ return new Playlist
+ {
+ Path = args.Path,
+ Name = Path.GetFileName(args.Path).Replace("[playlist]", string.Empty, StringComparison.OrdinalIgnoreCase).Trim()
+ };
}
- if (filename.IndexOf("[playlist]", StringComparison.OrdinalIgnoreCase) != -1)
+ // It's a directory-based playlist if the directory contains a playlist file
+ var filePaths = Directory.EnumerateFiles(args.Path);
+ if (filePaths.Any(f => f.EndsWith(PlaylistXmlSaver.DefaultPlaylistFilename, StringComparison.OrdinalIgnoreCase)))
{
return new Playlist
{
Path = args.Path,
- Name = Path.GetFileName(args.Path).Replace("[playlist]", string.Empty, StringComparison.OrdinalIgnoreCase).Trim()
+ Name = Path.GetFileName(args.Path)
};
}
}
- else
+
+ // Check if this is a music playlist file
+ // It should have the correct collection type and a supported file extension
+ else if (_musicPlaylistCollectionTypes.Contains(args.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
{
- if (SupportedCollectionTypes.Contains(args.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
+ var extension = Path.GetExtension(args.Path);
+ if (Playlist.SupportedExtensions.Contains(extension ?? string.Empty, StringComparer.OrdinalIgnoreCase))
{
- var extension = Path.GetExtension(args.Path);
- if (Playlist.SupportedExtensions.Contains(extension ?? string.Empty, StringComparer.OrdinalIgnoreCase))
+ return new Playlist
{
- return new Playlist
- {
- Path = args.Path,
- Name = Path.GetFileNameWithoutExtension(args.Path),
- IsInMixedFolder = true
- };
- }
+ Path = args.Path,
+ Name = Path.GetFileNameWithoutExtension(args.Path),
+ IsInMixedFolder = true
+ };
}
}
diff --git a/Emby.Server.Implementations/Localization/Core/he.json b/Emby.Server.Implementations/Localization/Core/he.json
index 5ef59797d..f3a7794da 100644
--- a/Emby.Server.Implementations/Localization/Core/he.json
+++ b/Emby.Server.Implementations/Localization/Core/he.json
@@ -81,9 +81,9 @@
"System": "System",
"TvShows": "סדרות טלוויזיה",
"User": "User",
- "UserCreatedWithName": "User {0} has been created",
- "UserDeletedWithName": "User {0} has been deleted",
- "UserDownloadingItemWithValues": "{0} is downloading {1}",
+ "UserCreatedWithName": "המשתמש {0} נוצר",
+ "UserDeletedWithName": "המשתמש {0} הוסר",
+ "UserDownloadingItemWithValues": "{0} מוריד את {1}",
"UserLockedOutWithName": "User {0} has been locked out",
"UserOfflineFromDevice": "{0} has disconnected from {1}",
"UserOnlineFromDevice": "{0} is online from {1}",
diff --git a/Emby.Server.Implementations/Localization/Core/hu.json b/Emby.Server.Implementations/Localization/Core/hu.json
index 950be68d0..6017aa7f9 100644
--- a/Emby.Server.Implementations/Localization/Core/hu.json
+++ b/Emby.Server.Implementations/Localization/Core/hu.json
@@ -11,7 +11,7 @@
"Collections": "Gyűjtemények",
"DeviceOfflineWithName": "{0} kijelentkezett",
"DeviceOnlineWithName": "{0} belépett",
- "FailedLoginAttemptWithUserName": "Sikertelen bejelentkezési kísérlet {0}",
+ "FailedLoginAttemptWithUserName": "Sikertelen bejelentkezési kísérlet tőle: {0}",
"Favorites": "Kedvencek",
"Folders": "Könyvtárak",
"Genres": "Műfajok",
@@ -27,7 +27,7 @@
"HeaderNextUp": "Következik",
"HeaderRecordingGroups": "Felvételi csoportok",
"HomeVideos": "Házi videók",
- "Inherit": "Öröklés",
+ "Inherit": "Örökölt",
"ItemAddedWithName": "{0} hozzáadva a könyvtárhoz",
"ItemRemovedWithName": "{0} eltávolítva a könyvtárból",
"LabelIpAddressValue": "IP cím: {0}",
@@ -73,7 +73,7 @@
"ServerNameNeedsToBeRestarted": "{0}-t újra kell indítani",
"Shows": "Műsorok",
"Songs": "Dalok",
- "StartupEmbyServerIsLoading": "A Jellyfin Szerver betöltődik. Kérlek próbáld újra később.",
+ "StartupEmbyServerIsLoading": "A Jellyfin Szerver betöltődik. Kérlek, próbáld újra hamarosan.",
"SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}",
"SubtitleDownloadFailureFromForItem": "Nem sikerült a felirat letöltése innen: {0} ehhez: {1}",
"SubtitlesDownloadedForItem": "Letöltött feliratok a következőhöz: {0}",
@@ -86,11 +86,11 @@
"UserDownloadingItemWithValues": "{0} letölti {1}",
"UserLockedOutWithName": "{0} felhasználó zárolva van",
"UserOfflineFromDevice": "{0} kijelentkezett innen: {1}",
- "UserOnlineFromDevice": "{0} online itt: {1}",
+ "UserOnlineFromDevice": "{0} online innen: {1}",
"UserPasswordChangedWithName": "Jelszó megváltozott a következő felhasználó számára: {0}",
"UserPolicyUpdatedWithName": "A felhasználói házirend frissítve lett neki: {0}",
"UserStartedPlayingItemWithValues": "{0} elkezdte játszani a következőt: {1} itt: {2}",
- "UserStoppedPlayingItemWithValues": "{0} befejezte a következőt: {1} itt: {2}",
+ "UserStoppedPlayingItemWithValues": "{0} befejezte {1} lejátászását itt: {2}",
"ValueHasBeenAddedToLibrary": "{0} hozzáadva a médiatárhoz",
"ValueSpecialEpisodeName": "Special - {0}",
"VersionNumber": "Verzió: {0}"
diff --git a/Emby.Server.Implementations/Localization/Core/id.json b/Emby.Server.Implementations/Localization/Core/id.json
index 38c6cf54f..68fffbf0a 100644
--- a/Emby.Server.Implementations/Localization/Core/id.json
+++ b/Emby.Server.Implementations/Localization/Core/id.json
@@ -91,5 +91,6 @@
"NotificationOptionVideoPlayback": "Pemutaran video dimulai",
"NotificationOptionAudioPlaybackStopped": "Pemutaran audio berhenti",
"NotificationOptionAudioPlayback": "Pemutaran audio dimulai",
- "MixedContent": "Konten campur"
+ "MixedContent": "Konten campur",
+ "PluginUninstalledWithName": "{0} telah dihapus"
}
diff --git a/Emby.Server.Implementations/Localization/Core/mk.json b/Emby.Server.Implementations/Localization/Core/mk.json
new file mode 100644
index 000000000..684a97aad
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Core/mk.json
@@ -0,0 +1,96 @@
+{
+ "ScheduledTaskFailedWithName": "{0} неуспешно",
+ "ProviderValue": "Провајдер: {0}",
+ "PluginUpdatedWithName": "{0} беше надоградено",
+ "PluginUninstalledWithName": "{0} беше успешно деинсталирано",
+ "PluginInstalledWithName": "{0} беше успешно инсталирано",
+ "Plugin": "Додатоци",
+ "Playlists": "Листи",
+ "Photos": "Слики",
+ "NotificationOptionVideoPlaybackStopped": "Видео стопирано",
+ "NotificationOptionVideoPlayback": "Видео пуштено",
+ "NotificationOptionUserLockedOut": "Корисникот е ослободен",
+ "NotificationOptionTaskFailed": "Закажани задачи неуспешно",
+ "NotificationOptionServerRestartRequired": "Задолжително рестартирање на серверот",
+ "NotificationOptionPluginUpdateInstalled": "Надоградба на Додаток успешна",
+ "NotificationOptionPluginUninstalled": "Додаток успешно деинсталиран",
+ "NotificationOptionPluginInstalled": "Додаток успешно инсталиран",
+ "NotificationOptionPluginError": "Грешка на додаток",
+ "NotificationOptionNewLibraryContent": "Додадена нова содржина",
+ "NotificationOptionInstallationFailed": "Неуспешна Инсталација",
+ "NotificationOptionCameraImageUploaded": "Слика од камера поставена",
+ "NotificationOptionAudioPlaybackStopped": "Аудио стопирано",
+ "NotificationOptionAudioPlayback": "Аудио стартувано",
+ "NotificationOptionApplicationUpdateInstalled": "Надоградбата на Апликацијата е иснталирана",
+ "NotificationOptionApplicationUpdateAvailable": "Возможна надоградба на Апликацијата",
+ "NewVersionIsAvailable": "Нова верзија од Jellyfin е возможна за спуштање.",
+ "NameSeasonUnknown": "Непозната Сезона",
+ "NameSeasonNumber": "Сезона {0}",
+ "NameInstallFailed": "{0} неуспешна инсталација",
+ "MusicVideos": "Музички видеа",
+ "Music": "Музика",
+ "Movies": "Филмови",
+ "MixedContent": "Мешана содржина",
+ "MessageServerConfigurationUpdated": "Серверската конфигурација беше надградена",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Секцијата на конфигурација на сервер {0} беше надоградена",
+ "MessageApplicationUpdatedTo": "Jellyfin беше надограден до {0}",
+ "MessageApplicationUpdated": "Jellyfin Серверот беше надограден",
+ "Latest": "Последно",
+ "LabelRunningTimeValue": "Време на работа: {0}",
+ "LabelIpAddressValue": "ИП Адреса: {0}",
+ "ItemRemovedWithName": "{0} е избришано до Библиотеката",
+ "ItemAddedWithName": "{0} беше додадено во Библиотеката",
+ "Inherit": "Следно",
+ "HomeVideos": "Домашни Видеа",
+ "HeaderRecordingGroups": "Групи на снимање",
+ "HeaderNextUp": "Следно",
+ "HeaderLiveTV": "ТВ",
+ "HeaderFavoriteSongs": "Омилени Песни",
+ "HeaderFavoriteShows": "Омилени Серии",
+ "HeaderFavoriteEpisodes": "Омилени Епизоди",
+ "HeaderFavoriteArtists": "Омилени Изведувачи",
+ "HeaderFavoriteAlbums": "Омилени Албуми",
+ "HeaderContinueWatching": "Продолжи со гледање",
+ "HeaderCameraUploads": "Поставувања од камера",
+ "HeaderAlbumArtists": "Изведувачи од Албуми",
+ "Genres": "Жанрови",
+ "Folders": "Папки",
+ "Favorites": "Омилени",
+ "FailedLoginAttemptWithUserName": "Неуспешно поврзување од {0}",
+ "DeviceOnlineWithName": "{0} е приклучен",
+ "DeviceOfflineWithName": "{0} се исклучи",
+ "Collections": "Колекции",
+ "ChapterNameValue": "Дел {0}",
+ "Channels": "Канали",
+ "CameraImageUploadedFrom": "Нова слика од камера беше поставена од {0}",
+ "Books": "Книги",
+ "AuthenticationSucceededWithUserName": "{0} успешно поврзан",
+ "Artists": "Изведувач",
+ "Application": "Апликација",
+ "AppDeviceValues": "Аплиакција: {0}, Уред: {1}",
+ "Albums": "Албуми",
+ "VersionNumber": "Верзија {0}",
+ "ValueSpecialEpisodeName": "Специјално - {0}",
+ "ValueHasBeenAddedToLibrary": "{0} е додадено во твојата библиотека",
+ "UserStoppedPlayingItemWithValues": "{0} заврши со репродукција {1} во {2}",
+ "UserStartedPlayingItemWithValues": "{0} пушти {1} на {2}",
+ "UserPolicyUpdatedWithName": "Полисата на користење беше надоградена за {0}",
+ "UserPasswordChangedWithName": "Лозинката е сменета за корисникот {0}",
+ "UserOnlineFromDevice": "{0} е приклучен од {1}",
+ "UserOfflineFromDevice": "{0} е дисконектиран од {1}",
+ "UserLockedOutWithName": "Корисникот {0} е заклучен",
+ "UserDownloadingItemWithValues": "{0} се спушта {1}",
+ "UserDeletedWithName": "Корисникот {0} е избришан",
+ "UserCreatedWithName": "Корисникот {0} е креиран",
+ "User": "Корисник",
+ "TvShows": "ТВ Серии",
+ "System": "Систем",
+ "Sync": "Синхронизација",
+ "SubtitlesDownloadedForItem": "Спуштање превод за {0}",
+ "SubtitleDownloadFailureFromForItem": "Преводот неуспешно се спушти од {0} за {1}",
+ "StartupEmbyServerIsLoading": "Jellyfin Server се пушта. Ве молиме причекајте.",
+ "Songs": "Песни",
+ "Shows": "Серии",
+ "ServerNameNeedsToBeRestarted": "{0} треба да се рестартира",
+ "ScheduledTaskStartedWithName": "{0} започна"
+}
diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs
index 3d1e4a363..15284958d 100644
--- a/MediaBrowser.Api/Library/LibraryService.cs
+++ b/MediaBrowser.Api/Library/LibraryService.cs
@@ -815,7 +815,7 @@ namespace MediaBrowser.Api.Library
if (!string.IsNullOrWhiteSpace(filename))
{
// Kestrel doesn't support non-ASCII characters in headers
- if (Regex.IsMatch(filename, "[^[:ascii:]]"))
+ if (Regex.IsMatch(filename, @"[^\p{IsBasicLatin}]"))
{
// Manually encoding non-ASCII characters, following https://tools.ietf.org/html/rfc5987#section-3.2.2
headers[HeaderNames.ContentDisposition] = "attachment; filename*=UTF-8''" + WebUtility.UrlEncode(filename);
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index efe0d3cf7..5e3056ccb 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -198,6 +198,7 @@ namespace MediaBrowser.Controller.Entities.Audio
return true;
}
}
+
return base.RequiresRefresh();
}
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 353c675cb..66de080a3 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -387,15 +387,12 @@ namespace MediaBrowser.Controller.Entities
while (thisMarker < s1.Length)
{
- if (thisMarker >= s1.Length)
- {
- break;
- }
char thisCh = s1[thisMarker];
var thisChunk = new StringBuilder();
+ bool isNumeric = char.IsDigit(thisCh);
- while ((thisMarker < s1.Length) && (thisChunk.Length == 0 || SortHelper.InChunk(thisCh, thisChunk[0])))
+ while (thisMarker < s1.Length && char.IsDigit(thisCh) == isNumeric)
{
thisChunk.Append(thisCh);
thisMarker++;
@@ -406,7 +403,6 @@ namespace MediaBrowser.Controller.Entities
}
}
- var isNumeric = thisChunk.Length > 0 && char.IsDigit(thisChunk[0]);
list.Add(new Tuple<StringBuilder, bool>(thisChunk, isNumeric));
}
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 64c2159e4..c72bd487e 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -322,10 +322,10 @@ namespace MediaBrowser.Controller.Entities
ProviderManager.OnRefreshProgress(this, 5);
}
- //build a dictionary of the current children we have now by Id so we can compare quickly and easily
+ // Build a dictionary of the current children we have now by Id so we can compare quickly and easily
var currentChildren = GetActualChildrenDictionary();
- //create a list for our validated children
+ // Create a list for our validated children
var newItems = new List<BaseItem>();
cancellationToken.ThrowIfCancellationRequested();
@@ -391,7 +391,7 @@ namespace MediaBrowser.Controller.Entities
var folder = this;
innerProgress.RegisterAction(p =>
{
- double newPct = .80 * p + 10;
+ double newPct = 0.80 * p + 10;
progress.Report(newPct);
ProviderManager.OnRefreshProgress(folder, newPct);
});
@@ -421,7 +421,7 @@ namespace MediaBrowser.Controller.Entities
var folder = this;
innerProgress.RegisterAction(p =>
{
- double newPct = .10 * p + 90;
+ double newPct = 0.10 * p + 90;
progress.Report(newPct);
if (recursive)
{
diff --git a/Emby.Server.Implementations/Sorting/AlphanumComparator.cs b/MediaBrowser.Controller/Sorting/AlphanumComparator.cs
index 2e00c24d7..65dc120ca 100644
--- a/Emby.Server.Implementations/Sorting/AlphanumComparator.cs
+++ b/MediaBrowser.Controller/Sorting/AlphanumComparator.cs
@@ -2,7 +2,7 @@ using System.Collections.Generic;
using System.Text;
using MediaBrowser.Controller.Sorting;
-namespace Emby.Server.Implementations.Sorting
+namespace MediaBrowser.Controller.Sorting
{
public class AlphanumComparator : IComparer<string>
{
@@ -31,8 +31,9 @@ namespace Emby.Server.Implementations.Sorting
var thisChunk = new StringBuilder();
var thatChunk = new StringBuilder();
+ bool thisNumeric = char.IsDigit(thisCh), thatNumeric = char.IsDigit(thatCh);
- while ((thisMarker < s1.Length) && (thisChunk.Length == 0 || SortHelper.InChunk(thisCh, thisChunk[0])))
+ while (thisMarker < s1.Length && char.IsDigit(thisCh) == thisNumeric)
{
thisChunk.Append(thisCh);
thisMarker++;
@@ -43,7 +44,7 @@ namespace Emby.Server.Implementations.Sorting
}
}
- while ((thatMarker < s2.Length) && (thatChunk.Length == 0 || SortHelper.InChunk(thatCh, thatChunk[0])))
+ while (thatMarker < s2.Length && char.IsDigit(thatCh) == thatNumeric)
{
thatChunk.Append(thatCh);
thatMarker++;
@@ -54,38 +55,35 @@ namespace Emby.Server.Implementations.Sorting
}
}
- int result = 0;
+
// If both chunks contain numeric characters, sort them numerically
- if (char.IsDigit(thisChunk[0]) && char.IsDigit(thatChunk[0]))
+ if (thisNumeric && thatNumeric)
{
- if (!int.TryParse(thisChunk.ToString(), out thisNumericChunk))
- {
- return 0;
- }
- if (!int.TryParse(thatChunk.ToString(), out thatNumericChunk))
+ if (!int.TryParse(thisChunk.ToString(), out thisNumericChunk)
+ || !int.TryParse(thatChunk.ToString(), out thatNumericChunk))
{
return 0;
}
if (thisNumericChunk < thatNumericChunk)
{
- result = -1;
+ return -1;
}
if (thisNumericChunk > thatNumericChunk)
{
- result = 1;
+ return 1;
}
}
else
{
- result = thisChunk.ToString().CompareTo(thatChunk.ToString());
+ int result = thisChunk.ToString().CompareTo(thatChunk.ToString());
+ if (result != 0)
+ {
+ return result;
+ }
}
- if (result != 0)
- {
- return result;
- }
}
return 0;
diff --git a/MediaBrowser.Controller/Sorting/SortExtensions.cs b/MediaBrowser.Controller/Sorting/SortExtensions.cs
index 111f4f17f..f5ee574a2 100644
--- a/MediaBrowser.Controller/Sorting/SortExtensions.cs
+++ b/MediaBrowser.Controller/Sorting/SortExtensions.cs
@@ -7,137 +7,25 @@ namespace MediaBrowser.Controller.Sorting
{
public static class SortExtensions
{
+ private static readonly AlphanumComparator _comparer = new AlphanumComparator();
public static IEnumerable<T> OrderByString<T>(this IEnumerable<T> list, Func<T, string> getName)
{
- return list.OrderBy(getName, new AlphanumComparator());
+ return list.OrderBy(getName, _comparer);
}
public static IEnumerable<T> OrderByStringDescending<T>(this IEnumerable<T> list, Func<T, string> getName)
{
- return list.OrderByDescending(getName, new AlphanumComparator());
+ return list.OrderByDescending(getName, _comparer);
}
public static IOrderedEnumerable<T> ThenByString<T>(this IOrderedEnumerable<T> list, Func<T, string> getName)
{
- return list.ThenBy(getName, new AlphanumComparator());
+ return list.ThenBy(getName, _comparer);
}
public static IOrderedEnumerable<T> ThenByStringDescending<T>(this IOrderedEnumerable<T> list, Func<T, string> getName)
{
- return list.ThenByDescending(getName, new AlphanumComparator());
- }
-
- private class AlphanumComparator : IComparer<string>
- {
- private enum ChunkType { Alphanumeric, Numeric };
-
- private static bool InChunk(char ch, char otherCh)
- {
- var type = ChunkType.Alphanumeric;
-
- if (char.IsDigit(otherCh))
- {
- type = ChunkType.Numeric;
- }
-
- if ((type == ChunkType.Alphanumeric && char.IsDigit(ch))
- || (type == ChunkType.Numeric && !char.IsDigit(ch)))
- {
- return false;
- }
-
- return true;
- }
-
- public static int CompareValues(string s1, string s2)
- {
- if (s1 == null || s2 == null)
- {
- return 0;
- }
-
- int thisMarker = 0, thisNumericChunk = 0;
- int thatMarker = 0, thatNumericChunk = 0;
-
- while ((thisMarker < s1.Length) || (thatMarker < s2.Length))
- {
- if (thisMarker >= s1.Length)
- {
- return -1;
- }
- else if (thatMarker >= s2.Length)
- {
- return 1;
- }
- char thisCh = s1[thisMarker];
- char thatCh = s2[thatMarker];
-
- var thisChunk = new StringBuilder();
- var thatChunk = new StringBuilder();
-
- while ((thisMarker < s1.Length) && (thisChunk.Length == 0 || InChunk(thisCh, thisChunk[0])))
- {
- thisChunk.Append(thisCh);
- thisMarker++;
-
- if (thisMarker < s1.Length)
- {
- thisCh = s1[thisMarker];
- }
- }
-
- while ((thatMarker < s2.Length) && (thatChunk.Length == 0 || InChunk(thatCh, thatChunk[0])))
- {
- thatChunk.Append(thatCh);
- thatMarker++;
-
- if (thatMarker < s2.Length)
- {
- thatCh = s2[thatMarker];
- }
- }
-
- int result = 0;
- // If both chunks contain numeric characters, sort them numerically
- if (char.IsDigit(thisChunk[0]) && char.IsDigit(thatChunk[0]))
- {
- if (!int.TryParse(thisChunk.ToString(), out thisNumericChunk))
- {
- return 0;
- }
- if (!int.TryParse(thatChunk.ToString(), out thatNumericChunk))
- {
- return 0;
- }
-
- if (thisNumericChunk < thatNumericChunk)
- {
- result = -1;
- }
-
- if (thisNumericChunk > thatNumericChunk)
- {
- result = 1;
- }
- }
- else
- {
- result = thisChunk.ToString().CompareTo(thatChunk.ToString());
- }
-
- if (result != 0)
- {
- return result;
- }
- }
-
- return 0;
- }
-
- public int Compare(string x, string y)
- {
- return CompareValues(x, y);
- }
+ return list.ThenByDescending(getName, _comparer);
}
}
}
diff --git a/MediaBrowser.Controller/Sorting/SortHelper.cs b/MediaBrowser.Controller/Sorting/SortHelper.cs
deleted file mode 100644
index 05981d975..000000000
--- a/MediaBrowser.Controller/Sorting/SortHelper.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-namespace MediaBrowser.Controller.Sorting
-{
- public static class SortHelper
- {
- private enum ChunkType { Alphanumeric, Numeric };
-
- public static bool InChunk(char ch, char otherCh)
- {
- var type = ChunkType.Alphanumeric;
-
- if (char.IsDigit(otherCh))
- {
- type = ChunkType.Numeric;
- }
-
- if ((type == ChunkType.Alphanumeric && char.IsDigit(ch))
- || (type == ChunkType.Numeric && !char.IsDigit(ch)))
- {
- return false;
- }
-
- return true;
- }
- }
-}
diff --git a/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs b/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs
index 35a431fa4..1a661edef 100644
--- a/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs
+++ b/MediaBrowser.LocalMetadata/Savers/PlaylistXmlSaver.cs
@@ -11,6 +11,11 @@ namespace MediaBrowser.LocalMetadata.Savers
{
public class PlaylistXmlSaver : BaseXmlSaver
{
+ /// <summary>
+ /// The default file name to use when creating a new playlist.
+ /// </summary>
+ public const string DefaultPlaylistFilename = "playlist.xml";
+
public override bool IsEnabledFor(BaseItem item, ItemUpdateType updateType)
{
if (!item.SupportsLocalMetadata)
@@ -45,7 +50,7 @@ namespace MediaBrowser.LocalMetadata.Savers
return Path.ChangeExtension(itemPath, ".xml");
}
- return Path.Combine(path, "playlist.xml");
+ return Path.Combine(path, DefaultPlaylistFilename);
}
public PlaylistXmlSaver(IFileSystem fileSystem, IServerConfigurationManager configurationManager, ILibraryManager libraryManager, IUserManager userManager, IUserDataManager userDataManager, ILogger logger)
diff --git a/MediaBrowser.Model/Configuration/EncodingOptions.cs b/MediaBrowser.Model/Configuration/EncodingOptions.cs
index ff431e44c..b3a784de7 100644
--- a/MediaBrowser.Model/Configuration/EncodingOptions.cs
+++ b/MediaBrowser.Model/Configuration/EncodingOptions.cs
@@ -34,7 +34,7 @@ namespace MediaBrowser.Model.Configuration
public EncodingOptions()
{
DownMixAudioBoost = 2;
- EnableThrottling = true;
+ EnableThrottling = false;
ThrottleDelaySeconds = 180;
EncodingThreadCount = -1;
// This is a DRM device that is almost guaranteed to be there on every intel platform, plus it's the default one in ffmpeg if you don't specify anything
diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
index 5280d455c..bf10108b8 100644
--- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs
+++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs
@@ -238,7 +238,7 @@ namespace MediaBrowser.Model.Configuration
CodecsUsed = Array.Empty<string>();
PathSubstitutions = Array.Empty<PathSubstitution>();
IgnoreVirtualInterfaces = false;
- EnableSimpleArtistDetection = true;
+ EnableSimpleArtistDetection = false;
DisplaySpecialsWithinSeasons = true;
EnableExternalContentInSuggestions = true;
diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
index 5593c5036..48c16b643 100644
--- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj
+++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj
@@ -24,4 +24,9 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
+ <ItemGroup>
+ <None Remove="Plugins\MusicBrainz\Configuration\config.html" />
+ <EmbeddedResource Include="Plugins\MusicBrainz\Configuration\config.html" />
+ </ItemGroup>
+
</Project>
diff --git a/MediaBrowser.Providers/Music/MusicExternalIds.cs b/MediaBrowser.Providers/Music/MusicExternalIds.cs
index 585c98af9..628b9a9a1 100644
--- a/MediaBrowser.Providers/Music/MusicExternalIds.cs
+++ b/MediaBrowser.Providers/Music/MusicExternalIds.cs
@@ -1,105 +1,9 @@
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
namespace MediaBrowser.Providers.Music
{
- public class MusicBrainzReleaseGroupExternalId : IExternalId
- {
- /// <inheritdoc />
- public string Name => "MusicBrainz Release Group";
-
- /// <inheritdoc />
- public string Key => MetadataProviders.MusicBrainzReleaseGroup.ToString();
-
- /// <inheritdoc />
- public string UrlFormatString => "https://musicbrainz.org/release-group/{0}";
-
- /// <inheritdoc />
- public bool Supports(IHasProviderIds item)
- => item is Audio || item is MusicAlbum;
- }
-
- public class MusicBrainzAlbumArtistExternalId : IExternalId
- {
- /// <inheritdoc />
- public string Name => "MusicBrainz Album Artist";
-
- /// <inheritdoc />
- public string Key => MetadataProviders.MusicBrainzAlbumArtist.ToString();
-
- /// <inheritdoc />
- public string UrlFormatString => "https://musicbrainz.org/artist/{0}";
-
- /// <inheritdoc />
- public bool Supports(IHasProviderIds item)
- => item is Audio;
- }
-
- public class MusicBrainzAlbumExternalId : IExternalId
- {
- /// <inheritdoc />
- public string Name => "MusicBrainz Album";
-
- /// <inheritdoc />
- public string Key => MetadataProviders.MusicBrainzAlbum.ToString();
-
- /// <inheritdoc />
- public string UrlFormatString => "https://musicbrainz.org/release/{0}";
-
- /// <inheritdoc />
- public bool Supports(IHasProviderIds item)
- => item is Audio || item is MusicAlbum;
- }
-
- public class MusicBrainzArtistExternalId : IExternalId
- {
- /// <inheritdoc />
- public string Name => "MusicBrainz";
-
- /// <inheritdoc />
- public string Key => MetadataProviders.MusicBrainzArtist.ToString();
-
- /// <inheritdoc />
- public string UrlFormatString => "https://musicbrainz.org/artist/{0}";
-
- /// <inheritdoc />
- public bool Supports(IHasProviderIds item) => item is MusicArtist;
- }
-
- public class MusicBrainzOtherArtistExternalId : IExternalId
- {
- /// <inheritdoc />
- public string Name => "MusicBrainz Artist";
-
- /// <inheritdoc />
-
- public string Key => MetadataProviders.MusicBrainzArtist.ToString();
-
- /// <inheritdoc />
- public string UrlFormatString => "https://musicbrainz.org/artist/{0}";
-
- /// <inheritdoc />
- public bool Supports(IHasProviderIds item)
- => item is Audio || item is MusicAlbum;
- }
-
- public class MusicBrainzTrackId : IExternalId
- {
- /// <inheritdoc />
- public string Name => "MusicBrainz Track";
-
- /// <inheritdoc />
- public string Key => MetadataProviders.MusicBrainzTrack.ToString();
-
- /// <inheritdoc />
- public string UrlFormatString => "https://musicbrainz.org/track/{0}";
-
- /// <inheritdoc />
- public bool Supports(IHasProviderIds item) => item is Audio;
- }
-
public class ImvdbId : IExternalId
{
/// <inheritdoc />
diff --git a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs
index 8e71b625e..748c23216 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzAlbumProvider.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/AlbumProvider.cs
@@ -15,7 +15,7 @@ using MediaBrowser.Controller.Entities.Audio;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
-using Microsoft.Extensions.Configuration;
+using MediaBrowser.Providers.Plugins.MusicBrainz;
using Microsoft.Extensions.Logging;
namespace MediaBrowser.Providers.Music
@@ -28,7 +28,7 @@ namespace MediaBrowser.Providers.Music
/// Be prudent, use a value slightly above the minimun required.
/// https://musicbrainz.org/doc/XML_Web_Service/Rate_Limiting
/// </summary>
- private const long MusicBrainzQueryIntervalMs = 1050u;
+ private readonly long _musicBrainzQueryIntervalMs;
/// <summary>
/// For each single MB lookup/search, this is the maximum number of
@@ -50,14 +50,14 @@ namespace MediaBrowser.Providers.Music
public MusicBrainzAlbumProvider(
IHttpClient httpClient,
IApplicationHost appHost,
- ILogger logger,
- IConfiguration configuration)
+ ILogger logger)
{
_httpClient = httpClient;
_appHost = appHost;
_logger = logger;
- _musicBrainzBaseUrl = configuration["MusicBrainz:BaseUrl"];
+ _musicBrainzBaseUrl = Plugin.Instance.Configuration.Server;
+ _musicBrainzQueryIntervalMs = Plugin.Instance.Configuration.RateLimit;
// Use a stopwatch to ensure we don't exceed the MusicBrainz rate limit
_stopWatchMusicBrainz.Start();
@@ -74,6 +74,12 @@ namespace MediaBrowser.Providers.Music
/// <inheritdoc />
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(AlbumInfo searchInfo, CancellationToken cancellationToken)
{
+ // TODO maybe remove when artist metadata can be disabled
+ if (!Plugin.Instance.Configuration.Enable)
+ {
+ return Enumerable.Empty<RemoteSearchResult>();
+ }
+
var releaseId = searchInfo.GetReleaseId();
var releaseGroupId = searchInfo.GetReleaseGroupId();
@@ -107,8 +113,8 @@ namespace MediaBrowser.Providers.Music
url = string.Format(
CultureInfo.InvariantCulture,
"/ws/2/release/?query=\"{0}\" AND artist:\"{1}\"",
- WebUtility.UrlEncode(queryName),
- WebUtility.UrlEncode(searchInfo.GetAlbumArtist()));
+ WebUtility.UrlEncode(queryName),
+ WebUtility.UrlEncode(searchInfo.GetAlbumArtist()));
}
}
@@ -170,7 +176,6 @@ namespace MediaBrowser.Providers.Music
}
return result;
-
});
}
}
@@ -187,6 +192,12 @@ namespace MediaBrowser.Providers.Music
Item = new MusicAlbum()
};
+ // TODO maybe remove when artist metadata can be disabled
+ if (!Plugin.Instance.Configuration.Enable)
+ {
+ return result;
+ }
+
// If we have a release group Id but not a release Id...
if (string.IsNullOrWhiteSpace(releaseId) && !string.IsNullOrWhiteSpace(releaseGroupId))
{
@@ -456,18 +467,6 @@ namespace MediaBrowser.Providers.Music
}
case "artist-credit":
{
- // TODO
-
- /*
- * <artist-credit>
-<name-credit>
-<artist id="e225cda5-882d-4b80-b8a3-b36d7175b1ea">
-<name>SARCASTIC+ZOOKEEPER</name>
-<sort-name>SARCASTIC+ZOOKEEPER</sort-name>
-</artist>
-</name-credit>
-</artist-credit>
- */
using (var subReader = reader.ReadSubtree())
{
var artist = ParseArtistCredit(subReader);
@@ -764,10 +763,10 @@ namespace MediaBrowser.Providers.Music
{
attempts++;
- if (_stopWatchMusicBrainz.ElapsedMilliseconds < MusicBrainzQueryIntervalMs)
+ if (_stopWatchMusicBrainz.ElapsedMilliseconds < _musicBrainzQueryIntervalMs)
{
// MusicBrainz is extremely adamant about limiting to one request per second
- var delayMs = MusicBrainzQueryIntervalMs - _stopWatchMusicBrainz.ElapsedMilliseconds;
+ var delayMs = _musicBrainzQueryIntervalMs - _stopWatchMusicBrainz.ElapsedMilliseconds;
await Task.Delay((int)delayMs, cancellationToken).ConfigureAwait(false);
}
@@ -778,7 +777,7 @@ namespace MediaBrowser.Providers.Music
response = await _httpClient.SendAsync(options, "GET").ConfigureAwait(false);
- // We retry a finite number of times, and only whilst MB is indcating 503 (throttling)
+ // We retry a finite number of times, and only whilst MB is indicating 503 (throttling)
}
while (attempts < MusicBrainzQueryAttempts && response.StatusCode == HttpStatusCode.ServiceUnavailable);
diff --git a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs
index 5d675392c..260a3b6e7 100644
--- a/MediaBrowser.Providers/Music/MusicBrainzArtistProvider.cs
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/ArtistProvider.cs
@@ -14,6 +14,7 @@ using MediaBrowser.Controller.Extensions;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Providers;
+using MediaBrowser.Providers.Plugins.MusicBrainz;
namespace MediaBrowser.Providers.Music
{
@@ -22,6 +23,12 @@ namespace MediaBrowser.Providers.Music
/// <inheritdoc />
public async Task<IEnumerable<RemoteSearchResult>> GetSearchResults(ArtistInfo searchInfo, CancellationToken cancellationToken)
{
+ // TODO maybe remove when artist metadata can be disabled
+ if (!Plugin.Instance.Configuration.Enable)
+ {
+ return Enumerable.Empty<RemoteSearchResult>();
+ }
+
var musicBrainzId = searchInfo.GetMusicBrainzArtistId();
if (!string.IsNullOrWhiteSpace(musicBrainzId))
@@ -226,6 +233,12 @@ namespace MediaBrowser.Providers.Music
Item = new MusicArtist()
};
+ // TODO maybe remove when artist metadata can be disabled
+ if (!Plugin.Instance.Configuration.Enable)
+ {
+ return result;
+ }
+
var musicBrainzId = id.GetMusicBrainzArtistId();
if (string.IsNullOrWhiteSpace(musicBrainzId))
@@ -237,8 +250,12 @@ namespace MediaBrowser.Providers.Music
if (singleResult != null)
{
musicBrainzId = singleResult.GetProviderId(MetadataProviders.MusicBrainzArtist);
- //result.Item.Name = singleResult.Name;
result.Item.Overview = singleResult.Overview;
+
+ if (Plugin.Instance.Configuration.ReplaceArtistName)
+ {
+ result.Item.Name = singleResult.Name;
+ }
}
}
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/PluginConfiguration.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/PluginConfiguration.cs
new file mode 100644
index 000000000..6910b4bb4
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/PluginConfiguration.cs
@@ -0,0 +1,44 @@
+using MediaBrowser.Model.Plugins;
+
+namespace MediaBrowser.Providers.Plugins.MusicBrainz
+{
+ public class PluginConfiguration : BasePluginConfiguration
+ {
+ private string _server = Plugin.DefaultServer;
+
+ private long _rateLimit = Plugin.DefaultRateLimit;
+
+ public string Server
+ {
+ get
+ {
+ return _server;
+ }
+
+ set
+ {
+ _server = value.TrimEnd('/');
+ }
+ }
+
+ public long RateLimit
+ {
+ get
+ {
+ return _rateLimit;
+ }
+
+ set
+ {
+ if (value < Plugin.DefaultRateLimit && _server == Plugin.DefaultServer)
+ {
+ RateLimit = Plugin.DefaultRateLimit;
+ }
+ }
+ }
+
+ public bool Enable { get; set; }
+
+ public bool ReplaceArtistName { get; set; }
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/config.html b/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/config.html
new file mode 100644
index 000000000..1f02461da
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/Configuration/config.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>MusicBrainz</title>
+</head>
+<body>
+ <div data-role="page" class="page type-interior pluginConfigurationPage musicBrainzConfigPage" data-require="emby-input,emby-button,emby-checkbox">
+ <div data-role="content">
+ <div class="content-primary">
+ <form class="musicBrainzConfigForm">
+ <div class="inputContainer">
+ <input is="emby-input" type="text" id="server" required label="Server" />
+ <div class="fieldDescription">This can be a mirror of the official server or even a custom server.</div>
+ </div>
+ <div class="inputContainer">
+ <input is="emby-input" type="number" id="rateLimit" pattern="[0-9]*" required min="0" max="10000" label="Rate Limit" />
+ <div class="fieldDescription">Span of time between requests in milliseconds. The official server is limited to one request every two seconds.</div>
+ </div>
+ <label class="checkboxContainer">
+ <input is="emby-checkbox" type="checkbox" id="enable" />
+ <span>Enable this provider for metadata searches on artists and albums.</span>
+ </label>
+ <label class="checkboxContainer">
+ <input is="emby-checkbox" type="checkbox" id="replaceArtistName" />
+ <span>When an artist is found during a metadata search, replace the artist name with the value on the server.</span>
+ </label>
+ <br />
+ <div>
+ <button is="emby-button" type="submit" class="raised button-submit block"><span>Save</span></button>
+ </div>
+ </form>
+ </div>
+ </div>
+ <script type="text/javascript">
+ var MusicBrainzPluginConfig = {
+ uniquePluginId: "8c95c4d2-e50c-4fb0-a4f3-6c06ff0f9a1a"
+ };
+
+ $('.musicBrainzConfigPage').on('pageshow', function () {
+ Dashboard.showLoadingMsg();
+ ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) {
+ $('#server').val(config.Server).change();
+ $('#rateLimit').val(config.RateLimit).change();
+ $('#enable').checked(config.Enable);
+ $('#replaceArtistName').checked(config.ReplaceArtistName);
+
+ Dashboard.hideLoadingMsg();
+ });
+ });
+
+ $('.musicBrainzConfigForm').on('submit', function (e) {
+ Dashboard.showLoadingMsg();
+
+ var form = this;
+ ApiClient.getPluginConfiguration(MusicBrainzPluginConfig.uniquePluginId).then(function (config) {
+ config.Server = $('#server', form).val();
+ config.RateLimit = $('#rateLimit', form).val();
+ config.Enable = $('#enable', form).checked();
+ config.ReplaceArtistName = $('#replaceArtistName', form).checked();
+
+ ApiClient.updatePluginConfiguration(MusicBrainzPluginConfig.uniquePluginId, config).then(Dashboard.processPluginConfigurationUpdateResult);
+ });
+
+ return false;
+ });
+ </script>
+ </div>
+</body>
+</html>
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs
new file mode 100644
index 000000000..03565a34c
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/ExternalIds.cs
@@ -0,0 +1,98 @@
+using MediaBrowser.Controller.Entities.Audio;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using MediaBrowser.Providers.Plugins.MusicBrainz;
+
+namespace MediaBrowser.Providers.Music
+{
+ public class MusicBrainzReleaseGroupExternalId : IExternalId
+ {
+ /// <inheritdoc />
+ public string Name => "MusicBrainz Release Group";
+
+ /// <inheritdoc />
+ public string Key => MetadataProviders.MusicBrainzReleaseGroup.ToString();
+
+ /// <inheritdoc />
+ public string UrlFormatString => Plugin.Instance.Configuration.Server + "/release-group/{0}";
+
+ /// <inheritdoc />
+ public bool Supports(IHasProviderIds item) => item is Audio || item is MusicAlbum;
+ }
+
+ public class MusicBrainzAlbumArtistExternalId : IExternalId
+ {
+ /// <inheritdoc />
+ public string Name => "MusicBrainz Album Artist";
+
+ /// <inheritdoc />
+ public string Key => MetadataProviders.MusicBrainzAlbumArtist.ToString();
+
+ /// <inheritdoc />
+ public string UrlFormatString => Plugin.Instance.Configuration.Server + "/artist/{0}";
+
+ /// <inheritdoc />
+ public bool Supports(IHasProviderIds item) => item is Audio;
+ }
+
+ public class MusicBrainzAlbumExternalId : IExternalId
+ {
+ /// <inheritdoc />
+ public string Name => "MusicBrainz Album";
+
+ /// <inheritdoc />
+ public string Key => MetadataProviders.MusicBrainzAlbum.ToString();
+
+ /// <inheritdoc />
+ public string UrlFormatString => Plugin.Instance.Configuration.Server + "/release/{0}";
+
+ /// <inheritdoc />
+ public bool Supports(IHasProviderIds item) => item is Audio || item is MusicAlbum;
+ }
+
+ public class MusicBrainzArtistExternalId : IExternalId
+ {
+ /// <inheritdoc />
+ public string Name => "MusicBrainz";
+
+ /// <inheritdoc />
+ public string Key => MetadataProviders.MusicBrainzArtist.ToString();
+
+ /// <inheritdoc />
+ public string UrlFormatString => Plugin.Instance.Configuration.Server + "/artist/{0}";
+
+ /// <inheritdoc />
+ public bool Supports(IHasProviderIds item) => item is MusicArtist;
+ }
+
+ public class MusicBrainzOtherArtistExternalId : IExternalId
+ {
+ /// <inheritdoc />
+ public string Name => "MusicBrainz Artist";
+
+ /// <inheritdoc />
+
+ public string Key => MetadataProviders.MusicBrainzArtist.ToString();
+
+ /// <inheritdoc />
+ public string UrlFormatString => Plugin.Instance.Configuration.Server + "/artist/{0}";
+
+ /// <inheritdoc />
+ public bool Supports(IHasProviderIds item) => item is Audio || item is MusicAlbum;
+ }
+
+ public class MusicBrainzTrackId : IExternalId
+ {
+ /// <inheritdoc />
+ public string Name => "MusicBrainz Track";
+
+ /// <inheritdoc />
+ public string Key => MetadataProviders.MusicBrainzTrack.ToString();
+
+ /// <inheritdoc />
+ public string UrlFormatString => Plugin.Instance.Configuration.Server + "/track/{0}";
+
+ /// <inheritdoc />
+ public bool Supports(IHasProviderIds item) => item is Audio;
+ }
+}
diff --git a/MediaBrowser.Providers/Plugins/MusicBrainz/Plugin.cs b/MediaBrowser.Providers/Plugins/MusicBrainz/Plugin.cs
new file mode 100644
index 000000000..8e1b3ea37
--- /dev/null
+++ b/MediaBrowser.Providers/Plugins/MusicBrainz/Plugin.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.Plugins;
+using MediaBrowser.Model.Plugins;
+using MediaBrowser.Model.Serialization;
+
+namespace MediaBrowser.Providers.Plugins.MusicBrainz
+{
+ public class Plugin : BasePlugin<PluginConfiguration>, IHasWebPages
+ {
+ public static Plugin Instance { get; private set; }
+
+ public override Guid Id => new Guid("8c95c4d2-e50c-4fb0-a4f3-6c06ff0f9a1a");
+
+ public override string Name => "MusicBrainz";
+
+ public override string Description => "Get artist and album metadata from any MusicBrainz server.";
+
+ public const string DefaultServer = "https://musicbrainz.org";
+
+ public const long DefaultRateLimit = 2000u;
+
+ public Plugin(IApplicationPaths applicationPaths, IXmlSerializer xmlSerializer)
+ : base(applicationPaths, xmlSerializer)
+ {
+ Instance = this;
+ }
+
+ public IEnumerable<PluginPageInfo> GetPages()
+ {
+ yield return new PluginPageInfo
+ {
+ Name = Name,
+ EmbeddedResourcePath = GetType().Namespace + ".Configuration.config.html"
+ };
+ }
+ }
+}
diff --git a/tests/Jellyfin.Naming.Tests/TV/AbsoluteEpisodeNumberTests.cs b/tests/Jellyfin.Naming.Tests/TV/AbsoluteEpisodeNumberTests.cs
index 9abbcc7bf..553d06681 100644
--- a/tests/Jellyfin.Naming.Tests/TV/AbsoluteEpisodeNumberTests.cs
+++ b/tests/Jellyfin.Naming.Tests/TV/AbsoluteEpisodeNumberTests.cs
@@ -6,56 +6,22 @@ namespace Jellyfin.Naming.Tests.TV
{
public class AbsoluteEpisodeNumberTests
{
- [Fact]
- public void TestAbsoluteEpisodeNumber1()
- {
- Assert.Equal(12, GetEpisodeNumberFromFile(@"The Simpsons/12.avi"));
- }
-
- [Fact]
- public void TestAbsoluteEpisodeNumber2()
- {
- Assert.Equal(12, GetEpisodeNumberFromFile(@"The Simpsons/The Simpsons 12.avi"));
- }
-
- [Fact]
- public void TestAbsoluteEpisodeNumber3()
- {
- Assert.Equal(82, GetEpisodeNumberFromFile(@"The Simpsons/The Simpsons 82.avi"));
- }
-
- [Fact]
- public void TestAbsoluteEpisodeNumber4()
- {
- Assert.Equal(112, GetEpisodeNumberFromFile(@"The Simpsons/The Simpsons 112.avi"));
- }
-
- [Fact]
- public void TestAbsoluteEpisodeNumber5()
- {
- Assert.Equal(2, GetEpisodeNumberFromFile(@"The Simpsons/Foo_ep_02.avi"));
- }
-
- [Fact]
- public void TestAbsoluteEpisodeNumber6()
- {
- Assert.Equal(889, GetEpisodeNumberFromFile(@"The Simpsons/The Simpsons 889.avi"));
- }
-
- [Fact]
- public void TestAbsoluteEpisodeNumber7()
- {
- Assert.Equal(101, GetEpisodeNumberFromFile(@"The Simpsons/The Simpsons 101.avi"));
- }
-
- private int? GetEpisodeNumberFromFile(string path)
+ [Theory]
+ [InlineData("The Simpsons/12.avi", 12)]
+ [InlineData("The Simpsons/The Simpsons 12.avi", 12)]
+ [InlineData("The Simpsons/The Simpsons 82.avi", 82)]
+ [InlineData("The Simpsons/The Simpsons 112.avi", 112)]
+ [InlineData("The Simpsons/Foo_ep_02.avi", 2)]
+ [InlineData("The Simpsons/The Simpsons 889.avi", 889)]
+ [InlineData("The Simpsons/The Simpsons 101.avi", 101)]
+ public void GetEpisodeNumberFromFileTest(string path, int episodeNumber)
{
var options = new NamingOptions();
var result = new EpisodeResolver(options)
.Resolve(path, false, null, null, true);
- return result.EpisodeNumber;
+ Assert.Equal(episodeNumber, result.EpisodeNumber);
}
}
}
diff --git a/tests/Jellyfin.Naming.Tests/TV/DailyEpisodeTests.cs b/tests/Jellyfin.Naming.Tests/TV/DailyEpisodeTests.cs
index 29daf8cc3..6ecffe80b 100644
--- a/tests/Jellyfin.Naming.Tests/TV/DailyEpisodeTests.cs
+++ b/tests/Jellyfin.Naming.Tests/TV/DailyEpisodeTests.cs
@@ -6,52 +6,17 @@ namespace Jellyfin.Naming.Tests.TV
{
public class DailyEpisodeTests
{
- [Fact]
- public void TestDailyEpisode1()
- {
- Test(@"/server/anything_1996.11.14.mp4", "anything", 1996, 11, 14);
- }
-
- [Fact]
- public void TestDailyEpisode2()
- {
- Test(@"/server/anything_1996-11-14.mp4", "anything", 1996, 11, 14);
- }
- // FIXME
- // [Fact]
- public void TestDailyEpisode3()
- {
- Test(@"/server/anything_14.11.1996.mp4", "anything", 1996, 11, 14);
- }
-
- // FIXME
- // [Fact]
- public void TestDailyEpisode4()
- {
- Test(@"/server/A Daily Show - (2015-01-15) - Episode Name - [720p].mkv", "A Daily Show", 2015, 01, 15);
- }
-
- [Fact]
- public void TestDailyEpisode5()
- {
- Test(@"/server/james.corden.2017.04.20.anne.hathaway.720p.hdtv.x264-crooks.mkv", "james.corden", 2017, 04, 20);
- }
-
- [Fact]
- public void TestDailyEpisode6()
- {
- Test(@"/server/ABC News 2018_03_24_19_00_00.mkv", "ABC News", 2018, 03, 24);
- }
-
- // FIXME
- // [Fact]
- public void TestDailyEpisode7()
- {
- Test(@"/server/Last Man Standing_KTLADT_2018_05_25_01_28_00.wtv", "Last Man Standing", 2018, 05, 25);
- }
- private void Test(string path, string seriesName, int? year, int? month, int? day)
+ [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)]
+ // 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)]
+ public void Test(string path, string seriesName, int? year, int? month, int? day)
{
var options = new NamingOptions();
diff --git a/tests/Jellyfin.Naming.Tests/TV/EpisodeNumberWithoutSeasonTests.cs b/tests/Jellyfin.Naming.Tests/TV/EpisodeNumberWithoutSeasonTests.cs
index 00aa9ee7c..0c7d9520e 100644
--- a/tests/Jellyfin.Naming.Tests/TV/EpisodeNumberWithoutSeasonTests.cs
+++ b/tests/Jellyfin.Naming.Tests/TV/EpisodeNumberWithoutSeasonTests.cs
@@ -6,122 +6,31 @@ namespace Jellyfin.Naming.Tests.TV
{
public class EpisodeNumberWithoutSeasonTests
{
- [Fact]
- public void TestEpisodeNumberWithoutSeason1()
- {
- Assert.Equal(8, GetEpisodeNumberFromFile(@"The Simpsons/The Simpsons.S25E08.Steal this episode.mp4"));
- }
-
- [Fact]
- public void TestEpisodeNumberWithoutSeason2()
- {
- Assert.Equal(2, GetEpisodeNumberFromFile(@"The Simpsons/The Simpsons - 02 - Ep Name.avi"));
- }
-
- [Fact]
- public void TestEpisodeNumberWithoutSeason3()
- {
- Assert.Equal(2, GetEpisodeNumberFromFile(@"The Simpsons/02.avi"));
- }
-
- [Fact]
- public void TestEpisodeNumberWithoutSeason4()
- {
- Assert.Equal(2, GetEpisodeNumberFromFile(@"The Simpsons/02 - Ep Name.avi"));
- }
-
- [Fact]
- public void TestEpisodeNumberWithoutSeason5()
- {
- Assert.Equal(2, GetEpisodeNumberFromFile(@"The Simpsons/02-Ep Name.avi"));
- }
- [Fact]
- public void TestEpisodeNumberWithoutSeason6()
- {
- Assert.Equal(2, GetEpisodeNumberFromFile(@"The Simpsons/02.EpName.avi"));
- }
-
- [Fact]
- public void TestEpisodeNumberWithoutSeason7()
- {
- Assert.Equal(2, GetEpisodeNumberFromFile(@"The Simpsons/The Simpsons - 02.avi"));
- }
-
- [Fact]
- public void TestEpisodeNumberWithoutSeason8()
- {
- Assert.Equal(2, GetEpisodeNumberFromFile(@"The Simpsons/The Simpsons - 02 Ep Name.avi"));
- }
-
- // FIXME
- // [Fact]
- public void TestEpisodeNumberWithoutSeason9()
- {
- Assert.Equal(2, GetEpisodeNumberFromFile(@"The Simpsons/The Simpsons 5 - 02 - Ep Name.avi"));
- }
-
- // FIXME
- // [Fact]
- public void TestEpisodeNumberWithoutSeason10()
- {
- Assert.Equal(2, GetEpisodeNumberFromFile(@"The Simpsons/The Simpsons 5 - 02 Ep Name.avi"));
- }
-
- // FIXME
- // [Fact]
- public void TestEpisodeNumberWithoutSeason11()
- {
- Assert.Equal(7, GetEpisodeNumberFromFile(@"Seinfeld/Seinfeld 0807 The Checks.avi"));
- Assert.Equal(8, GetSeasonNumberFromFile(@"Seinfeld/Seinfeld 0807 The Checks.avi"));
- }
-
- [Fact]
- public void TestEpisodeNumberWithoutSeason12()
- {
- Assert.Equal(7, GetEpisodeNumberFromFile(@"GJ Club (2013)/GJ Club - 07.mkv"));
- }
-
- // FIXME
- // [Fact]
- public void TestEpisodeNumberWithoutSeason13()
- {
- // This is not supported anymore after removing the episode number 365+ hack from EpisodePathParser
- Assert.Equal(13, GetEpisodeNumberFromFile(@"Case Closed (1996-2007)/Case Closed - 13.mkv"));
- }
-
- [Fact]
- public void TestEpisodeNumberWithoutSeason14()
- {
- Assert.Equal(3, GetSeasonNumberFromFile(@"Case Closed (1996-2007)/Case Closed - 317.mkv"));
- Assert.Equal(17, GetEpisodeNumberFromFile(@"Case Closed (1996-2007)/Case Closed - 317.mkv"));
- }
-
- [Fact]
- public void TestEpisodeNumberWithoutSeason15()
- {
- Assert.Equal(2017, GetSeasonNumberFromFile(@"Running Man/Running Man S2017E368.mkv"));
- }
-
- private int? GetEpisodeNumberFromFile(string path)
+ [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")]
+ // 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")]
+ // This is not supported anymore after removing the episode number 365+ hack from EpisodePathParser
+ // TODO: [InlineData(13, @"Case Closed (1996-2007)/Case Closed - 13.mkv")]
+ public void GetEpisodeNumberFromFileTest(int episodeNumber, string path)
{
var options = new NamingOptions();
var result = new EpisodeResolver(options)
.Resolve(path, false);
- return result.EpisodeNumber;
+ Assert.Equal(episodeNumber, result.EpisodeNumber);
}
-
- private int? GetSeasonNumberFromFile(string path)
- {
- var options = new NamingOptions();
-
- var result = new EpisodeResolver(options)
- .Resolve(path, false);
-
- return result.SeasonNumber;
- }
-
}
}
diff --git a/tests/Jellyfin.Naming.Tests/TV/EpisodePathParserTest.cs b/tests/Jellyfin.Naming.Tests/TV/EpisodePathParserTest.cs
index da6e99310..4b5606715 100644
--- a/tests/Jellyfin.Naming.Tests/TV/EpisodePathParserTest.cs
+++ b/tests/Jellyfin.Naming.Tests/TV/EpisodePathParserTest.cs
@@ -15,7 +15,27 @@ namespace Jellyfin.Naming.Tests.TV
[InlineData("D:\\media\\Foo - S04E011", "Foo", 4, 11)]
[InlineData("D:\\media\\Foo\\Foo s01x01", "Foo", 1, 1)]
[InlineData("D:\\media\\Foo (2019)\\Season 4\\Foo (2019).S04E03", "Foo (2019)", 4, 3)]
+ [InlineData("/Season 2/Elementary - 02x03-04-15 - Ep Name.mp4", "Elementary", 2, 3)]
+ [InlineData("/Season 1/seriesname S01E02 blah.avi", "seriesname", 1, 2)]
+ [InlineData("/Running Man/Running Man S2017E368.mkv", "Running Man", 2017, 368)]
+ [InlineData("/Season 1/seriesname 01x02 blah.avi", "seriesname", 1, 2)]
+ [InlineData("/Season 25/The Simpsons.S25E09.Steal this episode.mp4", "The Simpsons", 25, 9)]
+ [InlineData("/Season 1/seriesname S01x02 blah.avi", "seriesname", 1, 2)]
+ [InlineData("/Season 2/Elementary - 02x03 - 02x04 - 02x15 - Ep Name.mp4", "Elementary", 2, 3)]
+ [InlineData("/Season 1/seriesname S01xE02 blah.avi", "seriesname", 1, 2)]
+ [InlineData("/Season 02/Elementary - 02x03 - x04 - x15 - Ep Name.mp4", "Elementary", 2, 3)]
+ [InlineData("/Season 02/Elementary - 02x03x04x15 - Ep Name.mp4", "Elementary", 2, 3)]
+ [InlineData("/Season 02/Elementary - 02x03-E15 - Ep Name.mp4", "Elementary", 2, 3)]
+ [InlineData("/Season 1/Elementary - S01E23-E24-E26 - The Woman.mp4", "Elementary", 1, 23)]
+ [InlineData("/The Wonder Years/The.Wonder.Years.S04.PDTV.x264-JCH/The Wonder Years s04e07 Christmas Party NTSC PDTV.avi", "The Wonder Years", 4, 7)]
+ // TODO: [InlineData("/Castle Rock 2x01 Que el rio siga su curso [WEB-DL HULU 1080p h264 Dual DD5.1 Subs].mkv", "Castle Rock", 2, 1)]
+ // TODO: [InlineData("/After Life 1x06 Episodio 6 [WEB-DL NF 1080p h264 Dual DD 5.1 Sub].mkv", "After Life", 1, 6)]
+ // TODO: [InlineData("/Season 4/Uchuu.Senkan.Yamato.2199.E03.avi", "Uchuu Senkan Yamoto 2199", 4, 3)]
+ // TODO: [InlineData("The Daily Show/The Daily Show 25x22 - [WEBDL-720p][AAC 2.0][x264] Noah Baumbach-TBS.mkv", "The Daily Show", 25, 22)]
+ // TODO: [InlineData("Watchmen (2019)/Watchmen 1x03 [WEBDL-720p][EAC3 5.1][h264][-TBS] - She Was Killed by Space Junk.mkv", "Watchmen (2019)", 1, 3)]
+ // TODO: [InlineData("/The.Legend.of.Condor.Heroes.2017.V2.web-dl.1080p.h264.aac-hdctv/The.Legend.of.Condor.Heroes.2017.E07.V2.web-dl.1080p.h264.aac-hdctv.mkv", "The Legend of Condor Heroes 2017", 1, 7)]
public void ParseEpisodesCorrectly(string path, string name, int season, int episode)
+
{
NamingOptions o = new NamingOptions();
EpisodePathParser p = new EpisodePathParser(o);
@@ -26,22 +46,5 @@ namespace Jellyfin.Naming.Tests.TV
Assert.Equal(season, res.SeasonNumber);
Assert.Equal(episode, res.EpisodeNumber);
}
-
- [Theory]
- [InlineData("/media/Foo/Foo 889", "Foo", 889)]
- [InlineData("/media/Foo/[Bar] Foo Baz - 11 [1080p]", "Foo Baz", 11)]
- [InlineData("D:\\media\\Foo\\Foo 889", "Foo", 889)]
- [InlineData("D:\\media\\Foo\\[Bar] Foo Baz - 11 [1080p]", "Foo Baz", 11)]
- public void ParseEpisodeWithoutSeason(string path, string name, int episode)
- {
- NamingOptions o = new NamingOptions();
- EpisodePathParser p = new EpisodePathParser(o);
- var res = p.Parse(path, true, fillExtendedInfo: true);
-
- Assert.True(res.Success);
- Assert.Equal(name, res.SeriesName);
- Assert.Null(res.SeasonNumber);
- Assert.Equal(episode, res.EpisodeNumber);
- }
}
}
diff --git a/tests/Jellyfin.Naming.Tests/TV/EpisodeWithoutSeasonTests.cs b/tests/Jellyfin.Naming.Tests/TV/EpisodeWithoutSeasonTests.cs
index c2851ccdb..364eb7ff8 100644
--- a/tests/Jellyfin.Naming.Tests/TV/EpisodeWithoutSeasonTests.cs
+++ b/tests/Jellyfin.Naming.Tests/TV/EpisodeWithoutSeasonTests.cs
@@ -6,42 +6,13 @@ namespace Jellyfin.Naming.Tests.TV
{
public class EpisodeWithoutSeasonTests
{
- // FIXME
- // [Fact]
- public void TestWithoutSeason1()
- {
- Test(@"/server/anything_ep02.mp4", "anything", null, 2);
- }
-
- // FIXME
- // [Fact]
- public void TestWithoutSeason2()
- {
- Test(@"/server/anything_ep_02.mp4", "anything", null, 2);
- }
-
- // FIXME
- // [Fact]
- public void TestWithoutSeason3()
- {
- Test(@"/server/anything_part.II.mp4", "anything", null, null);
- }
-
- // FIXME
- // [Fact]
- public void TestWithoutSeason4()
- {
- Test(@"/server/anything_pt.II.mp4", "anything", null, null);
- }
-
- // FIXME
- // [Fact]
- public void TestWithoutSeason5()
- {
- Test(@"/server/anything_pt_II.mp4", "anything", null, null);
- }
-
- private void Test(string path, string seriesName, int? seasonNumber, int? episodeNumber)
+ // TODO: [Theory]
+ // TODO: [InlineData(@"/server/anything_ep02.mp4", "anything", null, 2)]
+ // TODO: [InlineData(@"/server/anything_ep_02.mp4", "anything", null, 2)]
+ // TODO: [InlineData(@"/server/anything_part.II.mp4", "anything", null, null)]
+ // TODO: [InlineData(@"/server/anything_pt.II.mp4", "anything", null, null)]
+ // TODO: [InlineData(@"/server/anything_pt_II.mp4", "anything", null, null)]
+ public void Test(string path, string seriesName, int? seasonNumber, int? episodeNumber)
{
var options = new NamingOptions();
diff --git a/tests/Jellyfin.Naming.Tests/TV/MultiEpisodeTests.cs b/tests/Jellyfin.Naming.Tests/TV/MultiEpisodeTests.cs
index b15dd6b74..3513050b6 100644
--- a/tests/Jellyfin.Naming.Tests/TV/MultiEpisodeTests.cs
+++ b/tests/Jellyfin.Naming.Tests/TV/MultiEpisodeTests.cs
@@ -6,100 +6,75 @@ namespace Jellyfin.Naming.Tests.TV
{
public class MultiEpisodeTests
{
- [Fact]
- public void TestGetEndingEpisodeNumberFromFile()
- {
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 1/4x01 – 20 Hours in America (1).mkv"));
-
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 1/01x02 blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 1/S01x02 blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 1/S01E02 blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 1/S01xE02 blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 1/seriesname 01x02 blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 1/seriesname S01x02 blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 1/seriesname S01E02 blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 1/seriesname S01xE02 blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 2/02x03 - 04 Ep Name.mp4"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 2/My show name 02x03 - 04 Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 2/Elementary - 02x03 - 02x04 - 02x15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 2/02x03 - 02x04 - 02x15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 2/02x03-04-15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 2/Elementary - 02x03-04-15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 02/02x03-E15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 02/Elementary - 02x03-E15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 02/02x03 - x04 - x15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 02/Elementary - 02x03 - x04 - x15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 02/02x03x04x15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 02/Elementary - 02x03x04x15 - Ep Name.mp4"));
- Assert.Equal(26, GetEndingEpisodeNumberFromFile(@"Season 1/Elementary - S01E23-E24-E26 - The Woman.mp4"));
- Assert.Equal(26, GetEndingEpisodeNumberFromFile(@"Season 1/S01E23-E24-E26 - The Woman.mp4"));
-
-
- // Four Digits seasons
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 2009/2009x02 blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 2009/S2009x02 blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 2009/S2009E02 blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 2009/S2009xE02 blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 2009/seriesname 2009x02 blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 2009/seriesname S2009x02 blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 2009/seriesname S2009E02 blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 2009/seriesname S2009xE02 blah.avi"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 2009/Elementary - 2009x03 - 2009x04 - 2009x15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 2009/2009x03 - 2009x04 - 2009x15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 2009/2009x03-04-15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 2009/Elementary - 2009x03-04-15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 2009/2009x03-E15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 2009/Elementary - 2009x03-E15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 2009/2009x03 - x04 - x15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 2009/Elementary - 2009x03 - x04 - x15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 2009/2009x03x04x15 - Ep Name.mp4"));
- Assert.Equal(15, GetEndingEpisodeNumberFromFile(@"Season 2009/Elementary - 2009x03x04x15 - Ep Name.mp4"));
- Assert.Equal(26, GetEndingEpisodeNumberFromFile(@"Season 2009/Elementary - S2009E23-E24-E26 - The Woman.mp4"));
- Assert.Equal(26, GetEndingEpisodeNumberFromFile(@"Season 2009/S2009E23-E24-E26 - The Woman.mp4"));
-
- // Without season number
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 1/02 - blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 2/02 - blah 14 blah.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 1/02 - blah-02 a.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 2/02.avi"));
-
- Assert.Equal(3, GetEndingEpisodeNumberFromFile(@"Season 1/02-03 - blah.avi"));
- Assert.Equal(4, GetEndingEpisodeNumberFromFile(@"Season 2/02-04 - blah 14 blah.avi"));
- Assert.Equal(5, GetEndingEpisodeNumberFromFile(@"Season 1/02-05 - blah-02 a.avi"));
- Assert.Equal(4, GetEndingEpisodeNumberFromFile(@"Season 2/02-04.avi"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 2/[HorribleSubs] Hunter X Hunter - 136 [720p].mkv"));
-
- // With format specification that must not be detected as ending episode number
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 1/series-s09e14-1080p.mkv"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 1/series-s09e14-720p.mkv"));
- Assert.Null(GetEndingEpisodeNumberFromFile(@"Season 1/series-s09e14-720i.mkv"));
- Assert.Equal(4, GetEndingEpisodeNumberFromFile(@"Season 1/MOONLIGHTING_s01e01-e04.mkv"));
- }
-
- [Fact]
- public void TestGetEndingEpisodeNumberFromFolder()
- {
- Assert.Equal(4, GetEndingEpisodeNumberFromFolder(@"Season 1/MOONLIGHTING_s01e01-e04"));
- }
-
- private int? GetEndingEpisodeNumberFromFolder(string path)
- {
- var options = new NamingOptions();
-
- var result = new EpisodePathParser(options)
- .Parse(path, true);
-
- return result.EndingEpsiodeNumber;
- }
-
- private int? GetEndingEpisodeNumberFromFile(string path)
+ [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)]
+ // 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)]
+ // 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)]
+ // 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)]
+ public void TestGetEndingEpisodeNumberFromFile(string filename, int? endingEpisodeNumber)
{
var options = new NamingOptions();
var result = new EpisodePathParser(options)
- .Parse(path, false);
+ .Parse(filename, false);
- return result.EndingEpsiodeNumber;
+ Assert.Equal(result.EndingEpsiodeNumber, endingEpisodeNumber);
}
}
}
diff --git a/tests/Jellyfin.Naming.Tests/TV/SeasonFolderTests.cs b/tests/Jellyfin.Naming.Tests/TV/SeasonFolderTests.cs
index df683fc34..078f940b2 100644
--- a/tests/Jellyfin.Naming.Tests/TV/SeasonFolderTests.cs
+++ b/tests/Jellyfin.Naming.Tests/TV/SeasonFolderTests.cs
@@ -5,107 +5,27 @@ namespace Jellyfin.Naming.Tests.TV
{
public class SeasonFolderTests
{
- [Fact]
- public void TestGetSeasonNumberFromPath1()
- {
- Assert.Equal(1, GetSeasonNumberFromPath(@"/Drive/Season 1"));
- }
-
- [Fact]
- public void TestGetSeasonNumberFromPath2()
- {
- Assert.Equal(2, GetSeasonNumberFromPath(@"/Drive/Season 2"));
- }
-
- [Fact]
- public void TestGetSeasonNumberFromPath3()
- {
- Assert.Equal(2, GetSeasonNumberFromPath(@"/Drive/Season 02"));
- }
-
- [Fact]
- public void TestGetSeasonNumberFromPath4()
- {
- Assert.Equal(1, GetSeasonNumberFromPath(@"/Drive/Season 1"));
- }
-
- [Fact]
- public void TestGetSeasonNumberFromPath5()
- {
- Assert.Equal(2, GetSeasonNumberFromPath(@"/Drive/Seinfeld/S02"));
- }
-
- [Fact]
- public void TestGetSeasonNumberFromPath6()
- {
- Assert.Equal(2, GetSeasonNumberFromPath(@"/Drive/Seinfeld/2"));
- }
-
- [Fact]
- public void TestGetSeasonNumberFromPath7()
- {
- Assert.Equal(2009, GetSeasonNumberFromPath(@"/Drive/Season 2009"));
- }
-
- [Fact]
- public void TestGetSeasonNumberFromPath8()
- {
- Assert.Equal(1, GetSeasonNumberFromPath(@"/Drive/Season1"));
- }
-
- [Fact]
- public void TestGetSeasonNumberFromPath9()
- {
- Assert.Equal(4, GetSeasonNumberFromPath(@"The Wonder Years/The.Wonder.Years.S04.PDTV.x264-JCH"));
- }
-
- [Fact]
- public void TestGetSeasonNumberFromPath10()
- {
- Assert.Equal(7, GetSeasonNumberFromPath(@"/Drive/Season 7 (2016)"));
- }
-
- [Fact]
- public void TestGetSeasonNumberFromPath11()
- {
- Assert.Equal(7, GetSeasonNumberFromPath(@"/Drive/Staffel 7 (2016)"));
- }
-
- [Fact]
- public void TestGetSeasonNumberFromPath12()
- {
- Assert.Equal(7, GetSeasonNumberFromPath(@"/Drive/Stagione 7 (2016)"));
- }
-
- [Fact]
- public void TestGetSeasonNumberFromPath14()
- {
- Assert.Null(GetSeasonNumberFromPath(@"/Drive/Season (8)"));
- }
-
- [Fact]
- public void TestGetSeasonNumberFromPath13()
- {
- Assert.Equal(3, GetSeasonNumberFromPath(@"/Drive/3.Staffel"));
- }
-
- [Fact]
- public void TestGetSeasonNumberFromPath15()
- {
- Assert.Null(GetSeasonNumberFromPath(@"/Drive/s06e05"));
- }
-
- [Fact]
- public void TestGetSeasonNumberFromPath16()
- {
- Assert.Null(GetSeasonNumberFromPath(@"/Drive/The.Legend.of.Condor.Heroes.2017.V2.web-dl.1080p.h264.aac-hdctv"));
- }
-
- private int? GetSeasonNumberFromPath(string path)
+ [Theory]
+ [InlineData(@"/Drive/Season 1", 1)]
+ [InlineData(@"/Drive/Season 2", 2)]
+ [InlineData(@"/Drive/Season 02", 2)]
+ [InlineData(@"/Drive/Seinfeld/S02", 2)]
+ [InlineData(@"/Drive/Seinfeld/2", 2)]
+ [InlineData(@"/Drive/Season 2009", 2009)]
+ [InlineData(@"/Drive/Season1", 1)]
+ [InlineData(@"The Wonder Years/The.Wonder.Years.S04.PDTV.x264-JCH", 4)]
+ [InlineData(@"/Drive/Season 7 (2016)", 7)]
+ [InlineData(@"/Drive/Staffel 7 (2016)", 7)]
+ [InlineData(@"/Drive/Stagione 7 (2016)", 7)]
+ [InlineData(@"/Drive/Season (8)", null)]
+ [InlineData(@"/Drive/3.Staffel", 3)]
+ [InlineData(@"/Drive/s06e05", null)]
+ [InlineData(@"/Drive/The.Legend.of.Condor.Heroes.2017.V2.web-dl.1080p.h264.aac-hdctv", null)]
+ public void GetSeasonNumberFromPathTest(string path, int? seasonNumber)
{
var result = SeasonPathParser.Parse(path, true, true);
- return result.SeasonNumber;
+ Assert.Equal(result.SeasonNumber, seasonNumber);
}
}
}
diff --git a/tests/Jellyfin.Naming.Tests/TV/SeasonNumberTests.cs b/tests/Jellyfin.Naming.Tests/TV/SeasonNumberTests.cs
index 1df28c974..9eaf897b9 100644
--- a/tests/Jellyfin.Naming.Tests/TV/SeasonNumberTests.cs
+++ b/tests/Jellyfin.Naming.Tests/TV/SeasonNumberTests.cs
@@ -10,6 +10,50 @@ namespace Jellyfin.Naming.Tests.TV
[Theory]
[InlineData("The Daily Show/The Daily Show 25x22 - [WEBDL-720p][AAC 2.0][x264] Noah Baumbach-TBS.mkv", 25)]
+ [InlineData("/Show/Season 02/S02E03 blah.avi", 2)]
+ [InlineData("Season 1/seriesname S01x02 blah.avi", 1)]
+ [InlineData("Season 1/S01x02 blah.avi", 1)]
+ [InlineData("Season 1/seriesname S01xE02 blah.avi", 1)]
+ [InlineData("Season 1/01x02 blah.avi", 1)]
+ [InlineData("Season 1/S01E02 blah.avi", 1)]
+ [InlineData("Season 1/S01xE02 blah.avi", 1)]
+ [InlineData("Season 1/seriesname 01x02 blah.avi", 1)]
+ [InlineData("Season 1/seriesname S01E02 blah.avi", 1)]
+ [InlineData("Season 2/Elementary - 02x03 - 02x04 - 02x15 - Ep Name.mp4", 2)]
+ [InlineData("Season 2/02x03 - 02x04 - 02x15 - Ep Name.mp4", 2)]
+ [InlineData("Season 2/02x03-04-15 - Ep Name.mp4", 2)]
+ [InlineData("Season 2/Elementary - 02x03-04-15 - Ep Name.mp4", 2)]
+ [InlineData("Season 02/02x03-E15 - Ep Name.mp4", 2)]
+ [InlineData("Season 02/Elementary - 02x03-E15 - Ep Name.mp4", 2)]
+ [InlineData("Season 02/02x03 - x04 - x15 - Ep Name.mp4", 2)]
+ [InlineData("Season 02/Elementary - 02x03 - x04 - x15 - Ep Name.mp4", 2)]
+ [InlineData("Season 02/02x03x04x15 - Ep Name.mp4", 2)]
+ [InlineData("Season 02/Elementary - 02x03x04x15 - Ep Name.mp4", 2)]
+ [InlineData("Season 1/Elementary - S01E23-E24-E26 - The Woman.mp4", 1)]
+ [InlineData("Season 1/S01E23-E24-E26 - The Woman.mp4", 1)]
+ [InlineData("Season 25/The Simpsons.S25E09.Steal this episode.mp4", 25)]
+ [InlineData("The Simpsons/The Simpsons.S25E09.Steal this episode.mp4", 25)]
+ [InlineData("2016/Season s2016e1.mp4", 2016)]
+ [InlineData("2016/Season 2016x1.mp4", 2016)]
+ [InlineData("Season 2009/2009x02 blah.avi", 2009)]
+ [InlineData("Season 2009/S2009x02 blah.avi", 2009)]
+ [InlineData("Season 2009/S2009E02 blah.avi", 2009)]
+ [InlineData("Season 2009/S2009xE02 blah.avi", 2009)]
+ [InlineData("Season 2009/seriesname 2009x02 blah.avi", 2009)]
+ [InlineData("Season 2009/seriesname S2009x02 blah.avi", 2009)]
+ [InlineData("Season 2009/seriesname S2009E02 blah.avi", 2009)]
+ [InlineData("Season 2009/Elementary - 2009x03 - 2009x04 - 2009x15 - Ep Name.mp4", 2009)]
+ [InlineData("Season 2009/2009x03 - 2009x04 - 2009x15 - Ep Name.mp4", 2009)]
+ [InlineData("Season 2009/2009x03-04-15 - Ep Name.mp4", 2009)]
+ [InlineData("Season 2009/Elementary - 2009x03 - x04 - x15 - Ep Name.mp4", 2009)]
+ [InlineData("Season 2009/2009x03x04x15 - Ep Name.mp4", 2009)]
+ [InlineData("Season 2009/Elementary - 2009x03x04x15 - Ep Name.mp4", 2009)]
+ [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)]
+ // TODO: [InlineData(@"Seinfeld/Seinfeld 0807 The Checks.avi", 8)]
public void GetSeasonNumberFromEpisodeFileTest(string path, int? expected)
{
var result = new EpisodeResolver(_namingOptions)
@@ -17,299 +61,5 @@ namespace Jellyfin.Naming.Tests.TV
Assert.Equal(expected, result.SeasonNumber);
}
-
- private int? GetSeasonNumberFromEpisodeFile(string path)
- {
- var result = new EpisodeResolver(_namingOptions)
- .Resolve(path, false);
-
- return result.SeasonNumber;
- }
-
- [Fact]
- public void TestSeasonNumber1()
- {
- Assert.Equal(2, GetSeasonNumberFromEpisodeFile(@"/Show/Season 02/S02E03 blah.avi"));
- }
-
- [Fact]
- public void TestSeasonNumber2()
- {
- Assert.Equal(1, GetSeasonNumberFromEpisodeFile(@"Season 1/seriesname S01x02 blah.avi"));
- }
-
- [Fact]
- public void TestSeasonNumber3()
- {
- Assert.Equal(1, GetSeasonNumberFromEpisodeFile(@"Season 1/S01x02 blah.avi"));
- }
-
- [Fact]
- public void TestSeasonNumber4()
- {
- Assert.Equal(1, GetSeasonNumberFromEpisodeFile(@"Season 1/seriesname S01xE02 blah.avi"));
- }
-
- [Fact]
- public void TestSeasonNumber5()
- {
- Assert.Equal(1, GetSeasonNumberFromEpisodeFile(@"Season 1/01x02 blah.avi"));
- }
-
- [Fact]
- public void TestSeasonNumber6()
- {
- Assert.Equal(1, GetSeasonNumberFromEpisodeFile(@"Season 1/S01E02 blah.avi"));
- }
-
- [Fact]
- public void TestSeasonNumber7()
- {
- Assert.Equal(1, GetSeasonNumberFromEpisodeFile(@"Season 1/S01xE02 blah.avi"));
- }
-
- // FIXME
- // [Fact]
- public void TestSeasonNumber8()
- {
- Assert.Equal(1, GetSeasonNumberFromEpisodeFile(@"Season 1/seriesname 01x02 blah.avi"));
- }
-
- [Fact]
- public void TestSeasonNumber9()
- {
- Assert.Equal(1, GetSeasonNumberFromEpisodeFile(@"Season 1/seriesname S01x02 blah.avi"));
- }
-
- [Fact]
- public void TestSeasonNumber10()
- {
- Assert.Equal(1, GetSeasonNumberFromEpisodeFile(@"Season 1/seriesname S01E02 blah.avi"));
- }
-
- [Fact]
- public void TestSeasonNumber11()
- {
- Assert.Equal(2, GetSeasonNumberFromEpisodeFile(@"Season 2/Elementary - 02x03 - 02x04 - 02x15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestSeasonNumber12()
- {
- Assert.Equal(2, GetSeasonNumberFromEpisodeFile(@"Season 2/02x03 - 02x04 - 02x15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestSeasonNumber13()
- {
- Assert.Equal(2, GetSeasonNumberFromEpisodeFile(@"Season 2/02x03-04-15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestSeasonNumber14()
- {
- Assert.Equal(2, GetSeasonNumberFromEpisodeFile(@"Season 2/Elementary - 02x03-04-15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestSeasonNumber15()
- {
- Assert.Equal(2, GetSeasonNumberFromEpisodeFile(@"Season 02/02x03-E15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestSeasonNumber16()
- {
- Assert.Equal(2, GetSeasonNumberFromEpisodeFile(@"Season 02/Elementary - 02x03-E15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestSeasonNumber17()
- {
- Assert.Equal(2, GetSeasonNumberFromEpisodeFile(@"Season 02/02x03 - x04 - x15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestSeasonNumber18()
- {
- Assert.Equal(2, GetSeasonNumberFromEpisodeFile(@"Season 02/Elementary - 02x03 - x04 - x15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestSeasonNumber19()
- {
- Assert.Equal(2, GetSeasonNumberFromEpisodeFile(@"Season 02/02x03x04x15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestSeasonNumber20()
- {
- Assert.Equal(2, GetSeasonNumberFromEpisodeFile(@"Season 02/Elementary - 02x03x04x15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestSeasonNumber21()
- {
- Assert.Equal(1, GetSeasonNumberFromEpisodeFile(@"Season 1/Elementary - S01E23-E24-E26 - The Woman.mp4"));
- }
-
- [Fact]
- public void TestSeasonNumber22()
- {
- Assert.Equal(1, GetSeasonNumberFromEpisodeFile(@"Season 1/S01E23-E24-E26 - The Woman.mp4"));
- }
-
- [Fact]
- public void TestSeasonNumber23()
- {
- Assert.Equal(25, GetSeasonNumberFromEpisodeFile(@"Season 25/The Simpsons.S25E09.Steal this episode.mp4"));
- }
-
- [Fact]
- public void TestSeasonNumber24()
- {
- Assert.Equal(25, GetSeasonNumberFromEpisodeFile(@"The Simpsons/The Simpsons.S25E09.Steal this episode.mp4"));
- }
-
- [Fact]
- public void TestSeasonNumber25()
- {
- Assert.Equal(2016, GetSeasonNumberFromEpisodeFile(@"2016/Season s2016e1.mp4"));
- }
-
- // FIXME
- // [Fact]
- public void TestSeasonNumber26()
- {
- // This convention is not currently supported, just adding in case we want to look at it in the future
- Assert.Equal(2016, GetSeasonNumberFromEpisodeFile(@"2016/Season 2016x1.mp4"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber1()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/2009x02 blah.avi"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber2()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/S2009x02 blah.avi"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber3()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/S2009E02 blah.avi"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber4()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/S2009xE02 blah.avi"));
- }
-
- // FIXME
- // [Fact]
- public void TestFourDigitSeasonNumber5()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/seriesname 2009x02 blah.avi"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber6()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/seriesname S2009x02 blah.avi"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber7()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/seriesname S2009E02 blah.avi"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber8()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/Elementary - 2009x03 - 2009x04 - 2009x15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber9()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/2009x03 - 2009x04 - 2009x15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber10()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/2009x03-04-15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber11()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/Elementary - 2009x03 - x04 - x15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber12()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/2009x03x04x15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber13()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/Elementary - 2009x03x04x15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber14()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/Elementary - S2009E23-E24-E26 - The Woman.mp4"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber15()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/S2009E23-E24-E26 - The Woman.mp4"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber16()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/Elementary - 2009x03 - x04 - x15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber17()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/2009x03x04x15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber18()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/Elementary - 2009x03x04x15 - Ep Name.mp4"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber19()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/Elementary - S2009E23-E24-E26 - The Woman.mp4"));
- }
-
- [Fact]
- public void TestFourDigitSeasonNumber20()
- {
- Assert.Equal(2009, GetSeasonNumberFromEpisodeFile(@"Season 2009/S2009E23-E24-E26 - The Woman.mp4"));
- }
-
- [Fact]
- public void TestNoSeriesFolder()
- {
- Assert.Equal(1, GetSeasonNumberFromEpisodeFile(@"Series/1-12 - The Woman.mp4"));
- }
}
}
diff --git a/tests/Jellyfin.Naming.Tests/TV/SimpleEpisodeTests.cs b/tests/Jellyfin.Naming.Tests/TV/SimpleEpisodeTests.cs
index c9323c218..de253ce37 100644
--- a/tests/Jellyfin.Naming.Tests/TV/SimpleEpisodeTests.cs
+++ b/tests/Jellyfin.Naming.Tests/TV/SimpleEpisodeTests.cs
@@ -6,81 +6,25 @@ namespace Jellyfin.Naming.Tests.TV
{
public class SimpleEpisodeTests
{
- [Fact]
- public void TestSimpleEpisodePath1()
- {
- Test(@"/server/anything_s01e02.mp4", "anything", 1, 2);
- }
-
- [Fact]
- public void TestSimpleEpisodePath2()
- {
- Test(@"/server/anything_s1e2.mp4", "anything", 1, 2);
- }
-
- [Fact]
- public void TestSimpleEpisodePath3()
- {
- Test(@"/server/anything_s01.e02.mp4", "anything", 1, 2);
- }
-
- [Fact]
- public void TestSimpleEpisodePath4()
- {
- Test(@"/server/anything_s01_e02.mp4", "anything", 1, 2);
- }
-
- [Fact]
- public void TestSimpleEpisodePath5()
- {
- Test(@"/server/anything_102.mp4", "anything", 1, 2);
- }
-
- [Fact]
- public void TestSimpleEpisodePath6()
- {
- Test(@"/server/anything_1x02.mp4", "anything", 1, 2);
- }
-
- // FIXME
- // [Fact]
- public void TestSimpleEpisodePath7()
- {
- Test(@"/server/The Walking Dead 4x01.mp4", "The Walking Dead", 4, 1);
- }
-
- [Fact]
- public void TestSimpleEpisodePath8()
- {
- Test(@"/server/the_simpsons-s02e01_18536.mp4", "the_simpsons", 2, 1);
- }
-
-
- [Fact]
- public void TestSimpleEpisodePath9()
- {
- Test(@"/server/Temp/S01E02 foo.mp4", string.Empty, 1, 2);
- }
-
- [Fact]
- public void TestSimpleEpisodePath10()
- {
- Test(@"Series/4-12 - The Woman.mp4", string.Empty, 4, 12);
- }
-
- [Fact]
- public void TestSimpleEpisodePath11()
- {
- Test(@"Series/4x12 - The Woman.mp4", string.Empty, 4, 12);
- }
-
- [Fact]
- public void TestSimpleEpisodePath12()
- {
- Test(@"Series/LA X, Pt. 1_s06e32.mp4", "LA X, Pt. 1", 6, 32);
- }
-
- private void Test(string path, string seriesName, int? seasonNumber, int? episodeNumber)
+ [Theory]
+ [InlineData("/server/anything_s01e02.mp4", "anything", 1, 2)]
+ [InlineData("/server/anything_s1e2.mp4", "anything", 1, 2)]
+ [InlineData("/server/anything_s01.e02.mp4", "anything", 1, 2)]
+ [InlineData("/server/anything_102.mp4", "anything", 1, 2)]
+ [InlineData("/server/anything_1x02.mp4", "anything", 1, 2)]
+ [InlineData("/server/The Walking Dead 4x01.mp4", "The Walking Dead", 4, 1)]
+ [InlineData("/server/the_simpsons-s02e01_18536.mp4", "the_simpsons", 2, 1)]
+ [InlineData("/server/Temp/S01E02 foo.mp4", "", 1, 2)]
+ [InlineData("Series/4-12 - The Woman.mp4", "", 4, 12)]
+ [InlineData("Series/4x12 - The Woman.mp4", "", 4, 12)]
+ [InlineData("Series/LA X, Pt. 1_s06e32.mp4", "LA X, Pt. 1", 6, 32)]
+ [InlineData("[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)]
+ // TODO: [InlineData("[Baz-Bar]Foo - 01 - 12[1080p][Multiple Subtitle]/[Baz-Bar] Foo - 05 [1080p][Multiple Subtitle].mkv", "Foo", null, 5)]
+ // TODO: [InlineData("E:\\Anime\\Yahari Ore no Seishun Love Comedy wa Machigatteiru\\Yahari Ore no Seishun Love Comedy wa Machigatteiru. Zoku\\Oregairu Zoku 11 - Hayama Hayato Always Renconds to Everyone's Expectations..mkv", "Yahari Ore no Seishun Love Comedy wa Machigatteiru", null, 11)]
+ // TODO: [InlineData(@"/Library/Series/The Grand Tour (2016)/Season 1/S01E01 The Holy Trinity.mkv", "The Grand Tour", 1, 1)]
+ public void Test(string path, string seriesName, int? seasonNumber, int? episodeNumber)
{
var options = new NamingOptions();