Merge remote-tracking branch 'upstream/master' into NetworkPR2

This commit is contained in:
Jim Cartlidge 2020-09-14 16:01:23 +01:00
commit b04aed2f58
9 changed files with 387 additions and 17 deletions

View File

@ -198,3 +198,4 @@
- [tikuf](https://github.com/tikuf/)
- [Tim Hobbs](https://github.com/timhobbs)
- [SvenVandenbrande](https://github.com/SvenVandenbrande)
- [olsh](https://github.com/olsh)

View File

@ -455,7 +455,7 @@ namespace Emby.Drawing
throw new ArgumentException("Path can't be empty.", nameof(path));
}
if (path.IsEmpty)
if (filename.IsEmpty)
{
throw new ArgumentException("Filename can't be empty.", nameof(filename));
}

View File

@ -50,27 +50,14 @@ namespace Emby.Naming.AudioBook
{
if (int.TryParse(value.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intValue))
{
result.ChapterNumber = intValue;
result.PartNumber = intValue;
}
}
}
}
}
/*var matches = _iRegexProvider.GetRegex("\\d+", RegexOptions.IgnoreCase).Matches(fileName);
if (matches.Count > 0)
{
if (!result.ChapterNumber.HasValue)
{
result.ChapterNumber = int.Parse(matches[0].Groups[0].Value);
}
if (matches.Count > 1)
{
result.PartNumber = int.Parse(matches[matches.Count - 1].Groups[0].Value);
}
}*/
result.Success = result.PartNumber.HasValue || result.ChapterNumber.HasValue;
result.Success = result.ChapterNumber.HasValue || result.PartNumber.HasValue;
return result;
}

View File

@ -55,8 +55,8 @@ namespace Emby.Naming.AudioBook
{
Path = path,
Container = container,
PartNumber = parsingResult.PartNumber,
ChapterNumber = parsingResult.ChapterNumber,
PartNumber = parsingResult.PartNumber,
IsDirectory = isDirectory
};
}

View File

