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

This commit is contained in:
crobibero 2020-08-12 12:47:25 -06:00
commit 09bcc38feb
18 changed files with 177 additions and 84 deletions

14
.vscode/launch.json vendored
View file

@ -6,11 +6,21 @@
"type": "coreclr", "type": "coreclr",
"request": "launch", "request": "launch",
"preLaunchTask": "build", "preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/netcoreapp3.1/jellyfin.dll", "program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/netcoreapp3.1/jellyfin.dll",
"args": [], "args": [],
"cwd": "${workspaceFolder}/Jellyfin.Server", "cwd": "${workspaceFolder}/Jellyfin.Server",
// For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window "console": "internalConsole",
"stopAtEntry": false,
"internalConsoleOptions": "openOnSessionStart"
},
{
"name": ".NET Core Launch (nowebclient)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/netcoreapp3.1/jellyfin.dll",
"args": ["--nowebclient"],
"cwd": "${workspaceFolder}/Jellyfin.Server",
"console": "internalConsole", "console": "internalConsole",
"stopAtEntry": false, "stopAtEntry": false,
"internalConsoleOptions": "openOnSessionStart" "internalConsoleOptions": "openOnSessionStart"

View file

@ -38,7 +38,7 @@
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.6" /> <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.6" />
<PackageReference Include="Mono.Nat" Version="2.0.2" /> <PackageReference Include="Mono.Nat" Version="2.0.2" />
<PackageReference Include="prometheus-net.DotNetRuntime" Version="3.3.1" /> <PackageReference Include="prometheus-net.DotNetRuntime" Version="3.3.1" />
<PackageReference Include="ServiceStack.Text.Core" Version="5.9.0" /> <PackageReference Include="ServiceStack.Text.Core" Version="5.9.2" />
<PackageReference Include="sharpcompress" Version="0.26.0" /> <PackageReference Include="sharpcompress" Version="0.26.0" />
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="2.1.0" /> <PackageReference Include="SQLitePCL.pretty.netstandard" Version="2.1.0" />
<PackageReference Include="DotNet.Glob" Version="3.0.9" /> <PackageReference Include="DotNet.Glob" Version="3.0.9" />

View file

@ -23,10 +23,12 @@ namespace Emby.Server.Implementations.EntryPoints
public class LibraryChangedNotifier : IServerEntryPoint public class LibraryChangedNotifier : IServerEntryPoint
{ {
/// <summary> /// <summary>
/// The library manager. /// The library update duration.
/// </summary> /// </summary>
private readonly ILibraryManager _libraryManager; private const int LibraryUpdateDuration = 30000;
private readonly ILibraryManager _libraryManager;
private readonly IProviderManager _providerManager;
private readonly ISessionManager _sessionManager; private readonly ISessionManager _sessionManager;
private readonly IUserManager _userManager; private readonly IUserManager _userManager;
private readonly ILogger<LibraryChangedNotifier> _logger; private readonly ILogger<LibraryChangedNotifier> _logger;
@ -38,23 +40,10 @@ namespace Emby.Server.Implementations.EntryPoints
private readonly List<Folder> _foldersAddedTo = new List<Folder>(); private readonly List<Folder> _foldersAddedTo = new List<Folder>();
private readonly List<Folder> _foldersRemovedFrom = new List<Folder>(); private readonly List<Folder> _foldersRemovedFrom = new List<Folder>();
private readonly List<BaseItem> _itemsAdded = new List<BaseItem>(); private readonly List<BaseItem> _itemsAdded = new List<BaseItem>();
private readonly List<BaseItem> _itemsRemoved = new List<BaseItem>(); private readonly List<BaseItem> _itemsRemoved = new List<BaseItem>();
private readonly List<BaseItem> _itemsUpdated = new List<BaseItem>(); private readonly List<BaseItem> _itemsUpdated = new List<BaseItem>();
private readonly Dictionary<Guid, DateTime> _lastProgressMessageTimes = new Dictionary<Guid, DateTime>();
/// <summary>
/// Gets or sets the library update timer.
/// </summary>
/// <value>The library update timer.</value>
private Timer LibraryUpdateTimer { get; set; }
/// <summary>
/// The library update duration.
/// </summary>
private const int LibraryUpdateDuration = 30000;
private readonly IProviderManager _providerManager;
public LibraryChangedNotifier( public LibraryChangedNotifier(
ILibraryManager libraryManager, ILibraryManager libraryManager,
@ -70,22 +59,26 @@ namespace Emby.Server.Implementations.EntryPoints
_providerManager = providerManager; _providerManager = providerManager;
} }
/// <summary>
/// Gets or sets the library update timer.
/// </summary>
/// <value>The library update timer.</value>
private Timer LibraryUpdateTimer { get; set; }
public Task RunAsync() public Task RunAsync()
{ {
_libraryManager.ItemAdded += libraryManager_ItemAdded; _libraryManager.ItemAdded += OnLibraryItemAdded;
_libraryManager.ItemUpdated += libraryManager_ItemUpdated; _libraryManager.ItemUpdated += OnLibraryItemUpdated;
_libraryManager.ItemRemoved += libraryManager_ItemRemoved; _libraryManager.ItemRemoved += OnLibraryItemRemoved;
_providerManager.RefreshCompleted += _providerManager_RefreshCompleted; _providerManager.RefreshCompleted += OnProviderRefreshCompleted;
_providerManager.RefreshStarted += _providerManager_RefreshStarted; _providerManager.RefreshStarted += OnProviderRefreshStarted;
_providerManager.RefreshProgress += _providerManager_RefreshProgress; _providerManager.RefreshProgress += OnProviderRefreshProgress;
return Task.CompletedTask; return Task.CompletedTask;
} }
private Dictionary<Guid, DateTime> _lastProgressMessageTimes = new Dictionary<Guid, DateTime>(); private void OnProviderRefreshProgress(object sender, GenericEventArgs<Tuple<BaseItem, double>> e)
private void _providerManager_RefreshProgress(object sender, GenericEventArgs<Tuple<BaseItem, double>> e)
{ {
var item = e.Argument.Item1; var item = e.Argument.Item1;
@ -122,9 +115,11 @@ namespace Emby.Server.Implementations.EntryPoints
foreach (var collectionFolder in collectionFolders) foreach (var collectionFolder in collectionFolders)
{ {
var collectionFolderDict = new Dictionary<string, string>(); var collectionFolderDict = new Dictionary<string, string>
collectionFolderDict["ItemId"] = collectionFolder.Id.ToString("N", CultureInfo.InvariantCulture); {
collectionFolderDict["Progress"] = (collectionFolder.GetRefreshProgress() ?? 0).ToString(CultureInfo.InvariantCulture); ["ItemId"] = collectionFolder.Id.ToString("N", CultureInfo.InvariantCulture),
["Progress"] = (collectionFolder.GetRefreshProgress() ?? 0).ToString(CultureInfo.InvariantCulture)
};
try try
{ {
@ -136,21 +131,19 @@ namespace Emby.Server.Implementations.EntryPoints
} }
} }
private void _providerManager_RefreshStarted(object sender, GenericEventArgs<BaseItem> e) private void OnProviderRefreshStarted(object sender, GenericEventArgs<BaseItem> e)
{ {
_providerManager_RefreshProgress(sender, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(e.Argument, 0))); OnProviderRefreshProgress(sender, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(e.Argument, 0)));
} }
private void _providerManager_RefreshCompleted(object sender, GenericEventArgs<BaseItem> e) private void OnProviderRefreshCompleted(object sender, GenericEventArgs<BaseItem> e)
{ {
_providerManager_RefreshProgress(sender, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(e.Argument, 100))); OnProviderRefreshProgress(sender, new GenericEventArgs<Tuple<BaseItem, double>>(new Tuple<BaseItem, double>(e.Argument, 100)));
} }
private static bool EnableRefreshMessage(BaseItem item) private static bool EnableRefreshMessage(BaseItem item)
{ {
var folder = item as Folder; if (!(item is Folder folder))
if (folder == null)
{ {
return false; return false;
} }
@ -183,7 +176,7 @@ namespace Emby.Server.Implementations.EntryPoints
/// </summary> /// </summary>
/// <param name="sender">The source of the event.</param> /// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param> /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
void libraryManager_ItemAdded(object sender, ItemChangeEventArgs e) private void OnLibraryItemAdded(object sender, ItemChangeEventArgs e)
{ {
if (!FilterItem(e.Item)) if (!FilterItem(e.Item))
{ {
@ -205,8 +198,7 @@ namespace Emby.Server.Implementations.EntryPoints
LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite); LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
} }
var parent = e.Item.GetParent() as Folder; if (e.Item.GetParent() is Folder parent)
if (parent != null)
{ {
_foldersAddedTo.Add(parent); _foldersAddedTo.Add(parent);
} }
@ -220,7 +212,7 @@ namespace Emby.Server.Implementations.EntryPoints
/// </summary> /// </summary>
/// <param name="sender">The source of the event.</param> /// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param> /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
void libraryManager_ItemUpdated(object sender, ItemChangeEventArgs e) private void OnLibraryItemUpdated(object sender, ItemChangeEventArgs e)
{ {
if (!FilterItem(e.Item)) if (!FilterItem(e.Item))
{ {
@ -231,8 +223,7 @@ namespace Emby.Server.Implementations.EntryPoints
{ {
if (LibraryUpdateTimer == null) if (LibraryUpdateTimer == null)
{ {
LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration, LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration, Timeout.Infinite);
Timeout.Infinite);
} }
else else
{ {
@ -248,7 +239,7 @@ namespace Emby.Server.Implementations.EntryPoints
/// </summary> /// </summary>
/// <param name="sender">The source of the event.</param> /// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param> /// <param name="e">The <see cref="ItemChangeEventArgs"/> instance containing the event data.</param>
void libraryManager_ItemRemoved(object sender, ItemChangeEventArgs e) private void OnLibraryItemRemoved(object sender, ItemChangeEventArgs e)
{ {
if (!FilterItem(e.Item)) if (!FilterItem(e.Item))
{ {
@ -259,16 +250,14 @@ namespace Emby.Server.Implementations.EntryPoints
{ {
if (LibraryUpdateTimer == null) if (LibraryUpdateTimer == null)
{ {
LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration, LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, LibraryUpdateDuration, Timeout.Infinite);
Timeout.Infinite);
} }
else else
{ {
LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite); LibraryUpdateTimer.Change(LibraryUpdateDuration, Timeout.Infinite);
} }
var parent = e.Parent as Folder; if (e.Parent is Folder parent)
if (parent != null)
{ {
_foldersRemovedFrom.Add(parent); _foldersRemovedFrom.Add(parent);
} }
@ -486,13 +475,13 @@ namespace Emby.Server.Implementations.EntryPoints
LibraryUpdateTimer = null; LibraryUpdateTimer = null;
} }
_libraryManager.ItemAdded -= libraryManager_ItemAdded; _libraryManager.ItemAdded -= OnLibraryItemAdded;
_libraryManager.ItemUpdated -= libraryManager_ItemUpdated; _libraryManager.ItemUpdated -= OnLibraryItemUpdated;
_libraryManager.ItemRemoved -= libraryManager_ItemRemoved; _libraryManager.ItemRemoved -= OnLibraryItemRemoved;
_providerManager.RefreshCompleted -= _providerManager_RefreshCompleted; _providerManager.RefreshCompleted -= OnProviderRefreshCompleted;
_providerManager.RefreshStarted -= _providerManager_RefreshStarted; _providerManager.RefreshStarted -= OnProviderRefreshStarted;
_providerManager.RefreshProgress -= _providerManager_RefreshProgress; _providerManager.RefreshProgress -= OnProviderRefreshProgress;
} }
} }
} }

View file

@ -5,7 +5,7 @@
"Artists": "Interpreten", "Artists": "Interpreten",
"AuthenticationSucceededWithUserName": "{0} hat sich erfolgreich angemeldet", "AuthenticationSucceededWithUserName": "{0} hat sich erfolgreich angemeldet",
"Books": "Bücher", "Books": "Bücher",
"CameraImageUploadedFrom": "Ein neues Foto wurde von {0} hochgeladen", "CameraImageUploadedFrom": "Ein neues Kamerafoto wurde von {0} hochgeladen",
"Channels": "Kanäle", "Channels": "Kanäle",
"ChapterNameValue": "Kapitel {0}", "ChapterNameValue": "Kapitel {0}",
"Collections": "Sammlungen", "Collections": "Sammlungen",
@ -106,7 +106,7 @@
"TaskCleanLogsDescription": "Lösche Log Dateien die älter als {0} Tage sind.", "TaskCleanLogsDescription": "Lösche Log Dateien die älter als {0} Tage sind.",
"TaskCleanLogs": "Lösche Log Pfad", "TaskCleanLogs": "Lösche Log Pfad",
"TaskRefreshLibraryDescription": "Scanne alle Bibliotheken für hinzugefügte Datein und erneuere Metadaten.", "TaskRefreshLibraryDescription": "Scanne alle Bibliotheken für hinzugefügte Datein und erneuere Metadaten.",
"TaskRefreshLibrary": "Scanne alle Bibliotheken", "TaskRefreshLibrary": "Scanne Medien-Bibliothek",
"TaskRefreshChapterImagesDescription": "Kreiert Vorschaubilder für Videos welche Kapitel haben.", "TaskRefreshChapterImagesDescription": "Kreiert Vorschaubilder für Videos welche Kapitel haben.",
"TaskRefreshChapterImages": "Extrahiert Kapitel-Bilder", "TaskRefreshChapterImages": "Extrahiert Kapitel-Bilder",
"TaskCleanCacheDescription": "Löscht Zwischenspeicherdatein die nicht länger von System gebraucht werden.", "TaskCleanCacheDescription": "Löscht Zwischenspeicherdatein die nicht länger von System gebraucht werden.",

View file

@ -1,13 +1,13 @@
{ {
"MusicVideos": "Музичні відео", "MusicVideos": "Музичні кліпи",
"Music": "Музика", "Music": "Музика",
"Movies": "Фільми", "Movies": "Фільми",
"MessageApplicationUpdatedTo": "Jellyfin Server був оновлений до версії {0}", "MessageApplicationUpdatedTo": "Jellyfin Server оновлено до версії {0}",
"MessageApplicationUpdated": "Jellyfin Server був оновлений", "MessageApplicationUpdated": "Jellyfin Server оновлено",
"Latest": "Останні", "Latest": "Останні",
"LabelIpAddressValue": "IP-адреси: {0}", "LabelIpAddressValue": "IP-адреса: {0}",
"ItemRemovedWithName": "{0} видалено з бібліотеки", "ItemRemovedWithName": "{0} видалено з медіатеки",
"ItemAddedWithName": "{0} додано до бібліотеки", "ItemAddedWithName": "{0} додано до медіатеки",
"HeaderNextUp": "Наступний", "HeaderNextUp": "Наступний",
"HeaderLiveTV": "Ефірне ТБ", "HeaderLiveTV": "Ефірне ТБ",
"HeaderFavoriteSongs": "Улюблені пісні", "HeaderFavoriteSongs": "Улюблені пісні",
@ -17,20 +17,101 @@
"HeaderFavoriteAlbums": "Улюблені альбоми", "HeaderFavoriteAlbums": "Улюблені альбоми",
"HeaderContinueWatching": "Продовжити перегляд", "HeaderContinueWatching": "Продовжити перегляд",
"HeaderCameraUploads": "Завантажено з камери", "HeaderCameraUploads": "Завантажено з камери",
"HeaderAlbumArtists": "Виконавці альбомів", "HeaderAlbumArtists": "Виконавці альбому",
"Genres": "Жанри", "Genres": "Жанри",
"Folders": "Директорії", "Folders": "Каталоги",
"Favorites": "Улюблені", "Favorites": "Улюблені",
"DeviceOnlineWithName": "{0} під'єднано", "DeviceOnlineWithName": "Пристрій {0} підключився",
"DeviceOfflineWithName": "{0} від'єднано", "DeviceOfflineWithName": "Пристрій {0} відключився",
"Collections": "Колекції", "Collections": "Колекції",
"ChapterNameValue": "Глава {0}", "ChapterNameValue": "Розділ {0}",
"Channels": "Канали", "Channels": "Канали",
"CameraImageUploadedFrom": "Нова фотографія завантажена з {0}", "CameraImageUploadedFrom": "Нова фотографія завантажена з {0}",
"Books": "Книги", "Books": "Книги",
"AuthenticationSucceededWithUserName": "{0} успішно авторизовані", "AuthenticationSucceededWithUserName": "{0} успішно авторизований",
"Artists": "Виконавці", "Artists": "Виконавці",
"Application": "Додаток", "Application": "Додаток",
"AppDeviceValues": "Додаток: {0}, Пристрій: {1}", "AppDeviceValues": "Додаток: {0}, Пристрій: {1}",
"Albums": "Альбоми" "Albums": "Альбоми",
"NotificationOptionServerRestartRequired": "Необхідно перезапустити сервер",
"NotificationOptionPluginUpdateInstalled": "Встановлено оновлення плагіна",
"NotificationOptionPluginUninstalled": "Плагін видалено",
"NotificationOptionPluginInstalled": "Плагін встановлено",
"NotificationOptionPluginError": "Помилка плагіна",
"NotificationOptionNewLibraryContent": "Додано новий контент",
"HomeVideos": "Домашнє відео",
"FailedLoginAttemptWithUserName": "Невдала спроба входу від {0}",
"LabelRunningTimeValue": "Тривалість: {0}",
"TaskDownloadMissingSubtitlesDescription": "Шукає в Інтернеті відсутні субтитри на основі конфігурації метаданих.",
"TaskDownloadMissingSubtitles": "Завантажити відсутні субтитри",
"TaskRefreshChannelsDescription": "Оновлення інформації про Інтернет-канали.",
"TaskRefreshChannels": "Оновити канали",
"TaskCleanTranscodeDescription": "Вилучає файли для перекодування старше одного дня.",
"TaskCleanTranscode": "Очистити каталог перекодування",
"TaskUpdatePluginsDescription": "Завантажує та встановлює оновлення для плагінів, налаштованих на автоматичне оновлення.",
"TaskUpdatePlugins": "Оновити плагіни",
"TaskRefreshPeopleDescription": "Оновлення метаданих для акторів та режисерів у вашій медіатеці.",
"TaskRefreshPeople": "Оновити людей",
"TaskCleanLogsDescription": "Видаляє файли журналу, яким більше {0} днів.",
"TaskCleanLogs": "Очистити журнали",
"TaskRefreshLibraryDescription": "Сканує медіатеку на нові файли та оновлює метадані.",
"TaskRefreshLibrary": "Сканувати медіатеку",
"TaskRefreshChapterImagesDescription": "Створює ескізи для відео, які мають розділи.",
"TaskRefreshChapterImages": "Створити ескізи розділів",
"TaskCleanCacheDescription": "Видаляє файли кешу, які більше не потрібні системі.",
"TaskCleanCache": "Очистити кеш",
"TasksChannelsCategory": "Інтернет-канали",
"TasksApplicationCategory": "Додаток",
"TasksLibraryCategory": "Медіатека",
"TasksMaintenanceCategory": "Обслуговування",
"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": "Синхронізація",
"SubtitleDownloadFailureFromForItem": "Не вдалося завантажити субтитри з {0} для {1}",
"StartupEmbyServerIsLoading": "Jellyfin Server завантажується. Будь ласка, спробуйте трішки пізніше.",
"Songs": "Пісні",
"Shows": "Шоу",
"ServerNameNeedsToBeRestarted": "{0} потрібно перезапустити",
"ScheduledTaskStartedWithName": "{0} розпочато",
"ScheduledTaskFailedWithName": "Помилка {0}",
"ProviderValue": "Постачальник: {0}",
"PluginUpdatedWithName": "{0} оновлено",
"PluginUninstalledWithName": "{0} видалено",
"PluginInstalledWithName": "{0} встановлено",
"Plugin": "Плагін",
"Playlists": "Плейлисти",
"Photos": "Фотографії",
"NotificationOptionVideoPlaybackStopped": "Відтворення відео зупинено",
"NotificationOptionVideoPlayback": "Розпочато відтворення відео",
"NotificationOptionUserLockedOut": "Користувача заблоковано",
"NotificationOptionTaskFailed": "Помилка запланованого завдання",
"NotificationOptionInstallationFailed": "Помилка встановлення",
"NotificationOptionCameraImageUploaded": "Фотографію завантажено",
"NotificationOptionAudioPlaybackStopped": "Відтворення аудіо зупинено",
"NotificationOptionAudioPlayback": "Розпочато відтворення аудіо",
"NotificationOptionApplicationUpdateInstalled": "Встановлено оновлення додатка",
"NotificationOptionApplicationUpdateAvailable": "Доступне оновлення додатка",
"NewVersionIsAvailable": "Для завантаження доступна нова версія Jellyfin Server.",
"NameSeasonUnknown": "Сезон Невідомий",
"NameSeasonNumber": "Сезон {0}",
"NameInstallFailed": "Не вдалося встановити {0}",
"MixedContent": "Змішаний контент",
"MessageServerConfigurationUpdated": "Конфігурація сервера оновлена",
"MessageNamedServerConfigurationUpdatedWithValue": "Розділ конфігурації сервера {0} оновлено",
"Inherit": "Успадкувати",
"HeaderRecordingGroups": "Групи запису"
} }

View file

@ -1,5 +1,4 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Api.Auth.IgnoreParentalControlPolicy;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Library;
@ -11,7 +10,7 @@ namespace Jellyfin.Api.Auth.FirstTimeOrIgnoreParentalControlSetupPolicy
/// <summary> /// <summary>
/// Ignore parental control schedule and allow before startup wizard has been completed. /// Ignore parental control schedule and allow before startup wizard has been completed.
/// </summary> /// </summary>
public class FirstTimeOrIgnoreParentalControlSetupHandler : BaseAuthorizationHandler<IgnoreParentalControlRequirement> public class FirstTimeOrIgnoreParentalControlSetupHandler : BaseAuthorizationHandler<FirstTimeOrIgnoreParentalControlSetupRequirement>
{ {
private readonly IConfigurationManager _configurationManager; private readonly IConfigurationManager _configurationManager;
@ -33,7 +32,7 @@ namespace Jellyfin.Api.Auth.FirstTimeOrIgnoreParentalControlSetupPolicy
} }
/// <inheritdoc /> /// <inheritdoc />
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IgnoreParentalControlRequirement requirement) protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, FirstTimeOrIgnoreParentalControlSetupRequirement requirement)
{ {
if (!_configurationManager.CommonConfiguration.IsStartupWizardCompleted) if (!_configurationManager.CommonConfiguration.IsStartupWizardCompleted)
{ {

View file

@ -386,7 +386,7 @@ namespace Jellyfin.Api.Controllers
var user = _userManager.GetUserById(userId); var user = _userManager.GetUserById(userId);
// If removing admin access // If removing admin access
if (!(newPolicy.IsAdministrator && user.HasPermission(PermissionKind.IsAdministrator))) if (!newPolicy.IsAdministrator && user.HasPermission(PermissionKind.IsAdministrator))
{ {
if (_userManager.Users.Count(i => i.HasPermission(PermissionKind.IsAdministrator)) == 1) if (_userManager.Users.Count(i => i.HasPermission(PermissionKind.IsAdministrator)) == 1)
{ {

View file

@ -18,7 +18,7 @@
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="3.1.6" /> <PackageReference Include="Microsoft.Extensions.Http" Version="3.1.6" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.5.1" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="5.5.1" />
<PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="5.3.3" /> <PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="5.5.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -115,7 +115,7 @@ namespace Jellyfin.Drawing.Skia
// resize to the same aspect as the original // resize to the same aspect as the original
int iWidth = Math.Abs(iHeight * currentBitmap.Width / currentBitmap.Height); int iWidth = Math.Abs(iHeight * currentBitmap.Width / currentBitmap.Height);
using var resizedImage = SkiaEncoder.ResizeImage(bitmap, new SKImageInfo(iWidth, iHeight, currentBitmap.ColorType, currentBitmap.AlphaType, currentBitmap.ColorSpace)); using var resizedImage = SkiaEncoder.ResizeImage(currentBitmap, new SKImageInfo(iWidth, iHeight, currentBitmap.ColorType, currentBitmap.AlphaType, currentBitmap.ColorSpace));
// crop image // crop image
int ix = Math.Abs((iWidth - iSlice) / 2); int ix = Math.Abs((iWidth - iSlice) / 2);
@ -177,7 +177,7 @@ namespace Jellyfin.Drawing.Skia
// Scale image. The FromBitmap creates a copy // Scale image. The FromBitmap creates a copy
var imageInfo = new SKImageInfo(cellWidth, cellHeight, currentBitmap.ColorType, currentBitmap.AlphaType, currentBitmap.ColorSpace); var imageInfo = new SKImageInfo(cellWidth, cellHeight, currentBitmap.ColorType, currentBitmap.AlphaType, currentBitmap.ColorSpace);
using var resizedBitmap = SKBitmap.FromImage(SkiaEncoder.ResizeImage(bitmap, imageInfo)); using var resizedBitmap = SKBitmap.FromImage(SkiaEncoder.ResizeImage(currentBitmap, imageInfo));
// draw this image into the strip at the next position // draw this image into the strip at the next position
var xPos = x * cellWidth; var xPos = x * cellWidth;

View file

@ -4,6 +4,8 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net;
using System.Net.Mime;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Jellyfin.Data.Entities; using Jellyfin.Data.Entities;
@ -22,6 +24,7 @@ using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Events; using MediaBrowser.Model.Events;
using MediaBrowser.Model.IO; using MediaBrowser.Model.IO;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Providers; using MediaBrowser.Model.Providers;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Priority_Queue; using Priority_Queue;
@ -169,6 +172,15 @@ namespace MediaBrowser.Providers.Manager
} }
} }
// thetvdb will sometimes serve a rubbish 404 html page with a 200 OK code, because reasons...
if (response.ContentType.Equals(MediaTypeNames.Text.Html, StringComparison.OrdinalIgnoreCase))
{
throw new HttpException("Invalid image received.")
{
StatusCode = HttpStatusCode.NotFound
};
}
await SaveImage(item, response.Content, response.ContentType, type, imageIndex, cancellationToken).ConfigureAwait(false); await SaveImage(item, response.Content, response.ContentType, type, imageIndex, cancellationToken).ConfigureAwait(false);
} }

View file

@ -20,7 +20,7 @@
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.6" /> <PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.6" />
<PackageReference Include="OptimizedPriorityQueue" Version="4.2.0" /> <PackageReference Include="OptimizedPriorityQueue" Version="4.2.0" />
<PackageReference Include="PlaylistsNET" Version="1.1.2" /> <PackageReference Include="PlaylistsNET" Version="1.1.2" />
<PackageReference Include="TvDbSharper" Version="3.2.0" /> <PackageReference Include="TvDbSharper" Version="3.2.1" />
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>

View file

@ -166,3 +166,5 @@ To instruct the server not to host the web content, there is a `nowebclient` con
switch `--nowebclient` or the environment variable `JELLYFIN_NOWEBCONTENT=true`. switch `--nowebclient` or the environment variable `JELLYFIN_NOWEBCONTENT=true`.
Since this is a common scenario, there is also a separate launch profile defined for Visual Studio called `Jellyfin.Server (nowebcontent)` that can be selected from the 'Start Debugging' dropdown in the main toolbar. Since this is a common scenario, there is also a separate launch profile defined for Visual Studio called `Jellyfin.Server (nowebcontent)` that can be selected from the 'Start Debugging' dropdown in the main toolbar.
**NOTE:** The setup wizard can not be run if the web client is hosted separately.

View file

@ -17,7 +17,7 @@
<PackageReference Include="AutoFixture.AutoMoq" Version="4.12.0" /> <PackageReference Include="AutoFixture.AutoMoq" Version="4.12.0" />
<PackageReference Include="AutoFixture.Xunit2" Version="4.12.0" /> <PackageReference Include="AutoFixture.Xunit2" Version="4.12.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="3.1.6" /> <PackageReference Include="Microsoft.Extensions.Options" Version="3.1.6" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageReference Include="coverlet.collector" Version="1.3.0" /> <PackageReference Include="coverlet.collector" Version="1.3.0" />

View file

@ -13,7 +13,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageReference Include="coverlet.collector" Version="1.3.0" /> <PackageReference Include="coverlet.collector" Version="1.3.0" />

View file

@ -13,7 +13,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageReference Include="coverlet.collector" Version="1.3.0" /> <PackageReference Include="coverlet.collector" Version="1.3.0" />

View file

@ -19,7 +19,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageReference Include="coverlet.collector" Version="1.3.0" /> <PackageReference Include="coverlet.collector" Version="1.3.0" />

View file

@ -13,7 +13,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageReference Include="coverlet.collector" Version="1.3.0" /> <PackageReference Include="coverlet.collector" Version="1.3.0" />

View file

@ -9,7 +9,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.6" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" Version="3.1.6" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" /> <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
<PackageReference Include="coverlet.collector" Version="1.3.0" /> <PackageReference Include="coverlet.collector" Version="1.3.0" />