@ -0,0 +1,117 @@
{
"MessageApplicationUpdatedTo": "Serveri Jellyfin u përditesua në versionin {0}",
"Inherit": "Trashgimi",
"TaskDownloadMissingSubtitlesDescription": "Kërkon në internet për titra që mungojnë bazuar tek konfigurimi i metadata-ve.",
"TaskDownloadMissingSubtitles": "Shkarko titra që mungojnë",
"TaskRefreshChannelsDescription": "Rifreskon informacionin e kanaleve të internetit.",
"TaskRefreshChannels": "Rifresko Kanalet",
"TaskCleanTranscodeDescription": "Fshin skedarët e transkodimit që janë më të vjetër se një ditë.",
"TaskCleanTranscode": "Fshi dosjen e transkodimit",
"TaskUpdatePluginsDescription": "Shkarkon dhe instalon përditësimi për plugin që janë konfiguruar të përditësohen automatikisht.",
"TaskUpdatePlugins": "Përditëso Plugin",
"TaskRefreshPeopleDescription": "Përditëson metadata të aktorëve dhe regjizorëve në librarinë tuaj.",
"TaskRefreshPeople": "Rifresko aktorët",
"TaskCleanLogsDescription": "Fshin skëdarët log që janë më të vjetër se {0} ditë.",
"TaskCleanLogs": "Fshi dosjen Log",
"TaskRefreshLibraryDescription": "Skanon librarinë media për skedarë të rinj dhe rifreskon metadata.",
"TaskRefreshLibrary": "Skano librarinë media",
"TaskRefreshChapterImagesDescription": "Krijon imazh për videot që kanë kapituj.",
"TaskRefreshChapterImages": "Ekstrakto Imazhet e Kapitullit",
"TaskCleanCacheDescription": "Fshi skedarët e cache-s që nuk i duhen më sistemit.",
"TaskCleanCache": "Pastro memorjen cache",
"TasksChannelsCategory": "Kanalet nga interneti",
"TasksApplicationCategory": "Aplikacioni",
"TasksLibraryCategory": "Libraria",
"TasksMaintenanceCategory": "Mirëmbajtje",
"VersionNumber": "Versioni {0}",
"ValueSpecialEpisodeName": "Speciale - {0}",
"ValueHasBeenAddedToLibrary": "{0} u shtua tek libraria juaj",
"UserStoppedPlayingItemWithValues": "{0} mbaroi së shikuari {1} tek {2}",
"UserStartedPlayingItemWithValues": "{0} po shikon {1} tek {2}",
"UserPolicyUpdatedWithName": "Politika e përdoruesit u përditësua për {0}",
"UserPasswordChangedWithName": "Fjalëkalimi u ndryshua për përdoruesin {0}",
"UserOnlineFromDevice": "{0} është në linjë nga {1}",
"UserOfflineFromDevice": "{0} u shkëput nga {1}",
"UserLockedOutWithName": "Përdoruesi {0} u përjashtua",
"UserDownloadingItemWithValues": "{0} po shkarkon {1}",
"UserDeletedWithName": "Përdoruesi {0} u fshi",
"UserCreatedWithName": "Përdoruesi {0} u krijua",
"User": "Përdoruesi",
"TvShows": "Seriale TV",
"System": "Sistemi",
"Sync": "Sinkronizo",
"SubtitleDownloadFailureFromForItem": "Titrat deshtuan të shkarkohen nga {0} për {1}",
"StartupEmbyServerIsLoading": "Serveri Jellyfin po ngarkohet. Ju lutemi provoni përseri pas pak.",
"Songs": "Këngë",
"Shows": "Seriale",
"ServerNameNeedsToBeRestarted": "{0} duhet të ristartoj",
"ScheduledTaskStartedWithName": "{0} filloi",
"ScheduledTaskFailedWithName": "{0} dështoi",
"ProviderValue": "Ofruesi: {0}",
"PluginUpdatedWithName": "{0} u përditësua",
"PluginUninstalledWithName": "{0} u çinstalua",
"PluginInstalledWithName": "{0} u instalua",
"Plugin": "Plugin",
"Playlists": "Listat për luajtje",
"Photos": "Fotografitë",
"NotificationOptionVideoPlaybackStopped": "Luajtja e videos ndaloi",
"NotificationOptionVideoPlayback": "Luajtja e videos filloi",
"NotificationOptionUserLockedOut": "Përdoruesi u përjashtua",
"NotificationOptionTaskFailed": "Ushtrimi i planifikuar dështoi",
"NotificationOptionServerRestartRequired": "Kërkohet ristartim i serverit",
"NotificationOptionPluginUpdateInstalled": "Përditësimi i plugin u instalua",
"NotificationOptionPluginUninstalled": "Plugin u çinstalua",
"NotificationOptionPluginInstalled": "Plugin u instalua",
"NotificationOptionPluginError": "Plugin dështoi",
"NotificationOptionNewLibraryContent": "Një përmbajtje e re u shtua",
"NotificationOptionInstallationFailed": "Instalimi dështoi",
"NotificationOptionCameraImageUploaded": "Fotoja nga kamera u ngarkua",
"NotificationOptionAudioPlaybackStopped": "Luajtja e audios ndaloi",
"NotificationOptionAudioPlayback": "Luajtja e audios filloi",
"NotificationOptionApplicationUpdateInstalled": "Përditësimi i aplikacionit u instalua",
"NotificationOptionApplicationUpdateAvailable": "Një perditësim i aplikacionit është gati",
"NewVersionIsAvailable": "Një version i ri i Jellyfin është gati për tu shkarkuar.",
"NameSeasonUnknown": "Sezon i panjohur",
"NameSeasonNumber": "Sezoni {0}",
"NameInstallFailed": "Instalimi i {0} dështoi",
"MusicVideos": "Video muzikore",
"Music": "Muzikë",
"Movies": "Filma",
"MixedContent": "Përmbajtje e përzier",
"MessageServerConfigurationUpdated": "Konfigurimet e serverit u përditësuan",
"MessageNamedServerConfigurationUpdatedWithValue": "Seksioni i konfigurimit të serverit {0} u përditësua",
"MessageApplicationUpdated": "Serveri Jellyfin u përditësua",
"Latest": "Të fundit",
"LabelRunningTimeValue": "Kohëzgjatja: {0}",
"LabelIpAddressValue": "Adresa IP: {0}",
"ItemRemovedWithName": "{0} u fshi nga libraria",
"ItemAddedWithName": "{0} u shtua tek libraria",
"HomeVideos": "Video personale",
"HeaderRecordingGroups": "Grupet e regjistrimit",
"HeaderNextUp": "Në vazhdim",
"HeaderLiveTV": "TV Live",
"HeaderFavoriteSongs": "Kënget e preferuara",
"HeaderFavoriteShows": "Serialet e preferuar",
"HeaderFavoriteEpisodes": "Episodet e preferuar",
"HeaderFavoriteArtists": "Artistët e preferuar",
"HeaderFavoriteAlbums": "Albumet e preferuar",
"HeaderContinueWatching": "Vazhdo të shikosh",
"HeaderCameraUploads": "Ngarkimet nga Kamera",
"HeaderAlbumArtists": "Artistët e albumeve",
"Genres": "Zhanre",
"Folders": "Dosje",
"Favorites": "Të preferuara",
"FailedLoginAttemptWithUserName": "Përpjekja për hyrje dështoi nga {0}",
"DeviceOnlineWithName": "{0} u lidh",
"DeviceOfflineWithName": "{0} u shkëput",
"Collections": "Koleksione",
"ChapterNameValue": "Kapituj",
"Channels": "Kanale",
"CameraImageUploadedFrom": "Një foto e re nga kamera u ngarkua nga {0}",
"Books": "Libra",
"AuthenticationSucceededWithUserName": "{0} u identifikua me sukses",
"Artists": "Artistë",
"Application": "Aplikacioni",
"AppDeviceValues": "Aplikacioni: {0}, Pajisja: {1}",
"Albums": "Albumet"
}

View File

@ -0,0 +1,117 @@
{
"Collections": "Bộ Sưu Tập",
"Favorites": "Sở Thích",
"Folders": "Thư Mục",
"Genres": "Thể Loại",
"HeaderAlbumArtists": "Bộ Sưu Tập Nghệ sĩ",
"HeaderContinueWatching": "Tiếp Tục Xem",
"HeaderLiveTV": "TV Trực Tiếp",
"Movies": "Phim",
"Photos": "Ảnh",
"Playlists": "Danh Sách Chơi",
"Shows": "Các Chương Trình",
"Songs": "Các Bài Hát",
"Sync": "Đồng Bộ",
"ValueSpecialEpisodeName": "Đặc Biệt - {0}",
"Albums": "Bộ Sưu Tập",
"Artists": "Nghệ Sĩ",
"TaskDownloadMissingSubtitlesDescription": "Tìm kiếm phụ đề bị thiếu trên Internet dựa trên cấu hình thông tin chi tiết.",
"TaskDownloadMissingSubtitles": "Tải xuống phụ đề bị thiếu",
"TaskRefreshChannelsDescription": "Làm mới thông tin kênh internet.",
"TaskRefreshChannels": "Làm Mới Kênh",
"TaskCleanTranscodeDescription": "Xóa các tệp chuyển mã cũ hơn một ngày.",
"TaskCleanTranscode": "Làm Sạch Thư Mục Chuyển Mã",
"TaskUpdatePluginsDescription": "Tải xuống và cài đặt các bản cập nhật cho các plugin được định cấu hình để cập nhật tự động.",
"TaskUpdatePlugins": "Cập Nhật Plugins",
"TaskRefreshPeopleDescription": "Cập nhật thông tin chi tiết cho diễn viên và đạo diễn trong thư viện phương tiện của bạn.",
"TaskRefreshPeople": "Làm mới Người dùng",
"TaskCleanLogsDescription": "Xóa tập tin nhật ký cũ hơn {0} ngày.",
"TaskCleanLogs": "Làm sạch nhật ký",
"TaskRefreshLibraryDescription": "Quét thư viện phương tiện của bạn để tìm các tệp mới và làm mới thông tin chi tiết.",
"TaskRefreshLibrary": "Quét Thư viện Phương tiện",
"TaskRefreshChapterImagesDescription": "Tạo hình thu nhỏ cho các video có chương.",
"TaskRefreshChapterImages": "Trích xuất hình ảnh chương",
"TaskCleanCacheDescription": "Xóa các tệp cache không còn cần thiết của hệ thống.",
"TaskCleanCache": "Làm Sạch Thư Mục Cache",
"TasksChannelsCategory": "Kênh Internet",
"TasksApplicationCategory": "Ứng Dụng",
"TasksLibraryCategory": "Thư Viện",
"TasksMaintenanceCategory": "Bảo Trì",
"VersionNumber": "Phiên Bản {0}",
"ValueHasBeenAddedToLibrary": "{0} đã được thêm vào thư viện của bạn",
"UserStoppedPlayingItemWithValues": "{0} đã phát xong {1} trên {2}",
"UserStartedPlayingItemWithValues": "{0} đang phát {1} trên {2}",
"UserPolicyUpdatedWithName": "Chính sách người dùng đã được cập nhật cho {0}",
"UserPasswordChangedWithName": "Mật khẩu đã được thay đổi cho người dùng {0}",
"UserOnlineFromDevice": "{0} trực tuyến từ {1}",
"UserOfflineFromDevice": "{0} đã ngắt kết nối từ {1}",
"UserLockedOutWithName": "User {0} đã bị khóa",
"UserDownloadingItemWithValues": "{0} đang tải xuống {1}",
"UserDeletedWithName": "Người Dùng {0} đã được xóa",
"UserCreatedWithName": "Người Dùng {0} đã được tạo",
"User": "Người Dùng",
"TvShows": "Chương Trình TV",
"System": "Hệ Thống",
"SubtitleDownloadFailureFromForItem": "Không thể tải xuống phụ đề từ {0} cho {1}",
"StartupEmbyServerIsLoading": "Jellyfin Server đang tải. Vui lòng thử lại trong thời gian ngắn.",
"ServerNameNeedsToBeRestarted": "{0} cần được khởi động lại",
"ScheduledTaskStartedWithName": "{0} đã bắt đầu",
"ScheduledTaskFailedWithName": "{0} đã thất bại",
"ProviderValue": "Provider: {0}",
"PluginUpdatedWithName": "{0} đã cập nhật",
"PluginUninstalledWithName": "{0} đã được gỡ bỏ",
"PluginInstalledWithName": "{0} đã được cài đặt",
"Plugin": "Plugin",
"NotificationOptionVideoPlaybackStopped": "Phát lại video đã dừng",
"NotificationOptionVideoPlayback": "Đã bắt đầu phát lại video",
"NotificationOptionUserLockedOut": "Người dùng bị khóa",
"NotificationOptionTaskFailed": "Lỗi tác vụ đã lên lịch",
"NotificationOptionServerRestartRequired": "Yêu cầu khởi động lại Server",
"NotificationOptionPluginUpdateInstalled": "Cập nhật Plugin đã được cài đặt",
"NotificationOptionPluginUninstalled": "Đã gỡ bỏ Plugin",
"NotificationOptionPluginInstalled": "Đã cài đặt Plugin",
"NotificationOptionPluginError": "Thất bại Plugin",
"NotificationOptionNewLibraryContent": "Nội dung mới được thêm vào",
"NotificationOptionInstallationFailed": "Cài đặt thất bại",
"NotificationOptionCameraImageUploaded": "Đã tải lên hình ảnh máy ảnh",
"NotificationOptionAudioPlaybackStopped": "Phát lại âm thanh đã dừng",
"NotificationOptionAudioPlayback": "Phát lại âm thanh đã bắt đầu",
"NotificationOptionApplicationUpdateInstalled": "Bản cập nhật ứng dụng đã được cài đặt",
"NotificationOptionApplicationUpdateAvailable": "Bản cập nhật ứng dụng hiện sẵn có",
"NewVersionIsAvailable": "Một phiên bản mới của Jellyfin Server sẵn có để tải.",
"NameSeasonUnknown": "Không Rõ Mùa",
"NameSeasonNumber": "Mùa {0}",
"NameInstallFailed": "{0} cài đặt thất bại",
"MusicVideos": "Video Nhạc",
"Music": "Nhạc",
"MixedContent": "Nội dung hỗn hợp",
"MessageServerConfigurationUpdated": "Cấu hình máy chủ đã được cập nhật",
"MessageNamedServerConfigurationUpdatedWithValue": "Phần cấu hình máy chủ {0} đã được cập nhật",
"MessageApplicationUpdatedTo": "Jellyfin Server đã được cập nhật lên {0}",
"MessageApplicationUpdated": "Jellyfin Server đã được cập nhật",
"Latest": "Gần Nhất",
"LabelRunningTimeValue": "Thời Gian Chạy: {0}",
"LabelIpAddressValue": "Địa Chỉ IP: {0}",
"ItemRemovedWithName": "{0} đã xóa khỏi thư viện",
"ItemAddedWithName": "{0} được thêm vào thư viện",
"Inherit": "Thừa hưởng",
"HomeVideos": "Video nhà",
"HeaderRecordingGroups": "Nhóm Ghi Video",
"HeaderNextUp": "Tiếp Theo",
"HeaderFavoriteSongs": "Bài Hát Yêu Thích",
"HeaderFavoriteShows": "Chương Trình Yêu Thích",
"HeaderFavoriteEpisodes": "Tập Phim Yêu Thích",
"HeaderFavoriteArtists": "Nghệ Sĩ Yêu Thích",
"HeaderFavoriteAlbums": "Album Ưa Thích",
"HeaderCameraUploads": "Máy Ảnh Tải Lên",
"FailedLoginAttemptWithUserName": "Nỗ lực đăng nhập thất bại từ {0}",
"DeviceOnlineWithName": "{0} đã kết nối",
"DeviceOfflineWithName": "{0} đã ngắt kết nối",
"ChapterNameValue": "Chương {0}",
"Channels": "Kênh",
"CameraImageUploadedFrom": "Một hình ảnh máy ảnh mới đã được tải lên từ {0}",
"Books": "Sách",
"AuthenticationSucceededWithUserName": "{0} xác thực thành công",
"Application": "Ứng Dụng",
"AppDeviceValues": "Ứng Dụng: {0}, Thiết Bị: {1}"
}

View File

@ -141,6 +141,7 @@ namespace MediaBrowser.Providers.Plugins.TheTvdb
Name = episode.EpisodeName,
Overview = episode.Overview,
CommunityRating = (float?)episode.SiteRating,
OfficialRating = episode.ContentRating,
}
};
result.ResetPeople();

View File

@ -0,0 +1,90 @@
using System.Linq;
using Emby.Naming.AudioBook;
using Emby.Naming.Common;
using MediaBrowser.Model.IO;
using Xunit;
namespace Jellyfin.Naming.Tests.AudioBook
{
public class AudioBookListResolverTests
{
private readonly NamingOptions _namingOptions = new NamingOptions();
[Fact]
public void TestStackAndExtras()
{
// No stacking here because there is no part/disc/etc
var files = new[]
{
"Harry Potter and the Deathly Hallows/Part 1.mp3",
"Harry Potter and the Deathly Hallows/Part 2.mp3",
"Harry Potter and the Deathly Hallows/book.nfo",
"Batman/Chapter 1.mp3",
"Batman/Chapter 2.mp3",
"Batman/Chapter 3.mp3",
};
var resolver = GetResolver();
var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
})).ToList();
Assert.Equal(2, result[0].Files.Count);
// Assert.Empty(result[0].Extras); FIXME: AudioBookListResolver should resolve extra files properly
Assert.Equal("Harry Potter and the Deathly Hallows", result[0].Name);
Assert.Equal(3, result[1].Files.Count);
Assert.Empty(result[1].Extras);
Assert.Equal("Batman", result[1].Name);
}
[Fact]
public void TestWithMetadata()
{
var files = new[]
{
"Harry Potter and the Deathly Hallows/Chapter 1.ogg",
"Harry Potter and the Deathly Hallows/Harry Potter and the Deathly Hallows.nfo"
};
var resolver = GetResolver();
var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
}));
Assert.Single(result);
}
[Fact]
public void TestWithExtra()
{
var files = new[]
{
"Harry Potter and the Deathly Hallows/Chapter 1.mp3",
"Harry Potter and the Deathly Hallows/Harry Potter and the Deathly Hallows trailer.mp3"
};
var resolver = GetResolver();
var result = resolver.Resolve(files.Select(i => new FileSystemMetadata
{
IsDirectory = false,
FullName = i
})).ToList();
Assert.Single(result);
}
private AudioBookListResolver GetResolver()
{
return new AudioBookListResolver(_namingOptions);
}
}
}

View File

@ -0,0 +1,57 @@
using System.Collections.Generic;
using Emby.Naming.AudioBook;
using Emby.Naming.Common;
using Xunit;
namespace Jellyfin.Naming.Tests.AudioBook
{
public class AudioBookResolverTests
{
private readonly NamingOptions _namingOptions = new NamingOptions();
public static IEnumerable<object[]> GetResolveFileTestData()
{
yield return new object[]
{
new AudioBookFileInfo()
{
Path = @"/server/AudioBooks/Larry Potter/Larry Potter.mp3",
Container = "mp3",
}
};
yield return new object[]
{
new AudioBookFileInfo()
{
Path = @"/server/AudioBooks/Berry Potter/Chapter 1 .ogg",
Container = "ogg",
ChapterNumber = 1
}
};
yield return new object[]
{
new AudioBookFileInfo()
{
Path = @"/server/AudioBooks/Nerry Potter/Part 3 - Chapter 2.mp3",
Container = "mp3",
ChapterNumber = 2,
PartNumber = 3
}
};
}
[Theory]
[MemberData(nameof(GetResolveFileTestData))]
public void ResolveFile_ValidFileName_Success(AudioBookFileInfo expectedResult)
{
var result = new AudioBookResolver(_namingOptions).Resolve(expectedResult.Path);
Assert.NotNull(result);
Assert.Equal(result.Path, expectedResult.Path);
Assert.Equal(result.Container, expectedResult.Container);
Assert.Equal(result.ChapterNumber, expectedResult.ChapterNumber);
Assert.Equal(result.PartNumber, expectedResult.PartNumber);
Assert.Equal(result.IsDirectory, expectedResult.IsDirectory);
}
}
}