aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations')
-rw-r--r--Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs56
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs12
-rw-r--r--Emby.Server.Implementations/Channels/ChannelManager.cs13
-rw-r--r--Emby.Server.Implementations/Collections/CollectionManager.cs1
-rw-r--r--Emby.Server.Implementations/Data/BaseSqliteRepository.cs5
-rw-r--r--Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs1
-rw-r--r--Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs8
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs134
-rw-r--r--Emby.Server.Implementations/Data/SqliteUserDataRepository.cs12
-rw-r--r--Emby.Server.Implementations/Data/SqliteUserRepository.cs240
-rw-r--r--Emby.Server.Implementations/Devices/DeviceManager.cs32
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs55
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj4
-rw-r--r--Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs2
-rw-r--r--Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs3
-rw-r--r--Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs77
-rw-r--r--Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs30
-rw-r--r--Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs1
-rw-r--r--Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs2
-rw-r--r--Emby.Server.Implementations/HttpServer/FileWriter.cs4
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpListenerHost.cs3
-rw-r--r--Emby.Server.Implementations/HttpServer/HttpResultFactory.cs3
-rw-r--r--Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs15
-rw-r--r--Emby.Server.Implementations/HttpServer/ResponseFilter.cs1
-rw-r--r--Emby.Server.Implementations/HttpServer/Security/AuthService.cs25
-rw-r--r--Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs7
-rw-r--r--Emby.Server.Implementations/HttpServer/Security/SessionContext.cs2
-rw-r--r--Emby.Server.Implementations/HttpServer/WebSocketConnection.cs10
-rw-r--r--Emby.Server.Implementations/IO/LibraryMonitor.cs2
-rw-r--r--Emby.Server.Implementations/IO/ManagedFileSystem.cs4
-rw-r--r--Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs1
-rw-r--r--Emby.Server.Implementations/Images/DynamicImageProvider.cs1
-rw-r--r--Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs2
-rw-r--r--Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs139
-rw-r--r--Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs140
-rw-r--r--Emby.Server.Implementations/Library/ExclusiveLiveStream.cs2
-rw-r--r--Emby.Server.Implementations/Library/IgnorePatterns.cs6
-rw-r--r--Emby.Server.Implementations/Library/InvalidAuthProvider.cs54
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs30
-rw-r--r--Emby.Server.Implementations/Library/LiveStreamHelper.cs7
-rw-r--r--Emby.Server.Implementations/Library/MediaSourceManager.cs61
-rw-r--r--Emby.Server.Implementations/Library/MediaStreamSelector.cs2
-rw-r--r--Emby.Server.Implementations/Library/MusicManager.cs18
-rw-r--r--Emby.Server.Implementations/Library/ResolverHelper.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs4
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs4
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs5
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs1
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs1
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/SearchEngine.cs5
-rw-r--r--Emby.Server.Implementations/Library/UserDataManager.cs6
-rw-r--r--Emby.Server.Implementations/Library/UserManager.cs1107
-rw-r--r--Emby.Server.Implementations/Library/UserViewManager.cs30
-rw-r--r--Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs1
-rw-r--r--Emby.Server.Implementations/Library/Validators/StudiosValidator.cs1
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs1
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs10
-rw-r--r--Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs1
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs127
-rw-r--r--Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs1
-rw-r--r--Emby.Server.Implementations/LiveTv/LiveTvManager.cs57
-rw-r--r--Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs2
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs4
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs26
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs14
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs5
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs1
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs3
-rw-r--r--Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs20
-rw-r--r--Emby.Server.Implementations/Localization/Core/bn.json19
-rw-r--r--Emby.Server.Implementations/Localization/Core/fr-CA.json5
-rw-r--r--Emby.Server.Implementations/Net/SocketFactory.cs4
-rw-r--r--Emby.Server.Implementations/Networking/NetworkManager.cs4
-rw-r--r--Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs3
-rw-r--r--Emby.Server.Implementations/Playlists/PlaylistManager.cs6
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs23
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/TaskManager.cs8
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs2
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs8
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs2
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs4
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs6
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs4
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs8
-rw-r--r--Emby.Server.Implementations/Security/AuthenticationRepository.cs4
-rw-r--r--Emby.Server.Implementations/Services/ResponseHelper.cs4
-rw-r--r--Emby.Server.Implementations/Services/ServiceController.cs6
-rw-r--r--Emby.Server.Implementations/Services/ServiceHandler.cs2
-rw-r--r--Emby.Server.Implementations/Services/ServiceMethod.cs1
-rw-r--r--Emby.Server.Implementations/Services/ServicePath.cs17
-rw-r--r--Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs4
-rw-r--r--Emby.Server.Implementations/Services/SwaggerService.cs34
-rw-r--r--Emby.Server.Implementations/Services/UrlExtensions.cs2
-rw-r--r--Emby.Server.Implementations/Session/SessionManager.cs84
-rw-r--r--Emby.Server.Implementations/Session/SessionWebSocketListener.cs7
-rw-r--r--Emby.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/AlbumComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/CriticRatingComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/DateCreatedComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs1
-rw-r--r--Emby.Server.Implementations/Sorting/DatePlayedComparer.cs3
-rw-r--r--Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs1
-rw-r--r--Emby.Server.Implementations/Sorting/IsPlayedComparer.cs1
-rw-r--r--Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs1
-rw-r--r--Emby.Server.Implementations/Sorting/NameComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/PlayCountComparer.cs3
-rw-r--r--Emby.Server.Implementations/Sorting/PremiereDateComparer.cs3
-rw-r--r--Emby.Server.Implementations/Sorting/ProductionYearComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/RandomComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/RuntimeComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/SortNameComparer.cs2
-rw-r--r--Emby.Server.Implementations/SyncPlay/SyncPlayController.cs24
-rw-r--r--Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs91
-rw-r--r--Emby.Server.Implementations/TV/TVSeriesManager.cs18
-rw-r--r--Emby.Server.Implementations/Udp/UdpServer.cs2
119 files changed, 824 insertions, 2287 deletions
diff --git a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
index 6917efefa..84bec9201 100644
--- a/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
+++ b/Emby.Server.Implementations/Activity/ActivityLogEntryPoint.cs
@@ -88,25 +88,26 @@ namespace Emby.Server.Implementations.Activity
_subManager.SubtitleDownloadFailure += OnSubtitleDownloadFailure;
- _userManager.UserCreated += OnUserCreated;
- _userManager.UserPasswordChanged += OnUserPasswordChanged;
- _userManager.UserDeleted += OnUserDeleted;
- _userManager.UserPolicyUpdated += OnUserPolicyUpdated;
- _userManager.UserLockedOut += OnUserLockedOut;
+ _userManager.OnUserCreated += OnUserCreated;
+ _userManager.OnUserPasswordChanged += OnUserPasswordChanged;
+ _userManager.OnUserDeleted += OnUserDeleted;
+ _userManager.OnUserLockedOut += OnUserLockedOut;
return Task.CompletedTask;
}
- private async void OnUserLockedOut(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
+ private async void OnUserLockedOut(object sender, GenericEventArgs<User> e)
{
await CreateLogEntry(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("UserLockedOutWithName"),
- e.Argument.Name),
+ e.Argument.Username),
NotificationType.UserLockedOut.ToString(),
- e.Argument.Id))
- .ConfigureAwait(false);
+ e.Argument.Id)
+ {
+ LogSeverity = LogLevel.Error
+ }).ConfigureAwait(false);
}
private async void OnSubtitleDownloadFailure(object sender, SubtitleDownloadFailureEventArgs e)
@@ -152,7 +153,7 @@ namespace Emby.Server.Implementations.Activity
string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("UserStoppedPlayingItemWithValues"),
- user.Name,
+ user.Username,
GetItemName(item),
e.DeviceName),
GetPlaybackStoppedNotificationType(item.MediaType),
@@ -187,7 +188,7 @@ namespace Emby.Server.Implementations.Activity
string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("UserStartedPlayingItemWithValues"),
- user.Name,
+ user.Username,
GetItemName(item),
e.DeviceName),
GetPlaybackNotificationType(item.MediaType),
@@ -304,49 +305,37 @@ namespace Emby.Server.Implementations.Activity
}).ConfigureAwait(false);
}
- private async void OnUserPolicyUpdated(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
- {
- await CreateLogEntry(new ActivityLog(
- string.Format(
- CultureInfo.InvariantCulture,
- _localization.GetLocalizedString("UserPolicyUpdatedWithName"),
- e.Argument.Name),
- "UserPolicyUpdated",
- e.Argument.Id))
- .ConfigureAwait(false);
- }
-
- private async void OnUserDeleted(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
+ private async void OnUserDeleted(object sender, GenericEventArgs<User> e)
{
await CreateLogEntry(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("UserDeletedWithName"),
- e.Argument.Name),
+ e.Argument.Username),
"UserDeleted",
Guid.Empty))
.ConfigureAwait(false);
}
- private async void OnUserPasswordChanged(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
+ private async void OnUserPasswordChanged(object sender, GenericEventArgs<User> e)
{
await CreateLogEntry(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("UserPasswordChangedWithName"),
- e.Argument.Name),
+ e.Argument.Username),
"UserPasswordChanged",
e.Argument.Id))
.ConfigureAwait(false);
}
- private async void OnUserCreated(object sender, GenericEventArgs<MediaBrowser.Controller.Entities.User> e)
+ private async void OnUserCreated(object sender, GenericEventArgs<User> e)
{
await CreateLogEntry(new ActivityLog(
string.Format(
CultureInfo.InvariantCulture,
_localization.GetLocalizedString("UserCreatedWithName"),
- e.Argument.Name),
+ e.Argument.Username),
"UserCreated",
e.Argument.Id))
.ConfigureAwait(false);
@@ -510,11 +499,10 @@ namespace Emby.Server.Implementations.Activity
_subManager.SubtitleDownloadFailure -= OnSubtitleDownloadFailure;
- _userManager.UserCreated -= OnUserCreated;
- _userManager.UserPasswordChanged -= OnUserPasswordChanged;
- _userManager.UserDeleted -= OnUserDeleted;
- _userManager.UserPolicyUpdated -= OnUserPolicyUpdated;
- _userManager.UserLockedOut -= OnUserLockedOut;
+ _userManager.OnUserCreated -= OnUserCreated;
+ _userManager.OnUserPasswordChanged -= OnUserPasswordChanged;
+ _userManager.OnUserDeleted -= OnUserDeleted;
+ _userManager.OnUserLockedOut -= OnUserLockedOut;
}
/// <summary>
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 184c6f399..23f0571a1 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -562,11 +562,8 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton<IAuthenticationRepository, AuthenticationRepository>();
- serviceCollection.AddSingleton<IUserRepository, SqliteUserRepository>();
-
// TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
serviceCollection.AddTransient(provider => new Lazy<IDtoService>(provider.GetRequiredService<IDtoService>));
- serviceCollection.AddSingleton<IUserManager, UserManager>();
// TODO: Refactor to eliminate the circular dependency here so that Lazy<T> isn't required
// TODO: Add StartupOptions.FFmpegPath to IConfiguration and remove this custom activation
@@ -659,15 +656,11 @@ namespace Emby.Server.Implementations
((SqliteDisplayPreferencesRepository)Resolve<IDisplayPreferencesRepository>()).Initialize();
((AuthenticationRepository)Resolve<IAuthenticationRepository>()).Initialize();
- ((SqliteUserRepository)Resolve<IUserRepository>()).Initialize();
SetStaticProperties();
- var userManager = (UserManager)Resolve<IUserManager>();
- userManager.Initialize();
-
var userDataRepo = (SqliteUserDataRepository)Resolve<IUserDataRepository>();
- ((SqliteItemRepository)Resolve<IItemRepository>()).Initialize(userDataRepo, userManager);
+ ((SqliteItemRepository)Resolve<IItemRepository>()).Initialize(userDataRepo, Resolve<IUserManager>());
FindParts();
}
@@ -750,7 +743,6 @@ namespace Emby.Server.Implementations
BaseItem.ProviderManager = Resolve<IProviderManager>();
BaseItem.LocalizationManager = Resolve<ILocalizationManager>();
BaseItem.ItemRepository = Resolve<IItemRepository>();
- User.UserManager = Resolve<IUserManager>();
BaseItem.FileSystem = _fileSystemManager;
BaseItem.UserDataManager = Resolve<IUserDataManager>();
BaseItem.ChannelManager = Resolve<IChannelManager>();
@@ -964,7 +956,7 @@ namespace Emby.Server.Implementations
}
/// <summary>
- /// Notifies that the kernel that a change has been made that requires a restart
+ /// Notifies that the kernel that a change has been made that requires a restart.
/// </summary>
public void NotifyPendingRestart()
{
diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs
index f9eea66b4..c803d9d82 100644
--- a/Emby.Server.Implementations/Channels/ChannelManager.cs
+++ b/Emby.Server.Implementations/Channels/ChannelManager.cs
@@ -6,6 +6,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Entities;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Progress;
using MediaBrowser.Controller.Channels;
@@ -13,8 +14,6 @@ using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Channels;
@@ -24,6 +23,11 @@ using MediaBrowser.Model.IO;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Serialization;
using Microsoft.Extensions.Logging;
+using Episode = MediaBrowser.Controller.Entities.TV.Episode;
+using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
+using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
+using Season = MediaBrowser.Controller.Entities.TV.Season;
+using Series = MediaBrowser.Controller.Entities.TV.Series;
namespace Emby.Server.Implementations.Channels
{
@@ -791,7 +795,8 @@ namespace Emby.Server.Implementations.Channels
return result;
}
- private async Task<ChannelItemResult> GetChannelItems(IChannel channel,
+ private async Task<ChannelItemResult> GetChannelItems(
+ IChannel channel,
User user,
string externalFolderId,
ChannelItemSortField? sortField,
@@ -1067,7 +1072,7 @@ namespace Emby.Server.Implementations.Channels
}
// was used for status
- //if (!string.Equals(item.ExternalEtag ?? string.Empty, info.Etag ?? string.Empty, StringComparison.Ordinal))
+ // if (!string.Equals(item.ExternalEtag ?? string.Empty, info.Etag ?? string.Empty, StringComparison.Ordinal))
//{
// item.ExternalEtag = info.Etag;
// forceUpdate = true;
diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs
index cba3975cf..8fb9520d6 100644
--- a/Emby.Server.Implementations/Collections/CollectionManager.cs
+++ b/Emby.Server.Implementations/Collections/CollectionManager.cs
@@ -5,6 +5,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Entities;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Collections;
using MediaBrowser.Controller.Configuration;
diff --git a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
index f816fd54f..8a3716380 100644
--- a/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
+++ b/Emby.Server.Implementations/Data/BaseSqliteRepository.cs
@@ -162,7 +162,6 @@ namespace Emby.Server.Implementations.Data
}
return false;
-
}, ReadTransactionMode);
}
@@ -248,12 +247,12 @@ namespace Emby.Server.Implementations.Data
public enum SynchronousMode
{
/// <summary>
- /// SQLite continues without syncing as soon as it has handed data off to the operating system
+ /// SQLite continues without syncing as soon as it has handed data off to the operating system.
/// </summary>
Off = 0,
/// <summary>
- /// SQLite database engine will still sync at the most critical moments
+ /// SQLite database engine will still sync at the most critical moments.
/// </summary>
Normal = 1,
diff --git a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs
index 6c9bcff0f..3de9d6371 100644
--- a/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs
+++ b/Emby.Server.Implementations/Data/CleanDatabaseScheduledTask.cs
@@ -51,7 +51,6 @@ namespace Emby.Server.Implementations.Data
_libraryManager.DeleteItem(item, new DeleteOptions
{
DeleteFileLocation = false
-
});
}
diff --git a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
index d474f1c6b..5597155a8 100644
--- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
@@ -1,4 +1,4 @@
-#pragma warning disable CS1591
+#pragma warning disable CS1591
using System;
using System.Collections.Generic;
@@ -59,7 +59,7 @@ namespace Emby.Server.Implementations.Data
}
/// <summary>
- /// Opens the connection to the database
+ /// Opens the connection to the database.
/// </summary>
/// <returns>Task.</returns>
private void InitializeInternal()
@@ -77,7 +77,7 @@ namespace Emby.Server.Implementations.Data
}
/// <summary>
- /// Save the display preferences associated with an item in the repo
+ /// Save the display preferences associated with an item in the repo.
/// </summary>
/// <param name="displayPreferences">The display preferences.</param>
/// <param name="userId">The user id.</param>
@@ -122,7 +122,7 @@ namespace Emby.Server.Implementations.Data
}
/// <summary>
- /// Save all display preferences associated with a user in the repo
+ /// Save all display preferences associated with a user in the repo.
/// </summary>
/// <param name="displayPreferences">The display preferences.</param>
/// <param name="userId">The user id.</param>
diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
index 43a593f11..da37a8c86 100644
--- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs
@@ -102,7 +102,7 @@ namespace Emby.Server.Implementations.Data
protected override TempStoreMode TempStore => TempStoreMode.Memory;
/// <summary>
- /// Opens the connection to the database
+ /// Opens the connection to the database.
/// </summary>
public void Initialize(SqliteUserDataRepository userDataRepo, IUserManager userManager)
{
@@ -321,7 +321,6 @@ namespace Emby.Server.Implementations.Data
AddColumn(db, "MediaStreams", "ColorPrimaries", "TEXT", existingColumnNames);
AddColumn(db, "MediaStreams", "ColorSpace", "TEXT", existingColumnNames);
AddColumn(db, "MediaStreams", "ColorTransfer", "TEXT", existingColumnNames);
-
}, TransactionMode);
connection.RunQueries(postQueries);
@@ -549,7 +548,7 @@ namespace Emby.Server.Implementations.Data
}
/// <summary>
- /// Save a standard item in the repo
+ /// Save a standard item in the repo.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
@@ -794,6 +793,7 @@ namespace Emby.Server.Implementations.Data
{
saveItemStatement.TryBindNull("@Width");
}
+
if (item.Height > 0)
{
saveItemStatement.TryBind("@Height", item.Height);
@@ -933,6 +933,7 @@ namespace Emby.Server.Implementations.Data
{
saveItemStatement.TryBindNull("@SeriesName");
}
+
if (string.IsNullOrWhiteSpace(userDataKey))
{
saveItemStatement.TryBindNull("@UserDataKey");
@@ -1008,6 +1009,7 @@ namespace Emby.Server.Implementations.Data
{
artists = string.Join("|", hasArtists.Artists);
}
+
saveItemStatement.TryBind("@Artists", artists);
string albumArtists = null;
@@ -1107,6 +1109,7 @@ namespace Emby.Server.Implementations.Data
{
continue;
}
+
str.Append(ToValueString(i) + "|");
}
@@ -1205,7 +1208,7 @@ namespace Emby.Server.Implementations.Data
}
/// <summary>
- /// Internal retrieve from items or users table
+ /// Internal retrieve from items or users table.
/// </summary>
/// <param name="id">The id.</param>
/// <returns>BaseItem.</returns>
@@ -1367,6 +1370,7 @@ namespace Emby.Server.Implementations.Data
hasStartDate.StartDate = reader[index].ReadDateTime();
}
}
+
index++;
}
@@ -1374,12 +1378,14 @@ namespace Emby.Server.Implementations.Data
{
item.EndDate = reader[index].TryReadDateTime();
}
+
index++;
if (!reader.IsDBNull(index))
{
item.ChannelId = new Guid(reader.GetString(index));
}
+
index++;
if (enableProgramAttributes)
@@ -1390,24 +1396,28 @@ namespace Emby.Server.Implementations.Data
{
hasProgramAttributes.IsMovie = reader.GetBoolean(index);
}
+
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsSeries = reader.GetBoolean(index);
}
+
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.EpisodeTitle = reader.GetString(index);
}
+
index++;
if (!reader.IsDBNull(index))
{
hasProgramAttributes.IsRepeat = reader.GetBoolean(index);
}
+
index++;
}
else
@@ -1420,6 +1430,7 @@ namespace Emby.Server.Implementations.Data
{
item.CommunityRating = reader.GetFloat(index);
}
+
index++;
if (HasField(query, ItemFields.CustomRating))
@@ -1428,6 +1439,7 @@ namespace Emby.Server.Implementations.Data
{
item.CustomRating = reader.GetString(index);
}
+
index++;
}
@@ -1435,6 +1447,7 @@ namespace Emby.Server.Implementations.Data
{
item.IndexNumber = reader.GetInt32(index);
}
+
index++;
if (HasField(query, ItemFields.Settings))
@@ -1443,18 +1456,21 @@ namespace Emby.Server.Implementations.Data
{
item.IsLocked = reader.GetBoolean(index);
}
+
index++;
if (!reader.IsDBNull(index))
{
item.PreferredMetadataLanguage = reader.GetString(index);
}
+
index++;
if (!reader.IsDBNull(index))
{
item.PreferredMetadataCountryCode = reader.GetString(index);
}
+
index++;
}
@@ -1464,6 +1480,7 @@ namespace Emby.Server.Implementations.Data
{
item.Width = reader.GetInt32(index);
}
+
index++;
}
@@ -1473,6 +1490,7 @@ namespace Emby.Server.Implementations.Data
{
item.Height = reader.GetInt32(index);
}
+
index++;
}
@@ -1482,6 +1500,7 @@ namespace Emby.Server.Implementations.Data
{
item.DateLastRefreshed = reader[index].ReadDateTime();
}
+
index++;
}
@@ -1489,18 +1508,21 @@ namespace Emby.Server.Implementations.Data
{
item.Name = reader.GetString(index);
}
+
index++;
if (!reader.IsDBNull(index))
{
item.Path = RestorePath(reader.GetString(index));
}
+
index++;
if (!reader.IsDBNull(index))
{
item.PremiereDate = reader[index].TryReadDateTime();
}
+
index++;
if (HasField(query, ItemFields.Overview))
@@ -1509,6 +1531,7 @@ namespace Emby.Server.Implementations.Data
{
item.Overview = reader.GetString(index);
}
+
index++;
}
@@ -1516,18 +1539,21 @@ namespace Emby.Server.Implementations.Data
{
item.ParentIndexNumber = reader.GetInt32(index);
}
+
index++;
if (!reader.IsDBNull(index))
{
item.ProductionYear = reader.GetInt32(index);
}
+
index++;
if (!reader.IsDBNull(index))
{
item.OfficialRating = reader.GetString(index);
}
+
index++;
if (HasField(query, ItemFields.SortName))
@@ -1536,6 +1562,7 @@ namespace Emby.Server.Implementations.Data
{
item.ForcedSortName = reader.GetString(index);
}
+
index++;
}
@@ -1543,12 +1570,14 @@ namespace Emby.Server.Implementations.Data
{
item.RunTimeTicks = reader.GetInt64(index);
}
+
index++;
if (!reader.IsDBNull(index))
{
item.Size = reader.GetInt64(index);
}
+
index++;
if (HasField(query, ItemFields.DateCreated))
@@ -1557,6 +1586,7 @@ namespace Emby.Server.Implementations.Data
{
item.DateCreated = reader[index].ReadDateTime();
}
+
index++;
}
@@ -1564,6 +1594,7 @@ namespace Emby.Server.Implementations.Data
{
item.DateModified = reader[index].ReadDateTime();
}
+
index++;
item.Id = reader.GetGuid(index);
@@ -1575,6 +1606,7 @@ namespace Emby.Server.Implementations.Data
{
item.Genres = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
}
+
index++;
}
@@ -1582,6 +1614,7 @@ namespace Emby.Server.Implementations.Data
{
item.ParentId = reader.GetGuid(index);
}
+
index++;
if (!reader.IsDBNull(index))
@@ -1591,6 +1624,7 @@ namespace Emby.Server.Implementations.Data
item.Audio = audio;
}
}
+
index++;
// TODO: Even if not needed by apps, the server needs it internally
@@ -1604,6 +1638,7 @@ namespace Emby.Server.Implementations.Data
liveTvChannel.ServiceName = reader.GetString(index);
}
}
+
index++;
}
@@ -1611,6 +1646,7 @@ namespace Emby.Server.Implementations.Data
{
item.IsInMixedFolder = reader.GetBoolean(index);
}
+
index++;
if (HasField(query, ItemFields.DateLastSaved))
@@ -1619,6 +1655,7 @@ namespace Emby.Server.Implementations.Data
{
item.DateLastSaved = reader[index].ReadDateTime();
}
+
index++;
}
@@ -1636,8 +1673,10 @@ namespace Emby.Server.Implementations.Data
}
}
}
+
item.LockedFields = GetLockedFields(reader.GetString(index)).ToArray();
}
+
index++;
}
@@ -1647,6 +1686,7 @@ namespace Emby.Server.Implementations.Data
{
item.Studios = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
}
+
index++;
}
@@ -1656,6 +1696,7 @@ namespace Emby.Server.Implementations.Data
{
item.Tags = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
}
+
index++;
}
@@ -1675,9 +1716,11 @@ namespace Emby.Server.Implementations.Data
}
}
}
+
trailer.TrailerTypes = GetTrailerTypes(reader.GetString(index)).ToArray();
}
}
+
index++;
}
@@ -1687,6 +1730,7 @@ namespace Emby.Server.Implementations.Data
{
item.OriginalTitle = reader.GetString(index);
}
+
index++;
}
@@ -1697,6 +1741,7 @@ namespace Emby.Server.Implementations.Data
video.PrimaryVersionId = reader.GetString(index);
}
}
+
index++;
if (HasField(query, ItemFields.DateLastMediaAdded))
@@ -1705,6 +1750,7 @@ namespace Emby.Server.Implementations.Data
{
folder.DateLastMediaAdded = reader[index].TryReadDateTime();
}
+
index++;
}
@@ -1712,18 +1758,21 @@ namespace Emby.Server.Implementations.Data
{
item.Album = reader.GetString(index);
}
+
index++;
if (!reader.IsDBNull(index))
{
item.CriticRating = reader.GetFloat(index);
}
+
index++;
if (!reader.IsDBNull(index))
{
item.IsVirtualItem = reader.GetBoolean(index);
}
+
index++;
if (item is IHasSeries hasSeriesName)
@@ -1733,6 +1782,7 @@ namespace Emby.Server.Implementations.Data
hasSeriesName.SeriesName = reader.GetString(index);
}
}
+
index++;
if (hasEpisodeAttributes)
@@ -1743,6 +1793,7 @@ namespace Emby.Server.Implementations.Data
{
episode.SeasonName = reader.GetString(index);
}
+
index++;
if (!reader.IsDBNull(index))
{
@@ -1753,6 +1804,7 @@ namespace Emby.Server.Implementations.Data
{
index++;
}
+
index++;
}
@@ -1766,6 +1818,7 @@ namespace Emby.Server.Implementations.Data
hasSeries.SeriesId = reader.GetGuid(index);
}
}
+
index++;
}
@@ -1775,6 +1828,7 @@ namespace Emby.Server.Implementations.Data
{
item.PresentationUniqueKey = reader.GetString(index);
}
+
index++;
}
@@ -1784,6 +1838,7 @@ namespace Emby.Server.Implementations.Data
{
item.InheritedParentalRatingValue = reader.GetInt32(index);
}
+
index++;
}
@@ -1793,6 +1848,7 @@ namespace Emby.Server.Implementations.Data
{
item.ExternalSeriesId = reader.GetString(index);
}
+
index++;
}
@@ -1802,6 +1858,7 @@ namespace Emby.Server.Implementations.Data
{
item.Tagline = reader.GetString(index);
}
+
index++;
}
@@ -1809,6 +1866,7 @@ namespace Emby.Server.Implementations.Data
{
DeserializeProviderIds(reader.GetString(index), item);
}
+
index++;
if (query.DtoOptions.EnableImages)
@@ -1817,6 +1875,7 @@ namespace Emby.Server.Implementations.Data
{
DeserializeImages(reader.GetString(index), item);
}
+
index++;
}
@@ -1826,6 +1885,7 @@ namespace Emby.Server.Implementations.Data
{
item.ProductionLocations = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries).ToArray();
}
+
index++;
}
@@ -1835,6 +1895,7 @@ namespace Emby.Server.Implementations.Data
{
item.ExtraIds = SplitToGuids(reader.GetString(index));
}
+
index++;
}
@@ -1842,6 +1903,7 @@ namespace Emby.Server.Implementations.Data
{
item.TotalBitrate = reader.GetInt32(index);
}
+
index++;
if (!reader.IsDBNull(index))
@@ -1851,6 +1913,7 @@ namespace Emby.Server.Implementations.Data
item.ExtraType = extraType;
}
}
+
index++;
if (hasArtistFields)
@@ -1859,12 +1922,14 @@ namespace Emby.Server.Implementations.Data
{
hasArtists.Artists = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
}
+
index++;
if (item is IHasAlbumArtist hasAlbumArtists && !reader.IsDBNull(index))
{
hasAlbumArtists.AlbumArtists = reader.GetString(index).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
}
+
index++;
}
@@ -1872,6 +1937,7 @@ namespace Emby.Server.Implementations.Data
{
item.ExternalId = reader.GetString(index);
}
+
index++;
if (HasField(query, ItemFields.SeriesPresentationUniqueKey))
@@ -1883,6 +1949,7 @@ namespace Emby.Server.Implementations.Data
hasSeries.SeriesPresentationUniqueKey = reader.GetString(index);
}
}
+
index++;
}
@@ -1892,6 +1959,7 @@ namespace Emby.Server.Implementations.Data
{
program.ShowId = reader.GetString(index);
}
+
index++;
}
@@ -1899,6 +1967,7 @@ namespace Emby.Server.Implementations.Data
{
item.OwnerId = reader.GetGuid(index);
}
+
index++;
return item;
@@ -1919,7 +1988,7 @@ namespace Emby.Server.Implementations.Data
}
/// <summary>
- /// Gets chapters for an item
+ /// Gets chapters for an item.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>IEnumerable{ChapterInfo}.</returns>
@@ -1947,7 +2016,7 @@ namespace Emby.Server.Implementations.Data
}
/// <summary>
- /// Gets a single chapter for an item
+ /// Gets a single chapter for an item.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="index">The index.</param>
@@ -2044,7 +2113,6 @@ namespace Emby.Server.Implementations.Data
db.Execute("delete from " + ChaptersTableName + " where ItemId=@ItemId", idBlob);
InsertChapters(idBlob, chapters, db);
-
}, TransactionMode);
}
}
@@ -2475,6 +2543,7 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind("@SearchTermStartsWith", searchTerm + "%");
}
+
if (commandText.IndexOf("@SearchTermContains", StringComparison.OrdinalIgnoreCase) != -1)
{
statement.TryBind("@SearchTermContains", "%" + searchTerm + "%");
@@ -2745,6 +2814,7 @@ namespace Emby.Server.Implementations.Data
{
items[i] = newItem;
}
+
return;
}
}
@@ -2837,6 +2907,7 @@ namespace Emby.Server.Implementations.Data
{
statementTexts.Add(commandText);
}
+
if (query.EnableTotalRecordCount)
{
commandText = string.Empty;
@@ -3241,6 +3312,7 @@ namespace Emby.Server.Implementations.Data
{
statementTexts.Add(commandText);
}
+
if (query.EnableTotalRecordCount)
{
commandText = string.Empty;
@@ -3594,11 +3666,13 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add("IndexNumber=@IndexNumber");
statement?.TryBind("@IndexNumber", query.IndexNumber.Value);
}
+
if (query.ParentIndexNumber.HasValue)
{
whereClauses.Add("ParentIndexNumber=@ParentIndexNumber");
statement?.TryBind("@ParentIndexNumber", query.ParentIndexNumber.Value);
}
+
if (query.ParentIndexNumberNotEquals.HasValue)
{
whereClauses.Add("(ParentIndexNumber<>@ParentIndexNumberNotEquals or ParentIndexNumber is null)");
@@ -3884,6 +3958,7 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, artistId.ToByteArray());
}
+
index++;
}
@@ -3904,6 +3979,7 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, artistId.ToByteArray());
}
+
index++;
}
@@ -3924,8 +4000,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, artistId.ToByteArray());
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -3943,8 +4021,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, albumId.ToByteArray());
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -3962,8 +4042,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, artistId.ToByteArray());
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -3981,8 +4063,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, genreId.ToByteArray());
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -3998,8 +4082,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind("@Genre" + index, GetCleanValue(item));
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -4015,8 +4101,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind("@Tag" + index, GetCleanValue(item));
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -4032,8 +4120,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind("@ExcludeTag" + index, GetCleanValue(item));
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -4052,8 +4142,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, studioId.ToByteArray());
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -4069,8 +4161,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind("@OfficialRating" + index, item);
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -4245,6 +4339,7 @@ namespace Emby.Server.Implementations.Data
statement.TryBind("@IsVirtualItem", isVirtualItem.Value);
}
}
+
if (query.IsSpecialSeason.HasValue)
{
if (query.IsSpecialSeason.Value)
@@ -4256,6 +4351,7 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add("IndexNumber <> 0");
}
}
+
if (query.IsUnaired.HasValue)
{
if (query.IsUnaired.Value)
@@ -4267,6 +4363,7 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add("PremiereDate < DATETIME('now')");
}
}
+
var queryMediaTypes = query.MediaTypes.Where(IsValidMediaType).ToArray();
if (queryMediaTypes.Length == 1)
{
@@ -4282,6 +4379,7 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add("MediaType in (" + val + ")");
}
+
if (query.ItemIds.Length > 0)
{
var includeIds = new List<string>();
@@ -4294,11 +4392,13 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind("@IncludeId" + index, id);
}
+
index++;
}
whereClauses.Add("(" + string.Join(" OR ", includeIds) + ")");
}
+
if (query.ExcludeItemIds.Length > 0)
{
var excludeIds = new List<string>();
@@ -4311,6 +4411,7 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind("@ExcludeId" + index, id);
}
+
index++;
}
@@ -4335,6 +4436,7 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, "%" + pair.Key + "=" + pair.Value + "%");
}
+
index++;
break;
@@ -4360,7 +4462,7 @@ namespace Emby.Server.Implementations.Data
// TODO this seems to be an idea for a better schema where ProviderIds are their own table
// buut this is not implemented
- //hasProviderIds.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = '" + pair.Key + "'), '') <> " + paramName + ")");
+ // hasProviderIds.Add("(COALESCE((select value from ProviderIds where ItemId=Guid and Name = '" + pair.Key + "'), '') <> " + paramName + ")");
// TODO this is a really BAD way to do it since the pair:
// Tmdb, 1234 matches Tmdb=1234 but also Tmdb=1234567
@@ -4377,6 +4479,7 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, "%" + pair.Key + "=" + pair.Value + "%");
}
+
index++;
break;
@@ -4427,6 +4530,7 @@ namespace Emby.Server.Implementations.Data
{
whereClauses.Add("(TopParentId=@TopParentId)");
}
+
if (statement != null)
{
statement.TryBind("@TopParentId", queryTopParentIds[0].ToString("N", CultureInfo.InvariantCulture));
@@ -4464,11 +4568,13 @@ namespace Emby.Server.Implementations.Data
statement.TryBind("@AncestorId", query.AncestorIds[0]);
}
}
+
if (query.AncestorIds.Length > 1)
{
var inClause = string.Join(",", query.AncestorIds.Select(i => "'" + i.ToString("N", CultureInfo.InvariantCulture) + "'"));
whereClauses.Add(string.Format("Guid in (select itemId from AncestorIds where AncestorIdText in ({0}))", inClause));
}
+
if (!string.IsNullOrWhiteSpace(query.AncestorWithPresentationUniqueKey))
{
var inClause = "select guid from TypedBaseItems where PresentationUniqueKey=@AncestorWithPresentationUniqueKey";
@@ -4497,6 +4603,7 @@ namespace Emby.Server.Implementations.Data
statement.TryBind("@UnratedType", query.BlockUnratedItems[0].ToString());
}
}
+
if (query.BlockUnratedItems.Length > 1)
{
var inClause = string.Join(",", query.BlockUnratedItems.Select(i => "'" + i.ToString() + "'"));
@@ -4789,7 +4896,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
connection.RunInTransaction(db =>
{
connection.ExecuteAll(sql);
-
}, TransactionMode);
}
}
@@ -4972,6 +5078,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
statement.TryBind("@ItemId", query.ItemId.ToByteArray());
}
}
+
if (!query.AppearsInItemId.Equals(Guid.Empty))
{
whereClauses.Add("Name in (Select Name from People where ItemId=@AppearsInItemId)");
@@ -4980,6 +5087,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
statement.TryBind("@AppearsInItemId", query.AppearsInItemId.ToByteArray());
}
}
+
var queryPersonTypes = query.PersonTypes.Where(IsValidPersonType).ToList();
if (queryPersonTypes.Count == 1)
@@ -4996,6 +5104,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
whereClauses.Add("PersonType in (" + val + ")");
}
+
var queryExcludePersonTypes = query.ExcludePersonTypes.Where(IsValidPersonType).ToList();
if (queryExcludePersonTypes.Count == 1)
@@ -5012,6 +5121,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
whereClauses.Add("PersonType not in (" + val + ")");
}
+
if (query.MaxListOrder.HasValue)
{
whereClauses.Add("ListOrder<=@MaxListOrder");
@@ -5020,6 +5130,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
statement.TryBind("@MaxListOrder", query.MaxListOrder.Value);
}
}
+
if (!string.IsNullOrWhiteSpace(query.NameContains))
{
whereClauses.Add("Name like @NameContains");
@@ -5159,6 +5270,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
var typeString = string.Join(",", withItemTypes.Select(i => "'" + i + "'"));
commandText += " AND ItemId In (select guid from typedbaseitems where type in (" + typeString + "))";
}
+
if (excludeItemTypes.Count > 0)
{
var typeString = string.Join(",", excludeItemTypes.Select(i => "'" + i + "'"));
@@ -5180,7 +5292,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
}
}
}
-
}
LogQueryTime("GetItemValueNames", commandText, now);
@@ -5631,7 +5742,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
db.Execute("delete from People where ItemId=@ItemId", itemIdBlob);
InsertPeople(itemIdBlob, people, db);
-
}, TransactionMode);
}
}
@@ -5788,7 +5898,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
db.Execute("delete from mediastreams where ItemId=@ItemId", itemIdBlob);
InsertMediaStreams(itemIdBlob, streams, db);
-
}, TransactionMode);
}
}
@@ -6134,7 +6243,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
db.Execute("delete from mediaattachments where ItemId=@ItemId", itemIdBlob);
InsertMediaAttachments(itemIdBlob, attachments, db, cancellationToken);
-
}, TransactionMode);
}
}
diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
index 6ee6230fc..4a78aac8e 100644
--- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
+using Jellyfin.Data.Entities;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
@@ -134,10 +135,12 @@ namespace Emby.Server.Implementations.Data
{
throw new ArgumentNullException(nameof(userData));
}
+
if (internalUserId <= 0)
{
throw new ArgumentNullException(nameof(internalUserId));
}
+
if (string.IsNullOrEmpty(key))
{
throw new ArgumentNullException(nameof(key));
@@ -152,6 +155,7 @@ namespace Emby.Server.Implementations.Data
{
throw new ArgumentNullException(nameof(userData));
}
+
if (internalUserId <= 0)
{
throw new ArgumentNullException(nameof(internalUserId));
@@ -234,7 +238,7 @@ namespace Emby.Server.Implementations.Data
}
/// <summary>
- /// Persist all user data for the specified user
+ /// Persist all user data for the specified user.
/// </summary>
private void PersistAllUserData(long internalUserId, UserItemData[] userDataList, CancellationToken cancellationToken)
{
@@ -308,7 +312,7 @@ namespace Emby.Server.Implementations.Data
}
/// <summary>
- /// Return all user-data associated with the given user
+ /// Return all user-data associated with the given user.
/// </summary>
/// <param name="internalUserId"></param>
/// <returns></returns>
@@ -338,7 +342,7 @@ namespace Emby.Server.Implementations.Data
}
/// <summary>
- /// Read a row from the specified reader into the provided userData object
+ /// Read a row from the specified reader into the provided userData object.
/// </summary>
/// <param name="reader"></param>
private UserItemData ReadRow(IReadOnlyList<IResultSetValue> reader)
@@ -346,7 +350,7 @@ namespace Emby.Server.Implementations.Data
var userData = new UserItemData();
userData.Key = reader[0].ToString();
- //userData.UserId = reader[1].ReadGuidFromBlob();
+ // userData.UserId = reader[1].ReadGuidFromBlob();
if (reader[2].SQLiteType != SQLiteType.Null)
{
diff --git a/Emby.Server.Implementations/Data/SqliteUserRepository.cs b/Emby.Server.Implementations/Data/SqliteUserRepository.cs
deleted file mode 100644
index 0c3f26974..000000000
--- a/Emby.Server.Implementations/Data/SqliteUserRepository.cs
+++ /dev/null
@@ -1,240 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text.Json;
-using MediaBrowser.Common.Json;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Persistence;
-using Microsoft.Extensions.Logging;
-using SQLitePCL.pretty;
-
-namespace Emby.Server.Implementations.Data
-{
- /// <summary>
- /// Class SQLiteUserRepository
- /// </summary>
- public class SqliteUserRepository : BaseSqliteRepository, IUserRepository
- {
- private readonly JsonSerializerOptions _jsonOptions;
-
- public SqliteUserRepository(
- ILogger<SqliteUserRepository> logger,
- IServerApplicationPaths appPaths)
- : base(logger)
- {
- _jsonOptions = JsonDefaults.GetOptions();
-
- DbFilePath = Path.Combine(appPaths.DataPath, "users.db");
- }
-
- /// <summary>
- /// Gets the name of the repository
- /// </summary>
- /// <value>The name.</value>
- public string Name => "SQLite";
-
- /// <summary>
- /// Opens the connection to the database.
- /// </summary>
- public void Initialize()
- {
- using (var connection = GetConnection())
- {
- var localUsersTableExists = TableExists(connection, "LocalUsersv2");
-
- connection.RunQueries(new[] {
- "create table if not exists LocalUsersv2 (Id INTEGER PRIMARY KEY, guid GUID NOT NULL, data BLOB NOT NULL)",
- "drop index if exists idx_users"
- });
-
- if (!localUsersTableExists && TableExists(connection, "Users"))
- {
- TryMigrateToLocalUsersTable(connection);
- }
-
- RemoveEmptyPasswordHashes(connection);
- }
- }
-
- private void TryMigrateToLocalUsersTable(ManagedConnection connection)
- {
- try
- {
- connection.RunQueries(new[]
- {
- "INSERT INTO LocalUsersv2 (guid, data) SELECT guid,data from users"
- });
- }
- catch (Exception ex)
- {
- Logger.LogError(ex, "Error migrating users database");
- }
- }
-
- private void RemoveEmptyPasswordHashes(ManagedConnection connection)
- {
- foreach (var user in RetrieveAllUsers(connection))
- {
- // If the user password is the sha1 hash of the empty string, remove it
- if (!string.Equals(user.Password, "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709", StringComparison.Ordinal)
- && !string.Equals(user.Password, "$SHA1$DA39A3EE5E6B4B0D3255BFEF95601890AFD80709", StringComparison.Ordinal))
- {
- continue;
- }
-
- user.Password = null;
- var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions);
-
- connection.RunInTransaction(db =>
- {
- using (var statement = db.PrepareStatement("update LocalUsersv2 set data=@data where Id=@InternalId"))
- {
- statement.TryBind("@InternalId", user.InternalId);
- statement.TryBind("@data", serialized);
- statement.MoveNext();
- }
- }, TransactionMode);
- }
- }
-
- /// <summary>
- /// Save a user in the repo
- /// </summary>
- public void CreateUser(User user)
- {
- if (user == null)
- {
- throw new ArgumentNullException(nameof(user));
- }
-
- var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions);
-
- using (var connection = GetConnection())
- {
- connection.RunInTransaction(db =>
- {
- using (var statement = db.PrepareStatement("insert into LocalUsersv2 (guid, data) values (@guid, @data)"))
- {
- statement.TryBind("@guid", user.Id.ToByteArray());
- statement.TryBind("@data", serialized);
-
- statement.MoveNext();
- }
-
- var createdUser = GetUser(user.Id, connection);
-
- if (createdUser == null)
- {
- throw new ApplicationException("created user should never be null");
- }
-
- user.InternalId = createdUser.InternalId;
-
- }, TransactionMode);
- }
- }
-
- public void UpdateUser(User user)
- {
- if (user == null)
- {
- throw new ArgumentNullException(nameof(user));
- }
-
- var serialized = JsonSerializer.SerializeToUtf8Bytes(user, _jsonOptions);
-
- using (var connection = GetConnection())
- {
- connection.RunInTransaction(db =>
- {
- using (var statement = db.PrepareStatement("update LocalUsersv2 set data=@data where Id=@InternalId"))
- {
- statement.TryBind("@InternalId", user.InternalId);
- statement.TryBind("@data", serialized);
- statement.MoveNext();
- }
-
- }, TransactionMode);
- }
- }
-
- private User GetUser(Guid guid, ManagedConnection connection)
- {
- using (var statement = connection.PrepareStatement("select id,guid,data from LocalUsersv2 where guid=@guid"))
- {
- statement.TryBind("@guid", guid);
-
- foreach (var row in statement.ExecuteQuery())
- {
- return GetUser(row);
- }
- }
-
- return null;
- }
-
- private User GetUser(IReadOnlyList<IResultSetValue> row)
- {
- var id = row[0].ToInt64();
- var guid = row[1].ReadGuidFromBlob();
-
- var user = JsonSerializer.Deserialize<User>(row[2].ToBlob(), _jsonOptions);
- user.InternalId = id;
- user.Id = guid;
- return user;
- }
-
- /// <summary>
- /// Retrieve all users from the database
- /// </summary>
- /// <returns>IEnumerable{User}.</returns>
- public List<User> RetrieveAllUsers()
- {
- using (var connection = GetConnection(true))
- {
- return new List<User>(RetrieveAllUsers(connection));
- }
- }
-
- /// <summary>
- /// Retrieve all users from the database
- /// </summary>
- /// <returns>IEnumerable{User}.</returns>
- private IEnumerable<User> RetrieveAllUsers(ManagedConnection connection)
- {
- foreach (var row in connection.Query("select id,guid,data from LocalUsersv2"))
- {
- yield return GetUser(row);
- }
- }
-
- /// <summary>
- /// Deletes the user.
- /// </summary>
- /// <param name="user">The user.</param>
- /// <returns>Task.</returns>
- /// <exception cref="ArgumentNullException">user</exception>
- public void DeleteUser(User user)
- {
- if (user == null)
- {
- throw new ArgumentNullException(nameof(user));
- }
-
- using (var connection = GetConnection())
- {
- connection.RunInTransaction(db =>
- {
- using (var statement = db.PrepareStatement("delete from LocalUsersv2 where Id=@id"))
- {
- statement.TryBind("@id", user.InternalId);
- statement.MoveNext();
- }
- }, TransactionMode);
- }
- }
- }
-}
diff --git a/Emby.Server.Implementations/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs
index e39e0aa78..e75745cc6 100644
--- a/Emby.Server.Implementations/Devices/DeviceManager.cs
+++ b/Emby.Server.Implementations/Devices/DeviceManager.cs
@@ -5,10 +5,11 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
+using Jellyfin.Data.Enums;
+using Jellyfin.Data.Entities;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Security;
using MediaBrowser.Model.Devices;
@@ -16,7 +17,6 @@ using MediaBrowser.Model.Events;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Session;
-using MediaBrowser.Model.Users;
namespace Emby.Server.Implementations.Devices
{
@@ -27,11 +27,10 @@ namespace Emby.Server.Implementations.Devices
private readonly IServerConfigurationManager _config;
private readonly IAuthenticationRepository _authRepo;
private readonly Dictionary<string, ClientCapabilities> _capabilitiesCache;
+ private readonly object _capabilitiesSyncLock = new object();
public event EventHandler<GenericEventArgs<Tuple<string, DeviceOptions>>> DeviceOptionsUpdated;
- private readonly object _capabilitiesSyncLock = new object();
-
public DeviceManager(
IAuthenticationRepository authRepo,
IJsonSerializer json,
@@ -113,7 +112,7 @@ namespace Emby.Server.Implementations.Devices
{
IEnumerable<AuthenticationInfo> sessions = _authRepo.Get(new AuthenticationInfoQuery
{
- //UserId = query.UserId
+ // UserId = query.UserId
HasUser = true
}).Items;
@@ -170,12 +169,18 @@ namespace Emby.Server.Implementations.Devices
{
throw new ArgumentException("user not found");
}
+
if (string.IsNullOrEmpty(deviceId))
{
throw new ArgumentNullException(nameof(deviceId));
}
- if (!CanAccessDevice(user.Policy, deviceId))
+ if (user.HasPermission(PermissionKind.EnableAllDevices) || user.HasPermission(PermissionKind.IsAdministrator))
+ {
+ return true;
+ }
+
+ if (!user.GetPreference(PreferenceKind.EnabledDevices).Contains(deviceId, StringComparer.OrdinalIgnoreCase))
{
var capabilities = GetCapabilities(deviceId);
@@ -187,20 +192,5 @@ namespace Emby.Server.Implementations.Devices
return true;
}
-
- private static bool CanAccessDevice(UserPolicy policy, string id)
- {
- if (policy.EnableAllDevices)
- {
- return true;
- }
-
- if (policy.IsAdministrator)
- {
- return true;
- }
-
- return policy.EnabledDevices.Contains(id, StringComparer.OrdinalIgnoreCase);
- }
}
}
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index f9841082c..3d5460b8c 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -6,14 +6,14 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
+using Jellyfin.Data.Entities;
+using Jellyfin.Data.Enums;
using MediaBrowser.Common;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Persistence;
@@ -24,6 +24,14 @@ using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using Microsoft.Extensions.Logging;
+using Book = MediaBrowser.Controller.Entities.Book;
+using Episode = MediaBrowser.Controller.Entities.TV.Episode;
+using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
+using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
+using Person = MediaBrowser.Controller.Entities.Person;
+using Photo = MediaBrowser.Controller.Entities.Photo;
+using Season = MediaBrowser.Controller.Entities.TV.Season;
+using Series = MediaBrowser.Controller.Entities.TV.Series;
namespace Emby.Server.Implementations.Dto
{
@@ -66,7 +74,7 @@ namespace Emby.Server.Implementations.Dto
}
/// <summary>
- /// Converts a BaseItem to a DTOBaseItem
+ /// Converts a BaseItem to a DTOBaseItem.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="fields">The fields.</param>
@@ -269,6 +277,7 @@ namespace Emby.Server.Implementations.Dto
dto.EpisodeTitle = dto.Name;
dto.Name = dto.SeriesName;
}
+
liveTvManager.AddInfoToRecordingDto(item, dto, activeRecording, user);
}
@@ -284,6 +293,7 @@ namespace Emby.Server.Implementations.Dto
{
continue;
}
+
var containers = container.Split(new[] { ',' });
if (containers.Length < 2)
{
@@ -384,7 +394,7 @@ namespace Emby.Server.Implementations.Dto
if (options.ContainsField(ItemFields.ChildCount))
{
- dto.ChildCount = dto.ChildCount ?? GetChildCount(folder, user);
+ dto.ChildCount ??= GetChildCount(folder, user);
}
}
@@ -398,7 +408,6 @@ namespace Emby.Server.Implementations.Dto
dto.DateLastMediaAdded = folder.DateLastMediaAdded;
}
}
-
else
{
if (options.EnableUserData)
@@ -414,7 +423,7 @@ namespace Emby.Server.Implementations.Dto
if (options.ContainsField(ItemFields.BasicSyncInfo))
{
- var userCanSync = user != null && user.Policy.EnableContentDownloading;
+ var userCanSync = user != null && user.HasPermission(PermissionKind.EnableContentDownloading);
if (userCanSync && item.SupportsExternalTransfer)
{
dto.SupportsSync = true;
@@ -435,7 +444,7 @@ namespace Emby.Server.Implementations.Dto
}
/// <summary>
- /// Gets client-side Id of a server-side BaseItem
+ /// Gets client-side Id of a server-side BaseItem.
/// </summary>
/// <param name="item">The item.</param>
/// <returns>System.String.</returns>
@@ -449,6 +458,7 @@ namespace Emby.Server.Implementations.Dto
{
dto.SeriesName = item.SeriesName;
}
+
private static void SetPhotoProperties(BaseItemDto dto, Photo item)
{
dto.CameraMake = item.CameraMake;
@@ -530,7 +540,7 @@ namespace Emby.Server.Implementations.Dto
}
/// <summary>
- /// Attaches People DTO's to a DTOBaseItem
+ /// Attaches People DTO's to a DTOBaseItem.
/// </summary>
/// <param name="dto">The dto.</param>
/// <param name="item">The item.</param>
@@ -547,22 +557,27 @@ namespace Emby.Server.Implementations.Dto
{
return 0;
}
+
if (i.IsType(PersonType.GuestStar))
{
return 1;
}
+
if (i.IsType(PersonType.Director))
{
return 2;
}
+
if (i.IsType(PersonType.Writer))
{
return 3;
}
+
if (i.IsType(PersonType.Producer))
{
return 4;
}
+
if (i.IsType(PersonType.Composer))
{
return 4;
@@ -586,7 +601,6 @@ namespace Emby.Server.Implementations.Dto
_logger.LogError(ex, "Error getting person {Name}", c);
return null;
}
-
}).Where(i => i != null)
.GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
.Select(x => x.First())
@@ -719,7 +733,7 @@ namespace Emby.Server.Implementations.Dto
}
/// <summary>
- /// Sets simple property values on a DTOBaseItem
+ /// Sets simple property values on a DTOBaseItem.
/// </summary>
/// <param name="dto">The dto.</param>
/// <param name="item">The item.</param>
@@ -939,7 +953,7 @@ namespace Emby.Server.Implementations.Dto
dto.AlbumPrimaryImageTag = GetTagAndFillBlurhash(dto, albumParent, ImageType.Primary);
}
- //if (options.ContainsField(ItemFields.MediaSourceCount))
+ // if (options.ContainsField(ItemFields.MediaSourceCount))
//{
// Songs always have one
//}
@@ -949,13 +963,13 @@ namespace Emby.Server.Implementations.Dto
{
dto.Artists = hasArtist.Artists;
- //var artistItems = _libraryManager.GetArtists(new InternalItemsQuery
+ // var artistItems = _libraryManager.GetArtists(new InternalItemsQuery
//{
// EnableTotalRecordCount = false,
// ItemIds = new[] { item.Id.ToString("N", CultureInfo.InvariantCulture) }
//});
- //dto.ArtistItems = artistItems.Items
+ // dto.ArtistItems = artistItems.Items
// .Select(i =>
// {
// var artist = i.Item1;
@@ -968,7 +982,7 @@ namespace Emby.Server.Implementations.Dto
// .ToList();
// Include artists that are not in the database yet, e.g., just added via metadata editor
- //var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList();
+ // var foundArtists = artistItems.Items.Select(i => i.Item1.Name).ToList();
dto.ArtistItems = hasArtist.Artists
//.Except(foundArtists, new DistinctNameComparer())
.Select(i =>
@@ -993,7 +1007,6 @@ namespace Emby.Server.Implementations.Dto
}
return null;
-
}).Where(i => i != null).ToArray();
}
@@ -1002,13 +1015,13 @@ namespace Emby.Server.Implementations.Dto
{
dto.AlbumArtist = hasAlbumArtist.AlbumArtists.FirstOrDefault();
- //var artistItems = _libraryManager.GetAlbumArtists(new InternalItemsQuery
+ // var artistItems = _libraryManager.GetAlbumArtists(new InternalItemsQuery
//{
// EnableTotalRecordCount = false,
// ItemIds = new[] { item.Id.ToString("N", CultureInfo.InvariantCulture) }
//});
- //dto.AlbumArtists = artistItems.Items
+ // dto.AlbumArtists = artistItems.Items
// .Select(i =>
// {
// var artist = i.Item1;
@@ -1044,7 +1057,6 @@ namespace Emby.Server.Implementations.Dto
}
return null;
-
}).Where(i => i != null).ToArray();
}
@@ -1158,7 +1170,7 @@ namespace Emby.Server.Implementations.Dto
// this block will add the series poster for episodes without a poster
// TODO maybe remove the if statement entirely
- //if (options.ContainsField(ItemFields.SeriesPrimaryImage))
+ // if (options.ContainsField(ItemFields.SeriesPrimaryImage))
{
episodeSeries = episodeSeries ?? episode.Series;
if (episodeSeries != null)
@@ -1204,7 +1216,7 @@ namespace Emby.Server.Implementations.Dto
// this block will add the series poster for seasons without a poster
// TODO maybe remove the if statement entirely
- //if (options.ContainsField(ItemFields.SeriesPrimaryImage))
+ // if (options.ContainsField(ItemFields.SeriesPrimaryImage))
{
series = series ?? season.Series;
if (series != null)
@@ -1342,6 +1354,7 @@ namespace Emby.Server.Implementations.Dto
dto.ParentLogoImageTag = GetTagAndFillBlurhash(dto, parent, image);
}
}
+
if (artLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Art)) && dto.ParentArtItemId == null)
{
var image = allImages.FirstOrDefault(i => i.Type == ImageType.Art);
@@ -1352,6 +1365,7 @@ namespace Emby.Server.Implementations.Dto
dto.ParentArtImageTag = GetTagAndFillBlurhash(dto, parent, image);
}
}
+
if (thumbLimit > 0 && !(imageTags != null && imageTags.ContainsKey(ImageType.Thumb)) && (dto.ParentThumbItemId == null || parent is Series) && !(parent is ICollectionFolder) && !(parent is UserView))
{
var image = allImages.FirstOrDefault(i => i.Type == ImageType.Thumb);
@@ -1362,6 +1376,7 @@ namespace Emby.Server.Implementations.Dto
dto.ParentThumbImageTag = GetTagAndFillBlurhash(dto, parent, image);
}
}
+
if (backdropLimit > 0 && !((dto.BackdropImageTags != null && dto.BackdropImageTags.Length > 0) || (dto.ParentBackdropImageTags != null && dto.ParentBackdropImageTags.Length > 0)))
{
var images = allImages.Where(i => i.Type == ImageType.Backdrop).Take(backdropLimit).ToList();
diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
index e71e437ac..e75b66293 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -24,7 +24,7 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="IPNetwork2" Version="2.4.0.126" />
+ <PackageReference Include="IPNetwork2" Version="2.5.211" />
<PackageReference Include="Jellyfin.XmlTv" Version="10.4.3" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
@@ -41,7 +41,7 @@
<PackageReference Include="Mono.Nat" Version="2.0.1" />
<PackageReference Include="prometheus-net.DotNetRuntime" Version="3.3.1" />
<PackageReference Include="ServiceStack.Text.Core" Version="5.9.0" />
- <PackageReference Include="sharpcompress" Version="0.25.0" />
+ <PackageReference Include="sharpcompress" Version="0.25.1" />
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="2.1.0" />
<PackageReference Include="DotNet.Glob" Version="3.0.9" />
</ItemGroup>
diff --git a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
index b9992ae73..c1068522a 100644
--- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
@@ -6,6 +6,7 @@ using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -131,7 +132,6 @@ namespace Emby.Server.Implementations.EntryPoints
}
catch
{
-
}
}
}
diff --git a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs
index b64439802..632735910 100644
--- a/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/RecordingNotifier.cs
@@ -4,6 +4,7 @@ using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Plugins;
@@ -64,7 +65,7 @@ namespace Emby.Server.Implementations.EntryPoints
private async Task SendMessage(string name, TimerEventInfo info)
{
- var users = _userManager.Users.Where(i => i.Policy.EnableLiveTvAccess).Select(i => i.Id).ToList();
+ var users = _userManager.Users.Where(i => i.HasPermission(PermissionKind.EnableLiveTvAccess)).Select(i => i.Id).ToList();
try
{
diff --git a/Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs b/Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs
deleted file mode 100644
index 54f4b67e6..000000000
--- a/Emby.Server.Implementations/EntryPoints/RefreshUsersMetadata.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Tasks;
-
-namespace Emby.Server.Implementations.EntryPoints
-{
- /// <summary>
- /// Class RefreshUsersMetadata.
- /// </summary>
- public class RefreshUsersMetadata : IScheduledTask, IConfigurableScheduledTask
- {
- /// <summary>
- /// The user manager.
- /// </summary>
- private readonly IUserManager _userManager;
- private readonly IFileSystem _fileSystem;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="RefreshUsersMetadata" /> class.
- /// </summary>
- public RefreshUsersMetadata(IUserManager userManager, IFileSystem fileSystem)
- {
- _userManager = userManager;
- _fileSystem = fileSystem;
- }
-
- /// <inheritdoc />
- public string Name => "Refresh Users";
-
- /// <inheritdoc />
- public string Key => "RefreshUsers";
-
- /// <inheritdoc />
- public string Description => "Refresh user infos";
-
- /// <inheritdoc />
- public string Category => "Library";
-
- /// <inheritdoc />
- public bool IsHidden => true;
-
- /// <inheritdoc />
- public bool IsEnabled => true;
-
- /// <inheritdoc />
- public bool IsLogged => true;
-
- /// <inheritdoc />
- public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
- {
- foreach (var user in _userManager.Users)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- await user.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_fileSystem)), cancellationToken).ConfigureAwait(false);
- }
- }
-
- /// <inheritdoc />
- public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
- {
- return new[]
- {
- new TaskTriggerInfo
- {
- IntervalTicks = TimeSpan.FromDays(1).Ticks,
- Type = TaskTriggerInfo.TriggerInterval
- }
- };
- }
- }
-}
diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs
index 11ba6f748..826d4d8dc 100644
--- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs
@@ -3,10 +3,10 @@ using System.Collections.Generic;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Entities;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Updates;
using MediaBrowser.Controller;
-using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Plugins;
using MediaBrowser.Controller.Session;
@@ -68,10 +68,8 @@ namespace Emby.Server.Implementations.EntryPoints
/// <inheritdoc />
public Task RunAsync()
{
- _userManager.UserDeleted += OnUserDeleted;
- _userManager.UserUpdated += OnUserUpdated;
- _userManager.UserPolicyUpdated += OnUserPolicyUpdated;
- _userManager.UserConfigurationUpdated += OnUserConfigurationUpdated;
+ _userManager.OnUserDeleted += OnUserDeleted;
+ _userManager.OnUserUpdated += OnUserUpdated;
_appHost.HasPendingRestartChanged += OnHasPendingRestartChanged;
@@ -153,20 +151,6 @@ namespace Emby.Server.Implementations.EntryPoints
await SendMessageToUserSession(e.Argument, "UserDeleted", e.Argument.Id.ToString("N", CultureInfo.InvariantCulture)).ConfigureAwait(false);
}
- private async void OnUserPolicyUpdated(object sender, GenericEventArgs<User> e)
- {
- var dto = _userManager.GetUserDto(e.Argument);
-
- await SendMessageToUserSession(e.Argument, "UserPolicyUpdated", dto).ConfigureAwait(false);
- }
-
- private async void OnUserConfigurationUpdated(object sender, GenericEventArgs<User> e)
- {
- var dto = _userManager.GetUserDto(e.Argument);
-
- await SendMessageToUserSession(e.Argument, "UserConfigurationUpdated", dto).ConfigureAwait(false);
- }
-
private async Task SendMessageToAdminSessions<T>(string name, T data)
{
try
@@ -175,7 +159,6 @@ namespace Emby.Server.Implementations.EntryPoints
}
catch (Exception)
{
-
}
}
@@ -191,7 +174,6 @@ namespace Emby.Server.Implementations.EntryPoints
}
catch (Exception)
{
-
}
}
@@ -210,10 +192,8 @@ namespace Emby.Server.Implementations.EntryPoints
{
if (dispose)
{
- _userManager.UserDeleted -= OnUserDeleted;
- _userManager.UserUpdated -= OnUserUpdated;
- _userManager.UserPolicyUpdated -= OnUserPolicyUpdated;
- _userManager.UserConfigurationUpdated -= OnUserConfigurationUpdated;
+ _userManager.OnUserDeleted -= OnUserDeleted;
+ _userManager.OnUserUpdated -= OnUserUpdated;
_installationManager.PluginUninstalled -= OnPluginUninstalled;
_installationManager.PackageInstalling -= OnPackageInstalling;
diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
index ecdce89ce..b207397bd 100644
--- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
+++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
@@ -43,7 +43,6 @@ namespace Emby.Server.Implementations.EntryPoints
_logger = logger;
_appHost = appHost;
_config = configuration;
-
}
/// <inheritdoc />
diff --git a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
index 87977494a..25adc5812 100644
--- a/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
+++ b/Emby.Server.Implementations/HttpClientManager/HttpClientManager.cs
@@ -140,7 +140,7 @@ namespace Emby.Server.Implementations.HttpClientManager
=> SendAsync(options, HttpMethod.Get);
/// <summary>
- /// Performs a GET request and returns the resulting stream
+ /// Performs a GET request and returns the resulting stream.
/// </summary>
/// <param name="options">The options.</param>
/// <returns>Task{Stream}.</returns>
diff --git a/Emby.Server.Implementations/HttpServer/FileWriter.cs b/Emby.Server.Implementations/HttpServer/FileWriter.cs
index 0b61e40b0..590eee1b4 100644
--- a/Emby.Server.Implementations/HttpServer/FileWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/FileWriter.cs
@@ -32,12 +32,12 @@ namespace Emby.Server.Implementations.HttpServer
private readonly IFileSystem _fileSystem;
/// <summary>
- /// The _options
+ /// The _options.
/// </summary>
private readonly IDictionary<string, string> _options = new Dictionary<string, string>();
/// <summary>
- /// The _requested ranges
+ /// The _requested ranges.
/// </summary>
private List<KeyValuePair<long, long?>> _requestedRanges;
diff --git a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
index 1b6e4b554..c3428ee62 100644
--- a/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpListenerHost.cs
@@ -453,6 +453,7 @@ namespace Emby.Server.Implementations.HttpServer
{
httpRes.Headers.Add(key, value);
}
+
httpRes.ContentType = "text/plain";
await httpRes.WriteAsync(string.Empty, cancellationToken).ConfigureAwait(false);
return;
@@ -591,7 +592,7 @@ namespace Emby.Server.Implementations.HttpServer
}
/// <summary>
- /// Get the default CORS headers
+ /// Get the default CORS headers.
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
diff --git a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
index cc4797790..ad31b3e1e 100644
--- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -580,7 +580,6 @@ namespace Emby.Server.Implementations.HttpServer
}
catch (NotSupportedException)
{
-
}
}
@@ -693,7 +692,7 @@ namespace Emby.Server.Implementations.HttpServer
/// <summary>
- /// When the browser sends the IfModifiedDate, it's precision is limited to seconds, so this will account for that
+ /// When the browser sends the IfModifiedDate, it's precision is limited to seconds, so this will account for that.
/// </summary>
/// <param name="date">The date.</param>
/// <returns>DateTime.</returns>
diff --git a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs b/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs
index 8b9028f6b..540340272 100644
--- a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs
@@ -20,31 +20,37 @@ namespace Emby.Server.Implementations.HttpServer
/// </summary>
/// <value>The source stream.</value>
private Stream SourceStream { get; set; }
+
private string RangeHeader { get; set; }
+
private bool IsHeadRequest { get; set; }
private long RangeStart { get; set; }
+
private long RangeEnd { get; set; }
+
private long RangeLength { get; set; }
+
private long TotalContentLength { get; set; }
public Action OnComplete { get; set; }
+
private readonly ILogger _logger;
private const int BufferSize = 81920;
/// <summary>
- /// The _options
+ /// The _options.
/// </summary>
private readonly Dictionary<string, string> _options = new Dictionary<string, string>();
/// <summary>
- /// The us culture
+ /// The us culture.
/// </summary>
private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
/// <summary>
- /// Additional HTTP Headers
+ /// Additional HTTP Headers.
/// </summary>
/// <value>The headers.</value>
public IDictionary<string, string> Headers => _options;
@@ -110,7 +116,7 @@ namespace Emby.Server.Implementations.HttpServer
}
/// <summary>
- /// The _requested ranges
+ /// The _requested ranges.
/// </summary>
private List<KeyValuePair<long, long?>> _requestedRanges;
/// <summary>
@@ -139,6 +145,7 @@ namespace Emby.Server.Implementations.HttpServer
{
start = long.Parse(vals[0], UsCulture);
}
+
if (!string.IsNullOrEmpty(vals[1]))
{
end = long.Parse(vals[1], UsCulture);
diff --git a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs
index 85c3db9b2..3ab5dbc16 100644
--- a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs
+++ b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Generic;
using System.Globalization;
using System.Text;
using MediaBrowser.Controller.Net;
diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs
index 1b68617c1..2e6ff65a6 100644
--- a/Emby.Server.Implementations/HttpServer/Security/AuthService.cs
+++ b/Emby.Server.Implementations/HttpServer/Security/AuthService.cs
@@ -3,10 +3,11 @@
using System;
using System.Linq;
using Emby.Server.Implementations.SocketSharp;
+using Jellyfin.Data.Entities;
+using Jellyfin.Data.Enums;
using MediaBrowser.Common.Net;
using MediaBrowser.Controller.Authentication;
using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
@@ -90,7 +91,8 @@ namespace Emby.Server.Implementations.HttpServer.Security
!string.IsNullOrEmpty(auth.Client) &&
!string.IsNullOrEmpty(auth.Device))
{
- _sessionManager.LogSessionActivity(auth.Client,
+ _sessionManager.LogSessionActivity(
+ auth.Client,
auth.Version,
auth.DeviceId,
auth.Device,
@@ -104,21 +106,21 @@ namespace Emby.Server.Implementations.HttpServer.Security
private void ValidateUserAccess(
User user,
IRequest request,
- IAuthenticationAttributes authAttribtues,
+ IAuthenticationAttributes authAttributes,
AuthorizationInfo auth)
{
- if (user.Policy.IsDisabled)
+ if (user.HasPermission(PermissionKind.IsDisabled))
{
throw new SecurityException("User account has been disabled.");
}
- if (!user.Policy.EnableRemoteAccess && !_networkManager.IsInLocalNetwork(request.RemoteIp))
+ if (!user.HasPermission(PermissionKind.EnableRemoteAccess) && !_networkManager.IsInLocalNetwork(request.RemoteIp))
{
throw new SecurityException("User account has been disabled.");
}
- if (!user.Policy.IsAdministrator
- && !authAttribtues.EscapeParentalControl
+ if (!user.HasPermission(PermissionKind.IsAdministrator)
+ && !authAttributes.EscapeParentalControl
&& !user.IsParentalScheduleAllowed())
{
request.Response.Headers.Add("X-Application-Error-Code", "ParentalControl");
@@ -138,6 +140,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
{
return true;
}
+
if (authAttribtues.AllowLocalOnly && request.IsLocal)
{
return true;
@@ -180,7 +183,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
{
if (roles.Contains("admin", StringComparer.OrdinalIgnoreCase))
{
- if (user == null || !user.Policy.IsAdministrator)
+ if (user == null || !user.HasPermission(PermissionKind.IsAdministrator))
{
throw new SecurityException("User does not have admin access.");
}
@@ -188,7 +191,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
if (roles.Contains("delete", StringComparer.OrdinalIgnoreCase))
{
- if (user == null || !user.Policy.EnableContentDeletion)
+ if (user == null || !user.HasPermission(PermissionKind.EnableContentDeletion))
{
throw new SecurityException("User does not have delete access.");
}
@@ -196,7 +199,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
if (roles.Contains("download", StringComparer.OrdinalIgnoreCase))
{
- if (user == null || !user.Policy.EnableContentDownloading)
+ if (user == null || !user.HasPermission(PermissionKind.EnableContentDownloading))
{
throw new SecurityException("User does not have download access.");
}
@@ -223,7 +226,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
throw new AuthenticationException("Access token is invalid or expired.");
}
- //if (!string.IsNullOrEmpty(info.UserId))
+ // if (!string.IsNullOrEmpty(info.UserId))
//{
// var user = _userManager.GetUserById(info.UserId);
diff --git a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
index 129faeaab..bbade00ff 100644
--- a/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
+++ b/Emby.Server.Implementations/HttpServer/Security/AuthorizationContext.cs
@@ -71,6 +71,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
{
token = httpReq.Headers["X-MediaBrowser-Token"];
}
+
if (string.IsNullOrEmpty(token))
{
token = httpReq.QueryString["api_key"];
@@ -116,7 +117,6 @@ namespace Emby.Server.Implementations.HttpServer.Security
{
info.Device = tokenInfo.DeviceName;
}
-
else if (!string.Equals(info.Device, tokenInfo.DeviceName, StringComparison.OrdinalIgnoreCase))
{
if (allowTokenInfoUpdate)
@@ -149,9 +149,9 @@ namespace Emby.Server.Implementations.HttpServer.Security
{
info.User = _userManager.GetUserById(tokenInfo.UserId);
- if (info.User != null && !string.Equals(info.User.Name, tokenInfo.UserName, StringComparison.OrdinalIgnoreCase))
+ if (info.User != null && !string.Equals(info.User.Username, tokenInfo.UserName, StringComparison.OrdinalIgnoreCase))
{
- tokenInfo.UserName = info.User.Name;
+ tokenInfo.UserName = info.User.Username;
updateToken = true;
}
}
@@ -161,6 +161,7 @@ namespace Emby.Server.Implementations.HttpServer.Security
_authRepo.Update(tokenInfo);
}
}
+
httpReq.Items["OriginalAuthenticationInfo"] = tokenInfo;
}
diff --git a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs
index 166952c64..03fcfa53d 100644
--- a/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs
+++ b/Emby.Server.Implementations/HttpServer/Security/SessionContext.cs
@@ -1,7 +1,7 @@
#pragma warning disable CS1591
using System;
-using MediaBrowser.Controller.Entities;
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Security;
diff --git a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
index c64d57339..316cd84cf 100644
--- a/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
+++ b/Emby.Server.Implementations/HttpServer/WebSocketConnection.cs
@@ -234,10 +234,12 @@ namespace Emby.Server.Implementations.HttpServer
private Task SendKeepAliveResponse()
{
LastKeepAliveDate = DateTime.UtcNow;
- return SendAsync(new WebSocketMessage<string>
- {
- MessageType = "KeepAlive"
- }, CancellationToken.None);
+ return SendAsync(
+ new WebSocketMessage<string>
+ {
+ MessageId = Guid.NewGuid(),
+ MessageType = "KeepAlive"
+ }, CancellationToken.None);
}
/// <inheritdoc />
diff --git a/Emby.Server.Implementations/IO/LibraryMonitor.cs b/Emby.Server.Implementations/IO/LibraryMonitor.cs
index 49bca7dac..a32b03aaa 100644
--- a/Emby.Server.Implementations/IO/LibraryMonitor.cs
+++ b/Emby.Server.Implementations/IO/LibraryMonitor.cs
@@ -266,7 +266,6 @@ namespace Emby.Server.Implementations.IO
{
DisposeWatcher(newWatcher, false);
}
-
}
catch (Exception ex)
{
@@ -393,7 +392,6 @@ namespace Emby.Server.Implementations.IO
}
return false;
-
}))
{
monitorPath = false;
diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
index 2bcfc82b6..a3a3f91b7 100644
--- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs
+++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs
@@ -237,7 +237,7 @@ namespace Emby.Server.Implementations.IO
{
result.IsDirectory = info is DirectoryInfo || (info.Attributes & FileAttributes.Directory) == FileAttributes.Directory;
- //if (!result.IsDirectory)
+ // if (!result.IsDirectory)
//{
// result.IsHidden = (info.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden;
//}
@@ -628,6 +628,7 @@ namespace Emby.Server.Implementations.IO
{
return false;
}
+
return extensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
});
}
@@ -682,6 +683,7 @@ namespace Emby.Server.Implementations.IO
{
return false;
}
+
return extensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
});
}
diff --git a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs
index dc8062b45..da88b8d8a 100644
--- a/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs
+++ b/Emby.Server.Implementations/Images/CollectionFolderImageProvider.cs
@@ -71,7 +71,6 @@ namespace Emby.Server.Implementations.Images
new ValueTuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending)
},
IncludeItemTypes = includeItemTypes
-
});
}
diff --git a/Emby.Server.Implementations/Images/DynamicImageProvider.cs b/Emby.Server.Implementations/Images/DynamicImageProvider.cs
index ca0aa4a9f..462eb03a8 100644
--- a/Emby.Server.Implementations/Images/DynamicImageProvider.cs
+++ b/Emby.Server.Implementations/Images/DynamicImageProvider.cs
@@ -78,7 +78,6 @@ namespace Emby.Server.Implementations.Images
}
return i;
-
}).GroupBy(x => x.Id)
.Select(x => x.First());
diff --git a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
index 218e5a0c6..e140009ea 100644
--- a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
+++ b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
@@ -8,7 +8,7 @@ using MediaBrowser.Model.IO;
namespace Emby.Server.Implementations.Library
{
/// <summary>
- /// Provides the core resolver ignore rules
+ /// Provides the core resolver ignore rules.
/// </summary>
public class CoreResolutionIgnoreRule : IResolverIgnoreRule
{
diff --git a/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs b/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs
deleted file mode 100644
index 02f150607..000000000
--- a/Emby.Server.Implementations/Library/DefaultAuthenticationProvider.cs
+++ /dev/null
@@ -1,139 +0,0 @@
-using System;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using MediaBrowser.Common;
-using MediaBrowser.Common.Cryptography;
-using MediaBrowser.Controller.Authentication;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Model.Cryptography;
-
-namespace Emby.Server.Implementations.Library
-{
- /// <summary>
- /// The default authentication provider.
- /// </summary>
- public class DefaultAuthenticationProvider : IAuthenticationProvider, IRequiresResolvedUser
- {
- private readonly ICryptoProvider _cryptographyProvider;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="DefaultAuthenticationProvider"/> class.
- /// </summary>
- /// <param name="cryptographyProvider">The cryptography provider.</param>
- public DefaultAuthenticationProvider(ICryptoProvider cryptographyProvider)
- {
- _cryptographyProvider = cryptographyProvider;
- }
-
- /// <inheritdoc />
- public string Name => "Default";
-
- /// <inheritdoc />
- public bool IsEnabled => true;
-
- /// <inheritdoc />
- // This is dumb and an artifact of the backwards way auth providers were designed.
- // This version of authenticate was never meant to be called, but needs to be here for interface compat
- // Only the providers that don't provide local user support use this
- public Task<ProviderAuthenticationResult> Authenticate(string username, string password)
- {
- throw new NotImplementedException();
- }
-
- /// <inheritdoc />
- // This is the version that we need to use for local users. Because reasons.
- public Task<ProviderAuthenticationResult> Authenticate(string username, string password, User resolvedUser)
- {
- if (resolvedUser == null)
- {
- throw new AuthenticationException($"Specified user does not exist.");
- }
-
- bool success = false;
-
- // As long as jellyfin supports passwordless users, we need this little block here to accommodate
- if (!HasPassword(resolvedUser) && string.IsNullOrEmpty(password))
- {
- return Task.FromResult(new ProviderAuthenticationResult
- {
- Username = username
- });
- }
-
- byte[] passwordbytes = Encoding.UTF8.GetBytes(password);
-
- PasswordHash readyHash = PasswordHash.Parse(resolvedUser.Password);
- if (_cryptographyProvider.GetSupportedHashMethods().Contains(readyHash.Id)
- || _cryptographyProvider.DefaultHashMethod == readyHash.Id)
- {
- byte[] calculatedHash = _cryptographyProvider.ComputeHash(
- readyHash.Id,
- passwordbytes,
- readyHash.Salt.ToArray());
-
- if (readyHash.Hash.SequenceEqual(calculatedHash))
- {
- success = true;
- }
- }
- else
- {
- throw new AuthenticationException($"Requested crypto method not available in provider: {readyHash.Id}");
- }
-
- if (!success)
- {
- throw new AuthenticationException("Invalid username or password");
- }
-
- return Task.FromResult(new ProviderAuthenticationResult
- {
- Username = username
- });
- }
-
- /// <inheritdoc />
- public bool HasPassword(User user)
- => !string.IsNullOrEmpty(user.Password);
-
- /// <inheritdoc />
- public Task ChangePassword(User user, string newPassword)
- {
- if (string.IsNullOrEmpty(newPassword))
- {
- user.Password = null;
- return Task.CompletedTask;
- }
-
- PasswordHash newPasswordHash = _cryptographyProvider.CreatePasswordHash(newPassword);
- user.Password = newPasswordHash.ToString();
-
- return Task.CompletedTask;
- }
-
- /// <inheritdoc />
- public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash)
- {
- if (newPassword != null)
- {
- newPasswordHash = _cryptographyProvider.CreatePasswordHash(newPassword).ToString();
- }
-
- if (string.IsNullOrWhiteSpace(newPasswordHash))
- {
- throw new ArgumentNullException(nameof(newPasswordHash));
- }
-
- user.EasyPassword = newPasswordHash;
- }
-
- /// <inheritdoc />
- public string GetEasyPasswordHash(User user)
- {
- return string.IsNullOrEmpty(user.EasyPassword)
- ? null
- : Hex.Encode(PasswordHash.Parse(user.EasyPassword).Hash);
- }
- }
-}
diff --git a/Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs b/Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs
deleted file mode 100644
index 6c6fbd86f..000000000
--- a/Emby.Server.Implementations/Library/DefaultPasswordResetProvider.cs
+++ /dev/null
@@ -1,140 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Security.Cryptography;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Extensions;
-using MediaBrowser.Controller.Authentication;
-using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Users;
-
-namespace Emby.Server.Implementations.Library
-{
- /// <summary>
- /// The default password reset provider.
- /// </summary>
- public class DefaultPasswordResetProvider : IPasswordResetProvider
- {
- private const string BaseResetFileName = "passwordreset";
-
- private readonly IJsonSerializer _jsonSerializer;
- private readonly IUserManager _userManager;
-
- private readonly string _passwordResetFileBase;
- private readonly string _passwordResetFileBaseDir;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="DefaultPasswordResetProvider"/> class.
- /// </summary>
- /// <param name="configurationManager">The configuration manager.</param>
- /// <param name="jsonSerializer">The JSON serializer.</param>
- /// <param name="userManager">The user manager.</param>
- public DefaultPasswordResetProvider(
- IServerConfigurationManager configurationManager,
- IJsonSerializer jsonSerializer,
- IUserManager userManager)
- {
- _passwordResetFileBaseDir = configurationManager.ApplicationPaths.ProgramDataPath;
- _passwordResetFileBase = Path.Combine(_passwordResetFileBaseDir, BaseResetFileName);
- _jsonSerializer = jsonSerializer;
- _userManager = userManager;
- }
-
- /// <inheritdoc />
- public string Name => "Default Password Reset Provider";
-
- /// <inheritdoc />
- public bool IsEnabled => true;
-
- /// <inheritdoc />
- public async Task<PinRedeemResult> RedeemPasswordResetPin(string pin)
- {
- SerializablePasswordReset spr;
- List<string> usersreset = new List<string>();
- foreach (var resetfile in Directory.EnumerateFiles(_passwordResetFileBaseDir, $"{BaseResetFileName}*"))
- {
- using (var str = File.OpenRead(resetfile))
- {
- spr = await _jsonSerializer.DeserializeFromStreamAsync<SerializablePasswordReset>(str).ConfigureAwait(false);
- }
-
- if (spr.ExpirationDate < DateTime.Now)
- {
- File.Delete(resetfile);
- }
- else if (string.Equals(
- spr.Pin.Replace("-", string.Empty, StringComparison.Ordinal),
- pin.Replace("-", string.Empty, StringComparison.Ordinal),
- StringComparison.InvariantCultureIgnoreCase))
- {
- var resetUser = _userManager.GetUserByName(spr.UserName);
- if (resetUser == null)
- {
- throw new ResourceNotFoundException($"User with a username of {spr.UserName} not found");
- }
-
- await _userManager.ChangePassword(resetUser, pin).ConfigureAwait(false);
- usersreset.Add(resetUser.Name);
- File.Delete(resetfile);
- }
- }
-
- if (usersreset.Count < 1)
- {
- throw new ResourceNotFoundException($"No Users found with a password reset request matching pin {pin}");
- }
- else
- {
- return new PinRedeemResult
- {
- Success = true,
- UsersReset = usersreset.ToArray()
- };
- }
- }
-
- /// <inheritdoc />
- public async Task<ForgotPasswordResult> StartForgotPasswordProcess(MediaBrowser.Controller.Entities.User user, bool isInNetwork)
- {
- string pin = string.Empty;
- using (var cryptoRandom = RandomNumberGenerator.Create())
- {
- byte[] bytes = new byte[4];
- cryptoRandom.GetBytes(bytes);
- pin = BitConverter.ToString(bytes);
- }
-
- DateTime expireTime = DateTime.Now.AddMinutes(30);
- string filePath = _passwordResetFileBase + user.InternalId + ".json";
- SerializablePasswordReset spr = new SerializablePasswordReset
- {
- ExpirationDate = expireTime,
- Pin = pin,
- PinFile = filePath,
- UserName = user.Name
- };
-
- using (FileStream fileStream = File.OpenWrite(filePath))
- {
- _jsonSerializer.SerializeToStream(spr, fileStream);
- await fileStream.FlushAsync().ConfigureAwait(false);
- }
-
- return new ForgotPasswordResult
- {
- Action = ForgotPasswordAction.PinCode,
- PinExpirationDate = expireTime,
- PinFile = filePath
- };
- }
-
- private class SerializablePasswordReset : PasswordPinCreationResult
- {
- public string Pin { get; set; }
-
- public string UserName { get; set; }
- }
- }
-}
diff --git a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs
index 9a7186898..ab39a7223 100644
--- a/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs
+++ b/Emby.Server.Implementations/Library/ExclusiveLiveStream.cs
@@ -12,11 +12,13 @@ namespace Emby.Server.Implementations.Library
public class ExclusiveLiveStream : ILiveStream
{
public int ConsumerCount { get; set; }
+
public string OriginalStreamId { get; set; }
public string TunerHostId => null;
public bool EnableStreamSharing { get; set; }
+
public MediaSourceInfo MediaSource { get; set; }
public string UniqueId { get; private set; }
diff --git a/Emby.Server.Implementations/Library/IgnorePatterns.cs b/Emby.Server.Implementations/Library/IgnorePatterns.cs
index d12b5855b..8c4098948 100644
--- a/Emby.Server.Implementations/Library/IgnorePatterns.cs
+++ b/Emby.Server.Implementations/Library/IgnorePatterns.cs
@@ -4,12 +4,12 @@ using DotNet.Globbing;
namespace Emby.Server.Implementations.Library
{
/// <summary>
- /// Glob patterns for files to ignore
+ /// Glob patterns for files to ignore.
/// </summary>
public static class IgnorePatterns
{
/// <summary>
- /// Files matching these glob patterns will be ignored
+ /// Files matching these glob patterns will be ignored.
/// </summary>
public static readonly string[] Patterns = new string[]
{
@@ -64,7 +64,7 @@ namespace Emby.Server.Implementations.Library
private static readonly Glob[] _globs = Patterns.Select(p => Glob.Parse(p, _globOptions)).ToArray();
/// <summary>
- /// Returns true if the supplied path should be ignored
+ /// Returns true if the supplied path should be ignored.
/// </summary>
public static bool ShouldIgnore(string path)
{
diff --git a/Emby.Server.Implementations/Library/InvalidAuthProvider.cs b/Emby.Server.Implementations/Library/InvalidAuthProvider.cs
deleted file mode 100644
index dc61aacd7..000000000
--- a/Emby.Server.Implementations/Library/InvalidAuthProvider.cs
+++ /dev/null
@@ -1,54 +0,0 @@
-using System.Threading.Tasks;
-using MediaBrowser.Controller.Authentication;
-using MediaBrowser.Controller.Entities;
-
-namespace Emby.Server.Implementations.Library
-{
- /// <summary>
- /// An invalid authentication provider.
- /// </summary>
- public class InvalidAuthProvider : IAuthenticationProvider
- {
- /// <inheritdoc />
- public string Name => "InvalidOrMissingAuthenticationProvider";
-
- /// <inheritdoc />
- public bool IsEnabled => true;
-
- /// <inheritdoc />
- public Task<ProviderAuthenticationResult> Authenticate(string username, string password)
- {
- throw new AuthenticationException("User Account cannot login with this provider. The Normal provider for this user cannot be found");
- }
-
- /// <inheritdoc />
- public bool HasPassword(User user)
- {
- return true;
- }
-
- /// <inheritdoc />
- public Task ChangePassword(User user, string newPassword)
- {
- return Task.CompletedTask;
- }
-
- /// <inheritdoc />
- public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash)
- {
- // Nothing here
- }
-
- /// <inheritdoc />
- public string GetPasswordHash(User user)
- {
- return string.Empty;
- }
-
- /// <inheritdoc />
- public string GetEasyPasswordHash(User user)
- {
- return string.Empty;
- }
- }
-}
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index a57219143..893af4cae 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -17,6 +17,8 @@ using Emby.Server.Implementations.Library.Resolvers;
using Emby.Server.Implementations.Library.Validators;
using Emby.Server.Implementations.Playlists;
using Emby.Server.Implementations.ScheduledTasks;
+using Jellyfin.Data.Entities;
+using Jellyfin.Data.Enums;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Progress;
using MediaBrowser.Controller;
@@ -25,7 +27,6 @@ using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
-using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
@@ -46,6 +47,9 @@ using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Tasks;
using MediaBrowser.Providers.MediaInfo;
using Microsoft.Extensions.Logging;
+using Episode = MediaBrowser.Controller.Entities.TV.Episode;
+using Genre = MediaBrowser.Controller.Entities.Genre;
+using Person = MediaBrowser.Controller.Entities.Person;
using SortOrder = MediaBrowser.Model.Entities.SortOrder;
using VideoResolver = Emby.Naming.Video.VideoResolver;
@@ -93,13 +97,13 @@ namespace Emby.Server.Implementations.Library
private IIntroProvider[] IntroProviders { get; set; }
/// <summary>
- /// Gets or sets the list of entity resolution ignore rules
+ /// Gets or sets the list of entity resolution ignore rules.
/// </summary>
/// <value>The entity resolution ignore rules.</value>
private IResolverIgnoreRule[] EntityResolutionIgnoreRules { get; set; }
/// <summary>
- /// Gets or sets the list of currently registered entity resolvers
+ /// Gets or sets the list of currently registered entity resolvers.
/// </summary>
/// <value>The entity resolvers enumerable.</value>
private IItemResolver[] EntityResolvers { get; set; }
@@ -205,12 +209,12 @@ namespace Emby.Server.Implementations.Library
}
/// <summary>
- /// The _root folder
+ /// The _root folder.
/// </summary>
private volatile AggregateFolder _rootFolder;
/// <summary>
- /// The _root folder sync lock
+ /// The _root folder sync lock.
/// </summary>
private readonly object _rootFolderSyncLock = new object();
@@ -623,7 +627,7 @@ namespace Emby.Server.Implementations.Library
}
/// <summary>
- /// Determines whether a path should be ignored based on its contents - called after the contents have been read
+ /// Determines whether a path should be ignored based on its contents - called after the contents have been read.
/// </summary>
/// <param name="args">The args.</param>
/// <returns><c>true</c> if XXXX, <c>false</c> otherwise</returns>
@@ -905,7 +909,7 @@ namespace Emby.Server.Implementations.Library
}
/// <summary>
- /// Gets a Genre
+ /// Gets a Genre.
/// </summary>
/// <param name="name">The name.</param>
/// <returns>Task{Genre}.</returns>
@@ -986,7 +990,7 @@ namespace Emby.Server.Implementations.Library
}
/// <summary>
- /// Reloads the root media folder
+ /// Reloads the root media folder.
/// </summary>
/// <param name="progress">The progress.</param>
/// <param name="cancellationToken">The cancellation token.</param>
@@ -1539,7 +1543,8 @@ namespace Emby.Server.Implementations.Library
}
// Handle grouping
- if (user != null && !string.IsNullOrEmpty(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType) && user.Configuration.GroupedFolders.Length > 0)
+ if (user != null && !string.IsNullOrEmpty(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType)
+ && user.GetPreference(PreferenceKind.GroupedFolders).Length > 0)
{
return GetUserRootFolder()
.GetChildren(user, true)
@@ -2590,7 +2595,7 @@ namespace Emby.Server.Implementations.Library
Anime series don't generally have a season in their file name, however,
tvdb needs a season to correctly get the metadata.
Hence, a null season needs to be filled with something. */
- //FIXME perhaps this would be better for tvdb parser to ask for season 1 if no season is specified
+ // FIXME perhaps this would be better for tvdb parser to ask for season 1 if no season is specified
episode.ParentIndexNumber = 1;
}
@@ -2779,10 +2784,12 @@ namespace Emby.Server.Implementations.Library
{
throw new ArgumentNullException(nameof(path));
}
+
if (string.IsNullOrWhiteSpace(from))
{
throw new ArgumentNullException(nameof(from));
}
+
if (string.IsNullOrWhiteSpace(to))
{
throw new ArgumentNullException(nameof(to));
@@ -2856,7 +2863,6 @@ namespace Emby.Server.Implementations.Library
_logger.LogError(ex, "Error getting person");
return null;
}
-
}).Where(i => i != null).ToList();
}
@@ -2986,7 +2992,7 @@ namespace Emby.Server.Implementations.Library
private static bool ValidateNetworkPath(string path)
{
- //if (Environment.OSVersion.Platform == PlatformID.Win32NT)
+ // if (Environment.OSVersion.Platform == PlatformID.Win32NT)
//{
// // We can't validate protocol-based paths, so just allow them
// if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) == -1)
diff --git a/Emby.Server.Implementations/Library/LiveStreamHelper.cs b/Emby.Server.Implementations/Library/LiveStreamHelper.cs
index ed7d8aa40..9b9f53049 100644
--- a/Emby.Server.Implementations/Library/LiveStreamHelper.cs
+++ b/Emby.Server.Implementations/Library/LiveStreamHelper.cs
@@ -50,7 +50,7 @@ namespace Emby.Server.Implementations.Library
{
mediaInfo = _json.DeserializeFromFile<MediaInfo>(cacheFilePath);
- //_logger.LogDebug("Found cached media info");
+ // _logger.LogDebug("Found cached media info");
}
catch
{
@@ -85,7 +85,7 @@ namespace Emby.Server.Implementations.Library
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
_json.SerializeToFile(mediaInfo, cacheFilePath);
- //_logger.LogDebug("Saved media info to {0}", cacheFilePath);
+ // _logger.LogDebug("Saved media info to {0}", cacheFilePath);
}
}
@@ -148,17 +148,14 @@ namespace Emby.Server.Implementations.Library
{
videoStream.BitRate = 30000000;
}
-
else if (width >= 1900)
{
videoStream.BitRate = 20000000;
}
-
else if (width >= 1200)
{
videoStream.BitRate = 8000000;
}
-
else if (width >= 700)
{
videoStream.BitRate = 2000000;
diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs
index 00826c7cb..ceb36b389 100644
--- a/Emby.Server.Implementations/Library/MediaSourceManager.cs
+++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs
@@ -7,6 +7,8 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Entities;
+using Jellyfin.Data.Enums;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Entities;
@@ -14,7 +16,6 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Dlna;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
@@ -190,10 +191,7 @@ namespace Emby.Server.Implementations.Library
{
if (string.Equals(item.MediaType, MediaType.Audio, StringComparison.OrdinalIgnoreCase))
{
- if (!user.Policy.EnableAudioPlaybackTranscoding)
- {
- source.SupportsTranscoding = false;
- }
+ source.SupportsTranscoding = user.HasPermission(PermissionKind.EnableAudioPlaybackTranscoding);
}
}
}
@@ -207,22 +205,27 @@ namespace Emby.Server.Implementations.Library
{
return MediaProtocol.Rtsp;
}
+
if (path.StartsWith("Rtmp", StringComparison.OrdinalIgnoreCase))
{
return MediaProtocol.Rtmp;
}
+
if (path.StartsWith("Http", StringComparison.OrdinalIgnoreCase))
{
return MediaProtocol.Http;
}
+
if (path.StartsWith("rtp", StringComparison.OrdinalIgnoreCase))
{
return MediaProtocol.Rtp;
}
+
if (path.StartsWith("ftp", StringComparison.OrdinalIgnoreCase))
{
return MediaProtocol.Ftp;
}
+
if (path.StartsWith("udp", StringComparison.OrdinalIgnoreCase))
{
return MediaProtocol.Udp;
@@ -352,7 +355,9 @@ namespace Emby.Server.Implementations.Library
private void SetDefaultSubtitleStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)
{
- if (userData.SubtitleStreamIndex.HasValue && user.Configuration.RememberSubtitleSelections && user.Configuration.SubtitleMode != SubtitlePlaybackMode.None && allowRememberingSelection)
+ if (userData.SubtitleStreamIndex.HasValue
+ && user.RememberSubtitleSelections
+ && user.SubtitleMode != SubtitlePlaybackMode.None && allowRememberingSelection)
{
var index = userData.SubtitleStreamIndex.Value;
// Make sure the saved index is still valid
@@ -363,26 +368,27 @@ namespace Emby.Server.Implementations.Library
}
}
- var preferredSubs = string.IsNullOrEmpty(user.Configuration.SubtitleLanguagePreference)
- ? Array.Empty<string>() : NormalizeLanguage(user.Configuration.SubtitleLanguagePreference);
+
+ var preferredSubs = string.IsNullOrEmpty(user.SubtitleLanguagePreference)
+ ? Array.Empty<string>() : NormalizeLanguage(user.SubtitleLanguagePreference);
var defaultAudioIndex = source.DefaultAudioStreamIndex;
var audioLangage = defaultAudioIndex == null
? null
: source.MediaStreams.Where(i => i.Type == MediaStreamType.Audio && i.Index == defaultAudioIndex).Select(i => i.Language).FirstOrDefault();
- source.DefaultSubtitleStreamIndex = MediaStreamSelector.GetDefaultSubtitleStreamIndex(source.MediaStreams,
+ source.DefaultSubtitleStreamIndex = MediaStreamSelector.GetDefaultSubtitleStreamIndex(
+ source.MediaStreams,
preferredSubs,
- user.Configuration.SubtitleMode,
+ user.SubtitleMode,
audioLangage);
- MediaStreamSelector.SetSubtitleStreamScores(source.MediaStreams, preferredSubs,
- user.Configuration.SubtitleMode, audioLangage);
+ MediaStreamSelector.SetSubtitleStreamScores(source.MediaStreams, preferredSubs, user.SubtitleMode, audioLangage);
}
private void SetDefaultAudioStreamIndex(MediaSourceInfo source, UserItemData userData, User user, bool allowRememberingSelection)
{
- if (userData.AudioStreamIndex.HasValue && user.Configuration.RememberAudioSelections && allowRememberingSelection)
+ if (userData.AudioStreamIndex.HasValue && user.RememberAudioSelections && allowRememberingSelection)
{
var index = userData.AudioStreamIndex.Value;
// Make sure the saved index is still valid
@@ -393,11 +399,11 @@ namespace Emby.Server.Implementations.Library
}
}
- var preferredAudio = string.IsNullOrEmpty(user.Configuration.AudioLanguagePreference)
+ var preferredAudio = string.IsNullOrEmpty(user.AudioLanguagePreference)
? Array.Empty<string>()
- : NormalizeLanguage(user.Configuration.AudioLanguagePreference);
+ : NormalizeLanguage(user.AudioLanguagePreference);
- source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.Configuration.PlayDefaultAudioTrack);
+ source.DefaultAudioStreamIndex = MediaStreamSelector.GetDefaultAudioStreamIndex(source.MediaStreams, preferredAudio, user.PlayDefaultAudioTrack);
}
public void SetDefaultAudioAndSubtitleStreamIndexes(BaseItem item, MediaSourceInfo source, User user)
@@ -435,7 +441,6 @@ namespace Emby.Server.Implementations.Library
}
return 1;
-
}).ThenBy(i => i.Video3DFormat.HasValue ? 1 : 0)
.ThenByDescending(i =>
{
@@ -534,7 +539,7 @@ namespace Emby.Server.Implementations.Library
mediaSource.RunTimeTicks = null;
}
- var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaBrowser.Model.Entities.MediaStreamType.Audio);
+ var audioStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
if (audioStream == null || audioStream.Index == -1)
{
@@ -545,7 +550,7 @@ namespace Emby.Server.Implementations.Library
mediaSource.DefaultAudioStreamIndex = audioStream.Index;
}
- var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaBrowser.Model.Entities.MediaStreamType.Video);
+ var videoStream = mediaSource.MediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video);
if (videoStream != null)
{
if (!videoStream.BitRate.HasValue)
@@ -556,17 +561,14 @@ namespace Emby.Server.Implementations.Library
{
videoStream.BitRate = 30000000;
}
-
else if (width >= 1900)
{
videoStream.BitRate = 20000000;
}
-
else if (width >= 1200)
{
videoStream.BitRate = 8000000;
}
-
else if (width >= 700)
{
videoStream.BitRate = 2000000;
@@ -622,7 +624,6 @@ namespace Emby.Server.Implementations.Library
MediaSource = mediaSource,
ExtractChapters = false,
MediaType = DlnaProfileType.Video
-
}, cancellationToken).ConfigureAwait(false);
mediaSource.MediaStreams = info.MediaStreams;
@@ -648,7 +649,7 @@ namespace Emby.Server.Implementations.Library
{
mediaInfo = _jsonSerializer.DeserializeFromFile<MediaInfo>(cacheFilePath);
- //_logger.LogDebug("Found cached media info");
+ // _logger.LogDebug("Found cached media info");
}
catch (Exception ex)
{
@@ -670,20 +671,21 @@ namespace Emby.Server.Implementations.Library
mediaSource.AnalyzeDurationMs = 3000;
}
- mediaInfo = await _mediaEncoder.GetMediaInfo(new MediaInfoRequest
+ mediaInfo = await _mediaEncoder.GetMediaInfo(
+ new MediaInfoRequest
{
MediaSource = mediaSource,
MediaType = isAudio ? DlnaProfileType.Audio : DlnaProfileType.Video,
ExtractChapters = false
-
- }, cancellationToken).ConfigureAwait(false);
+ },
+ cancellationToken).ConfigureAwait(false);
if (cacheFilePath != null)
{
Directory.CreateDirectory(Path.GetDirectoryName(cacheFilePath));
_jsonSerializer.SerializeToFile(mediaInfo, cacheFilePath);
- //_logger.LogDebug("Saved media info to {0}", cacheFilePath);
+ // _logger.LogDebug("Saved media info to {0}", cacheFilePath);
}
}
@@ -749,17 +751,14 @@ namespace Emby.Server.Implementations.Library
{
videoStream.BitRate = 30000000;
}
-
else if (width >= 1900)
{
videoStream.BitRate = 20000000;
}
-
else if (width >= 1200)
{
videoStream.BitRate = 8000000;
}
-
else if (width >= 700)
{
videoStream.BitRate = 2000000;
diff --git a/Emby.Server.Implementations/Library/MediaStreamSelector.cs b/Emby.Server.Implementations/Library/MediaStreamSelector.cs
index e27145a1d..ca904c4ec 100644
--- a/Emby.Server.Implementations/Library/MediaStreamSelector.cs
+++ b/Emby.Server.Implementations/Library/MediaStreamSelector.cs
@@ -3,7 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using MediaBrowser.Model.Configuration;
+using Jellyfin.Data.Enums;
using MediaBrowser.Model.Entities;
namespace Emby.Server.Implementations.Library
diff --git a/Emby.Server.Implementations/Library/MusicManager.cs b/Emby.Server.Implementations/Library/MusicManager.cs
index 1ec578371..0bdc59914 100644
--- a/Emby.Server.Implementations/Library/MusicManager.cs
+++ b/Emby.Server.Implementations/Library/MusicManager.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -10,6 +11,7 @@ using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
+using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
namespace Emby.Server.Implementations.Library
{
@@ -75,7 +77,6 @@ namespace Emby.Server.Implementations.Library
{
return Guid.Empty;
}
-
}).Where(i => !i.Equals(Guid.Empty)).ToArray();
return GetInstantMixFromGenreIds(genreIds, user, dtoOptions);
@@ -105,32 +106,27 @@ namespace Emby.Server.Implementations.Library
return GetInstantMixFromGenreIds(new[] { item.Id }, user, dtoOptions);
}
- var playlist = item as Playlist;
- if (playlist != null)
+ if (item is Playlist playlist)
{
return GetInstantMixFromPlaylist(playlist, user, dtoOptions);
}
- var album = item as MusicAlbum;
- if (album != null)
+ if (item is MusicAlbum album)
{
return GetInstantMixFromAlbum(album, user, dtoOptions);
}
- var artist = item as MusicArtist;
- if (artist != null)
+ if (item is MusicArtist artist)
{
return GetInstantMixFromArtist(artist, user, dtoOptions);
}
- var song = item as Audio;
- if (song != null)
+ if (item is Audio song)
{
return GetInstantMixFromSong(song, user, dtoOptions);
}
- var folder = item as Folder;
- if (folder != null)
+ if (item is Folder folder)
{
return GetInstantMixFromFolder(folder, user, dtoOptions);
}
diff --git a/Emby.Server.Implementations/Library/ResolverHelper.cs b/Emby.Server.Implementations/Library/ResolverHelper.cs
index 7ca15b4e5..4e4cac75b 100644
--- a/Emby.Server.Implementations/Library/ResolverHelper.cs
+++ b/Emby.Server.Implementations/Library/ResolverHelper.cs
@@ -107,7 +107,7 @@ namespace Emby.Server.Implementations.Library
}
/// <summary>
- /// Ensures DateCreated and DateModified have values
+ /// Ensures DateCreated and DateModified have values.
/// </summary>
/// <param name="fileSystem">The file system.</param>
/// <param name="item">The item.</param>
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
index fefc8e789..03059e6d3 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/AudioResolver.cs
@@ -209,8 +209,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
Name = parseName ?
resolvedItem.Name :
Path.GetFileNameWithoutExtension(firstMedia.Path),
- //AdditionalParts = resolvedItem.Files.Skip(1).Select(i => i.Path).ToArray(),
- //LocalAlternateVersions = resolvedItem.AlternateVersions.Select(i => i.Path).ToArray()
+ // AdditionalParts = resolvedItem.Files.Skip(1).Select(i => i.Path).ToArray(),
+ // LocalAlternateVersions = resolvedItem.AlternateVersions.Select(i => i.Path).ToArray()
};
result.Items.Add(libraryItem);
diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
index ebfe95d0a..79b6dded3 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicAlbumResolver.cs
@@ -92,7 +92,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
// Args points to an album if parent is an Artist folder or it directly contains music
if (args.IsDirectory)
{
- // if (args.Parent is MusicArtist) return true; //saves us from testing children twice
+ // if (args.Parent is MusicArtist) return true; // saves us from testing children twice
if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService, _logger, _fileSystem, _libraryManager))
{
return true;
diff --git a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
index fb75593bd..2f5e46038 100644
--- a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
@@ -292,7 +292,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
}
return true;
- //var blurayExtensions = new[]
+ // var blurayExtensions = new[]
//{
// ".mts",
// ".m2ts",
@@ -300,7 +300,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
// ".mpls"
//};
- //return directoryService.GetFiles(fullPath).Any(i => blurayExtensions.Contains(i.Extension ?? string.Empty, StringComparer.OrdinalIgnoreCase));
+ // return directoryService.GetFiles(fullPath).Any(i => blurayExtensions.Contains(i.Extension ?? string.Empty, StringComparer.OrdinalIgnoreCase));
}
}
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs b/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs
index 32ccc7fdd..9ca76095b 100644
--- a/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/ItemResolver.cs
@@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
public virtual ResolverPriority Priority => ResolverPriority.First;
/// <summary>
- /// Sets initial values on the newly resolved item
+ /// Sets initial values on the newly resolved item.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="args">The args.</param>
diff --git a/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs b/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
index 1030ed39d..99f304190 100644
--- a/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/SpecialFolderResolver.cs
@@ -41,10 +41,12 @@ namespace Emby.Server.Implementations.Library.Resolvers
{
return new AggregateFolder();
}
+
if (string.Equals(args.Path, _appPaths.DefaultUserViewsPath, StringComparison.OrdinalIgnoreCase))
{
- return new UserRootFolder(); //if we got here and still a root - must be user root
+ return new UserRootFolder(); // if we got here and still a root - must be user root
}
+
if (args.IsVf)
{
return new CollectionFolder
@@ -73,7 +75,6 @@ namespace Emby.Server.Implementations.Library.Resolvers
{
return false;
}
-
})
.Select(i => _fileSystem.GetFileNameWithoutExtension(i))
.FirstOrDefault();
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
index 7f477a0f0..2f7af60c0 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
@@ -55,6 +55,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
episode.SeriesId = series.Id;
episode.SeriesName = series.Name;
}
+
if (season != null)
{
episode.SeasonId = season.Id;
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
index 7f8800a64..c43a0ec6b 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
@@ -94,7 +94,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
_localization.GetLocalizedString("NameSeasonNumber"),
seasonNumber,
args.GetLibraryOptions().PreferredMetadataLanguage);
-
}
return season;
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
index 2f206f74c..732bfd94d 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs
@@ -59,7 +59,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
var collectionType = args.GetCollectionType();
if (string.Equals(collectionType, CollectionType.TvShows, StringComparison.OrdinalIgnoreCase))
{
- //if (args.ContainsFileSystemEntryByName("tvshow.nfo"))
+ // if (args.ContainsFileSystemEntryByName("tvshow.nfo"))
//{
// return new Series
// {
diff --git a/Emby.Server.Implementations/Library/SearchEngine.cs b/Emby.Server.Implementations/Library/SearchEngine.cs
index bde77ee8e..3df9cc06f 100644
--- a/Emby.Server.Implementations/Library/SearchEngine.cs
+++ b/Emby.Server.Implementations/Library/SearchEngine.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -12,6 +13,8 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Search;
using Microsoft.Extensions.Logging;
+using Genre = MediaBrowser.Controller.Entities.Genre;
+using Person = MediaBrowser.Controller.Entities.Person;
namespace Emby.Server.Implementations.Library
{
@@ -191,6 +194,7 @@ namespace Emby.Server.Implementations.Library
{
searchQuery.AncestorIds = new[] { searchQuery.ParentId };
}
+
searchQuery.ParentId = Guid.Empty;
searchQuery.IncludeItemsByName = true;
searchQuery.IncludeItemTypes = Array.Empty<string>();
@@ -204,7 +208,6 @@ namespace Emby.Server.Implementations.Library
return mediaItems.Select(i => new SearchHintInfo
{
Item = i
-
}).ToList();
}
}
diff --git a/Emby.Server.Implementations/Library/UserDataManager.cs b/Emby.Server.Implementations/Library/UserDataManager.cs
index a463d37f0..175b3af57 100644
--- a/Emby.Server.Implementations/Library/UserDataManager.cs
+++ b/Emby.Server.Implementations/Library/UserDataManager.cs
@@ -5,6 +5,7 @@ using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Threading;
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
@@ -13,6 +14,7 @@ using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using Microsoft.Extensions.Logging;
+using Book = MediaBrowser.Controller.Entities.Book;
namespace Emby.Server.Implementations.Library
{
@@ -101,7 +103,7 @@ namespace Emby.Server.Implementations.Library
}
/// <summary>
- /// Retrieve all user data for the given user
+ /// Retrieve all user data for the given user.
/// </summary>
/// <param name="userId"></param>
/// <returns></returns>
@@ -186,7 +188,7 @@ namespace Emby.Server.Implementations.Library
}
/// <summary>
- /// Converts a UserItemData to a DTOUserItemData
+ /// Converts a UserItemData to a DTOUserItemData.
/// </summary>
/// <param name="data">The data.</param>
/// <returns>DtoUserItemData.</returns>
diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs
deleted file mode 100644
index 531e00666..000000000
--- a/Emby.Server.Implementations/Library/UserManager.cs
+++ /dev/null
@@ -1,1107 +0,0 @@
-#pragma warning disable CS1591
-
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading;
-using System.Threading.Tasks;
-using MediaBrowser.Common.Cryptography;
-using MediaBrowser.Common.Events;
-using MediaBrowser.Common.Net;
-using MediaBrowser.Controller;
-using MediaBrowser.Controller.Authentication;
-using MediaBrowser.Controller.Devices;
-using MediaBrowser.Controller.Drawing;
-using MediaBrowser.Controller.Dto;
-using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Net;
-using MediaBrowser.Controller.Persistence;
-using MediaBrowser.Controller.Plugins;
-using MediaBrowser.Controller.Providers;
-using MediaBrowser.Controller.Security;
-using MediaBrowser.Controller.Session;
-using MediaBrowser.Model.Configuration;
-using MediaBrowser.Model.Cryptography;
-using MediaBrowser.Model.Dto;
-using MediaBrowser.Model.Entities;
-using MediaBrowser.Model.Events;
-using MediaBrowser.Model.IO;
-using MediaBrowser.Model.Serialization;
-using MediaBrowser.Model.Users;
-using Microsoft.Extensions.Logging;
-
-namespace Emby.Server.Implementations.Library
-{
- /// <summary>
- /// Class UserManager.
- /// </summary>
- public class UserManager : IUserManager
- {
- private readonly object _policySyncLock = new object();
- private readonly object _configSyncLock = new object();
-
- private readonly ILogger<UserManager> _logger;
- private readonly IUserRepository _userRepository;
- private readonly IXmlSerializer _xmlSerializer;
- private readonly IJsonSerializer _jsonSerializer;
- private readonly INetworkManager _networkManager;
- private readonly IImageProcessor _imageProcessor;
- private readonly Lazy<IDtoService> _dtoServiceFactory;
- private readonly IServerApplicationHost _appHost;
- private readonly IFileSystem _fileSystem;
- private readonly ICryptoProvider _cryptoProvider;
-
- private ConcurrentDictionary<Guid, User> _users;
-
- private IAuthenticationProvider[] _authenticationProviders;
- private DefaultAuthenticationProvider _defaultAuthenticationProvider;
-
- private InvalidAuthProvider _invalidAuthProvider;
-
- private IPasswordResetProvider[] _passwordResetProviders;
- private DefaultPasswordResetProvider _defaultPasswordResetProvider;
-
- private IDtoService DtoService => _dtoServiceFactory.Value;
-
- public UserManager(
- ILogger<UserManager> logger,
- IUserRepository userRepository,
- IXmlSerializer xmlSerializer,
- INetworkManager networkManager,
- IImageProcessor imageProcessor,
- Lazy<IDtoService> dtoServiceFactory,
- IServerApplicationHost appHost,
- IJsonSerializer jsonSerializer,
- IFileSystem fileSystem,
- ICryptoProvider cryptoProvider)
- {
- _logger = logger;
- _userRepository = userRepository;
- _xmlSerializer = xmlSerializer;
- _networkManager = networkManager;
- _imageProcessor = imageProcessor;
- _dtoServiceFactory = dtoServiceFactory;
- _appHost = appHost;
- _jsonSerializer = jsonSerializer;
- _fileSystem = fileSystem;
- _cryptoProvider = cryptoProvider;
- _users = null;
- }
-
- public event EventHandler<GenericEventArgs<User>> UserPasswordChanged;
-
- /// <summary>
- /// Occurs when [user updated].
- /// </summary>
- public event EventHandler<GenericEventArgs<User>> UserUpdated;
-
- public event EventHandler<GenericEventArgs<User>> UserPolicyUpdated;
-
- public event EventHandler<GenericEventArgs<User>> UserConfigurationUpdated;
-
- public event EventHandler<GenericEventArgs<User>> UserLockedOut;
-
- public event EventHandler<GenericEventArgs<User>> UserCreated;
-
- /// <summary>
- /// Occurs when [user deleted].
- /// </summary>
- public event EventHandler<GenericEventArgs<User>> UserDeleted;
-
- /// <inheritdoc />
- public IEnumerable<User> Users => _users.Values;
-
- /// <inheritdoc />
- public IEnumerable<Guid> UsersIds => _users.Keys;
-
- /// <summary>
- /// Called when [user updated].
- /// </summary>
- /// <param name="user">The user.</param>
- private void OnUserUpdated(User user)
- {
- UserUpdated?.Invoke(this, new GenericEventArgs<User>(user));
- }
-
- /// <summary>
- /// Called when [user deleted].
- /// </summary>
- /// <param name="user">The user.</param>
- private void OnUserDeleted(User user)
- {
- UserDeleted?.Invoke(this, new GenericEventArgs<User>(user));
- }
-
- public NameIdPair[] GetAuthenticationProviders()
- {
- return _authenticationProviders
- .Where(i => i.IsEnabled)
- .OrderBy(i => i is DefaultAuthenticationProvider ? 0 : 1)
- .ThenBy(i => i.Name)
- .Select(i => new NameIdPair
- {
- Name = i.Name,
- Id = GetAuthenticationProviderId(i)
- })
- .ToArray();
- }
-
- public NameIdPair[] GetPasswordResetProviders()
- {
- return _passwordResetProviders
- .Where(i => i.IsEnabled)
- .OrderBy(i => i is DefaultPasswordResetProvider ? 0 : 1)
- .ThenBy(i => i.Name)
- .Select(i => new NameIdPair
- {
- Name = i.Name,
- Id = GetPasswordResetProviderId(i)
- })
- .ToArray();
- }
-
- public void AddParts(IEnumerable<IAuthenticationProvider> authenticationProviders, IEnumerable<IPasswordResetProvider> passwordResetProviders)
- {
- _authenticationProviders = authenticationProviders.ToArray();
-
- _defaultAuthenticationProvider = _authenticationProviders.OfType<DefaultAuthenticationProvider>().First();
-
- _invalidAuthProvider = _authenticationProviders.OfType<InvalidAuthProvider>().First();
-
- _passwordResetProviders = passwordResetProviders.ToArray();
-
- _defaultPasswordResetProvider = passwordResetProviders.OfType<DefaultPasswordResetProvider>().First();
- }
-
- /// <inheritdoc />
- public User GetUserById(Guid id)
- {
- if (id == Guid.Empty)
- {
- throw new ArgumentException("Guid can't be empty", nameof(id));
- }
-
- _users.TryGetValue(id, out User user);
- return user;
- }
-
- public User GetUserByName(string name)
- {
- if (string.IsNullOrWhiteSpace(name))
- {
- throw new ArgumentException("Invalid username", nameof(name));
- }
-
- return Users.FirstOrDefault(u => string.Equals(u.Name, name, StringComparison.OrdinalIgnoreCase));
- }
-
- public void Initialize()
- {
- LoadUsers();
-
- var users = Users;
-
- // If there are no local users with admin rights, make them all admins
- if (!users.Any(i => i.Policy.IsAdministrator))
- {
- foreach (var user in users)
- {
- user.Policy.IsAdministrator = true;
- UpdateUserPolicy(user, user.Policy, false);
- }
- }
- }
-
- public static bool IsValidUsername(string username)
- {
- // This is some regex that matches only on unicode "word" characters, as well as -, _ and @
- // In theory this will cut out most if not all 'control' characters which should help minimize any weirdness
- // Usernames can contain letters (a-z + whatever else unicode is cool with), numbers (0-9), at-signs (@), dashes (-), underscores (_), apostrophes ('), and periods (.)
- return Regex.IsMatch(username, @"^[\w\-'._@]*$");
- }
-
- private static bool IsValidUsernameCharacter(char i)
- => IsValidUsername(i.ToString(CultureInfo.InvariantCulture));
-
- public string MakeValidUsername(string username)
- {
- if (IsValidUsername(username))
- {
- return username;
- }
-
- // Usernames can contain letters (a-z), numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)
- var builder = new StringBuilder();
-
- foreach (var c in username)
- {
- if (IsValidUsernameCharacter(c))
- {
- builder.Append(c);
- }
- }
-
- return builder.ToString();
- }
-
- public async Task<User> AuthenticateUser(
- string username,
- string password,
- string hashedPassword,
- string remoteEndPoint,
- bool isUserSession)
- {
- if (string.IsNullOrWhiteSpace(username))
- {
- _logger.LogInformation("Authentication request without username has been denied (IP: {IP}).", remoteEndPoint);
- throw new ArgumentNullException(nameof(username));
- }
-
- var user = Users.FirstOrDefault(i => string.Equals(username, i.Name, StringComparison.OrdinalIgnoreCase));
-
- var success = false;
- IAuthenticationProvider authenticationProvider = null;
-
- if (user != null)
- {
- var authResult = await AuthenticateLocalUser(username, password, hashedPassword, user, remoteEndPoint).ConfigureAwait(false);
- authenticationProvider = authResult.authenticationProvider;
- success = authResult.success;
- }
- else
- {
- // user is null
- var authResult = await AuthenticateLocalUser(username, password, hashedPassword, null, remoteEndPoint).ConfigureAwait(false);
- authenticationProvider = authResult.authenticationProvider;
- string updatedUsername = authResult.username;
- success = authResult.success;
-
- if (success
- && authenticationProvider != null
- && !(authenticationProvider is DefaultAuthenticationProvider))
- {
- // Trust the username returned by the authentication provider
- username = updatedUsername;
-
- // Search the database for the user again
- // the authentication provider might have created it
- user = Users
- .FirstOrDefault(i => string.Equals(username, i.Name, StringComparison.OrdinalIgnoreCase));
-
- if (authenticationProvider is IHasNewUserPolicy hasNewUserPolicy)
- {
- var policy = hasNewUserPolicy.GetNewUserPolicy();
- UpdateUserPolicy(user, policy, true);
- }
- }
- }
-
- if (success && user != null && authenticationProvider != null)
- {
- var providerId = GetAuthenticationProviderId(authenticationProvider);
-
- if (!string.Equals(providerId, user.Policy.AuthenticationProviderId, StringComparison.OrdinalIgnoreCase))
- {
- user.Policy.AuthenticationProviderId = providerId;
- UpdateUserPolicy(user, user.Policy, true);
- }
- }
-
- if (user == null)
- {
- _logger.LogInformation("Authentication request for {UserName} has been denied (IP: {IP}).", username, remoteEndPoint);
- throw new AuthenticationException("Invalid username or password entered.");
- }
-
- if (user.Policy.IsDisabled)
- {
- _logger.LogInformation("Authentication request for {UserName} has been denied because this account is currently disabled (IP: {IP}).", username, remoteEndPoint);
- throw new SecurityException($"The {user.Name} account is currently disabled. Please consult with your administrator.");
- }
-
- if (!user.Policy.EnableRemoteAccess && !_networkManager.IsInLocalNetwork(remoteEndPoint))
- {
- _logger.LogInformation("Authentication request for {UserName} forbidden: remote access disabled and user not in local network (IP: {IP}).", username, remoteEndPoint);
- throw new SecurityException("Forbidden.");
- }
-
- if (!user.IsParentalScheduleAllowed())
- {
- _logger.LogInformation("Authentication request for {UserName} is not allowed at this time due parental restrictions (IP: {IP}).", username, remoteEndPoint);
- throw new SecurityException("User is not allowed access at this time.");
- }
-
- // Update LastActivityDate and LastLoginDate, then save
- if (success)
- {
- if (isUserSession)
- {
- user.LastActivityDate = user.LastLoginDate = DateTime.UtcNow;
- UpdateUser(user);
- }
-
- ResetInvalidLoginAttemptCount(user);
- _logger.LogInformation("Authentication request for {UserName} has succeeded.", user.Name);
- }
- else
- {
- IncrementInvalidLoginAttemptCount(user);
- _logger.LogInformation("Authentication request for {UserName} has been denied (IP: {IP}).", user.Name, remoteEndPoint);
- }
-
- return success ? user : null;
- }
-
-#nullable enable
-
- private static string GetAuthenticationProviderId(IAuthenticationProvider provider)
- {
- return provider.GetType().FullName;
- }
-
- private static string GetPasswordResetProviderId(IPasswordResetProvider provider)
- {
- return provider.GetType().FullName;
- }
-
- private IAuthenticationProvider GetAuthenticationProvider(User user)
- {
- return GetAuthenticationProviders(user)[0];
- }
-
- private IPasswordResetProvider GetPasswordResetProvider(User user)
- {
- return GetPasswordResetProviders(user)[0];
- }
-
- private IAuthenticationProvider[] GetAuthenticationProviders(User? user)
- {
- var authenticationProviderId = user?.Policy.AuthenticationProviderId;
-
- var providers = _authenticationProviders.Where(i => i.IsEnabled).ToArray();
-
- if (!string.IsNullOrEmpty(authenticationProviderId))
- {
- providers = providers.Where(i => string.Equals(authenticationProviderId, GetAuthenticationProviderId(i), StringComparison.OrdinalIgnoreCase)).ToArray();
- }
-
- if (providers.Length == 0)
- {
- // Assign the user to the InvalidAuthProvider since no configured auth provider was valid/found
- _logger.LogWarning("User {UserName} was found with invalid/missing Authentication Provider {AuthenticationProviderId}. Assigning user to InvalidAuthProvider until this is corrected", user?.Name, user?.Policy.AuthenticationProviderId);
- providers = new IAuthenticationProvider[] { _invalidAuthProvider };
- }
-
- return providers;
- }
-
- private IPasswordResetProvider[] GetPasswordResetProviders(User? user)
- {
- var passwordResetProviderId = user?.Policy.PasswordResetProviderId;
-
- var providers = _passwordResetProviders.Where(i => i.IsEnabled).ToArray();
-
- if (!string.IsNullOrEmpty(passwordResetProviderId))
- {
- providers = providers.Where(i => string.Equals(passwordResetProviderId, GetPasswordResetProviderId(i), StringComparison.OrdinalIgnoreCase)).ToArray();
- }
-
- if (providers.Length == 0)
- {
- providers = new IPasswordResetProvider[] { _defaultPasswordResetProvider };
- }
-
- return providers;
- }
-
- private async Task<(string username, bool success)> AuthenticateWithProvider(
- IAuthenticationProvider provider,
- string username,
- string password,
- User? resolvedUser)
- {
- try
- {
- var authenticationResult = provider is IRequiresResolvedUser requiresResolvedUser
- ? await requiresResolvedUser.Authenticate(username, password, resolvedUser).ConfigureAwait(false)
- : await provider.Authenticate(username, password).ConfigureAwait(false);
-
- if (authenticationResult.Username != username)
- {
- _logger.LogDebug("Authentication provider provided updated username {1}", authenticationResult.Username);
- username = authenticationResult.Username;
- }
-
- return (username, true);
- }
- catch (AuthenticationException ex)
- {
- _logger.LogError(ex, "Error authenticating with provider {Provider}", provider.Name);
-
- return (username, false);
- }
- }
-
- private async Task<(IAuthenticationProvider? authenticationProvider, string username, bool success)> AuthenticateLocalUser(
- string username,
- string password,
- string hashedPassword,
- User? user,
- string remoteEndPoint)
- {
- bool success = false;
- IAuthenticationProvider? authenticationProvider = null;
-
- foreach (var provider in GetAuthenticationProviders(user))
- {
- var providerAuthResult = await AuthenticateWithProvider(provider, username, password, user).ConfigureAwait(false);
- var updatedUsername = providerAuthResult.username;
- success = providerAuthResult.success;
-
- if (success)
- {
- authenticationProvider = provider;
- username = updatedUsername;
- break;
- }
- }
-
- if (!success
- && _networkManager.IsInLocalNetwork(remoteEndPoint)
- && user?.Configuration.EnableLocalPassword == true
- && !string.IsNullOrEmpty(user.EasyPassword))
- {
- // Check easy password
- var passwordHash = PasswordHash.Parse(user.EasyPassword);
- var hash = _cryptoProvider.ComputeHash(
- passwordHash.Id,
- Encoding.UTF8.GetBytes(password),
- passwordHash.Salt.ToArray());
- success = passwordHash.Hash.SequenceEqual(hash);
- }
-
- return (authenticationProvider, username, success);
- }
-
- private void ResetInvalidLoginAttemptCount(User user)
- {
- user.Policy.InvalidLoginAttemptCount = 0;
- UpdateUserPolicy(user, user.Policy, false);
- }
-
- private void IncrementInvalidLoginAttemptCount(User user)
- {
- int invalidLogins = ++user.Policy.InvalidLoginAttemptCount;
- int maxInvalidLogins = user.Policy.LoginAttemptsBeforeLockout;
- if (maxInvalidLogins > 0
- && invalidLogins >= maxInvalidLogins)
- {
- user.Policy.IsDisabled = true;
- UserLockedOut?.Invoke(this, new GenericEventArgs<User>(user));
- _logger.LogWarning(
- "Disabling user {UserName} due to {Attempts} unsuccessful login attempts.",
- user.Name,
- invalidLogins);
- }
-
- UpdateUserPolicy(user, user.Policy, false);
- }
-
- /// <summary>
- /// Loads the users from the repository.
- /// </summary>
- private void LoadUsers()
- {
- var users = _userRepository.RetrieveAllUsers();
-
- // There always has to be at least one user.
- if (users.Count != 0)
- {
- _users = new ConcurrentDictionary<Guid, User>(
- users.Select(x => new KeyValuePair<Guid, User>(x.Id, x)));
- return;
- }
-
- var defaultName = Environment.UserName;
- if (string.IsNullOrWhiteSpace(defaultName))
- {
- defaultName = "MyJellyfinUser";
- }
-
- _logger.LogWarning("No users, creating one with username {UserName}", defaultName);
-
- var name = MakeValidUsername(defaultName);
-
- var user = InstantiateNewUser(name);
-
- user.DateLastSaved = DateTime.UtcNow;
-
- _userRepository.CreateUser(user);
-
- user.Policy.IsAdministrator = true;
- user.Policy.EnableContentDeletion = true;
- user.Policy.EnableRemoteControlOfOtherUsers = true;
- UpdateUserPolicy(user, user.Policy, false);
-
- _users = new ConcurrentDictionary<Guid, User>();
- _users[user.Id] = user;
- }
-
-#nullable restore
-
- public UserDto GetUserDto(User user, string remoteEndPoint = null)
- {
- if (user == null)
- {
- throw new ArgumentNullException(nameof(user));
- }
-
- bool hasConfiguredPassword = GetAuthenticationProvider(user).HasPassword(user);
- bool hasConfiguredEasyPassword = !string.IsNullOrEmpty(GetAuthenticationProvider(user).GetEasyPasswordHash(user));
-
- bool hasPassword = user.Configuration.EnableLocalPassword && !string.IsNullOrEmpty(remoteEndPoint) && _networkManager.IsInLocalNetwork(remoteEndPoint) ?
- hasConfiguredEasyPassword :
- hasConfiguredPassword;
-
- UserDto dto = new UserDto
- {
- Id = user.Id,
- Name = user.Name,
- HasPassword = hasPassword,
- HasConfiguredPassword = hasConfiguredPassword,
- HasConfiguredEasyPassword = hasConfiguredEasyPassword,
- LastActivityDate = user.LastActivityDate,
- LastLoginDate = user.LastLoginDate,
- Configuration = user.Configuration,
- ServerId = _appHost.SystemId,
- Policy = user.Policy
- };
-
- if (!hasPassword && _users.Count == 1)
- {
- dto.EnableAutoLogin = true;
- }
-
- ItemImageInfo image = user.GetImageInfo(ImageType.Primary, 0);
-
- if (image != null)
- {
- dto.PrimaryImageTag = GetImageCacheTag(user, image);
-
- try
- {
- DtoService.AttachPrimaryImageAspectRatio(dto, user);
- }
- catch (Exception ex)
- {
- // Have to use a catch-all unfortunately because some .net image methods throw plain Exceptions
- _logger.LogError(ex, "Error generating PrimaryImageAspectRatio for {User}", user.Name);
- }
- }
-
- return dto;
- }
-
- public UserDto GetOfflineUserDto(User user)
- {
- var dto = GetUserDto(user);
-
- dto.ServerName = _appHost.FriendlyName;
-
- return dto;
- }
-
- private string GetImageCacheTag(BaseItem item, ItemImageInfo image)
- {
- try
- {
- return _imageProcessor.GetImageCacheTag(item, image);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error getting {ImageType} image info for {ImagePath}", image.Type, image.Path);
- return null;
- }
- }
-
- /// <summary>
- /// Refreshes metadata for each user
- /// </summary>
- /// <param name="cancellationToken">The cancellation token.</param>
- /// <returns>Task.</returns>
- public async Task RefreshUsersMetadata(CancellationToken cancellationToken)
- {
- foreach (var user in Users)
- {
- await user.RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(_fileSystem)), cancellationToken).ConfigureAwait(false);
- }
- }
-
- /// <summary>
- /// Renames the user.
- /// </summary>
- /// <param name="user">The user.</param>
- /// <param name="newName">The new name.</param>
- /// <returns>Task.</returns>
- /// <exception cref="ArgumentNullException">user</exception>
- /// <exception cref="ArgumentException"></exception>
- public async Task RenameUser(User user, string newName)
- {
- if (user == null)
- {
- throw new ArgumentNullException(nameof(user));
- }
-
- if (string.IsNullOrWhiteSpace(newName))
- {
- throw new ArgumentException("Invalid username", nameof(newName));
- }
-
- if (user.Name.Equals(newName, StringComparison.Ordinal))
- {
- throw new ArgumentException("The new and old names must be different.");
- }
-
- if (Users.Any(
- u => u.Id != user.Id && u.Name.Equals(newName, StringComparison.OrdinalIgnoreCase)))
- {
- throw new ArgumentException(string.Format(
- CultureInfo.InvariantCulture,
- "A user with the name '{0}' already exists.",
- newName));
- }
-
- await user.Rename(newName).ConfigureAwait(false);
-
- OnUserUpdated(user);
- }
-
- /// <summary>
- /// Updates the user.
- /// </summary>
- /// <param name="user">The user.</param>
- /// <exception cref="ArgumentNullException">user</exception>
- /// <exception cref="ArgumentException"></exception>
- public void UpdateUser(User user)
- {
- if (user == null)
- {
- throw new ArgumentNullException(nameof(user));
- }
-
- if (user.Id == Guid.Empty)
- {
- throw new ArgumentException("Id can't be empty.", nameof(user));
- }
-
- if (!_users.ContainsKey(user.Id))
- {
- throw new ArgumentException(
- string.Format(
- CultureInfo.InvariantCulture,
- "A user '{0}' with Id {1} does not exist.",
- user.Name,
- user.Id),
- nameof(user));
- }
-
- user.DateModified = DateTime.UtcNow;
- user.DateLastSaved = DateTime.UtcNow;
-
- _userRepository.UpdateUser(user);
-
- OnUserUpdated(user);
- }
-
- /// <summary>
- /// Creates the user.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>User.</returns>
- /// <exception cref="ArgumentNullException">name</exception>
- /// <exception cref="ArgumentException"></exception>
- public User CreateUser(string name)
- {
- if (string.IsNullOrWhiteSpace(name))
- {
- throw new ArgumentNullException(nameof(name));
- }
-
- if (!IsValidUsername(name))
- {
- throw new ArgumentException("Usernames can contain unicode symbols, numbers (0-9), dashes (-), underscores (_), apostrophes ('), and periods (.)");
- }
-
- if (Users.Any(u => u.Name.Equals(name, StringComparison.OrdinalIgnoreCase)))
- {
- throw new ArgumentException(string.Format("A user with the name '{0}' already exists.", name));
- }
-
- var user = InstantiateNewUser(name);
-
- _users[user.Id] = user;
-
- user.DateLastSaved = DateTime.UtcNow;
-
- _userRepository.CreateUser(user);
-
- EventHelper.QueueEventIfNotNull(UserCreated, this, new GenericEventArgs<User>(user), _logger);
-
- return user;
- }
-
- /// <inheritdoc />
- /// <exception cref="ArgumentNullException">The <c>user</c> is <c>null</c>.</exception>
- /// <exception cref="ArgumentException">The <c>user</c> doesn't exist, or is the last administrator.</exception>
- /// <exception cref="InvalidOperationException">The <c>user</c> can't be deleted; there are no other users.</exception>
- public void DeleteUser(User user)
- {
- if (user == null)
- {
- throw new ArgumentNullException(nameof(user));
- }
-
- if (!_users.ContainsKey(user.Id))
- {
- throw new ArgumentException(string.Format(
- CultureInfo.InvariantCulture,
- "The user cannot be deleted because there is no user with the Name {0} and Id {1}.",
- user.Name,
- user.Id));
- }
-
- if (_users.Count == 1)
- {
- throw new InvalidOperationException(string.Format(
- CultureInfo.InvariantCulture,
- "The user '{0}' cannot be deleted because there must be at least one user in the system.",
- user.Name));
- }
-
- if (user.Policy.IsAdministrator
- && Users.Count(i => i.Policy.IsAdministrator) == 1)
- {
- throw new ArgumentException(
- string.Format(
- CultureInfo.InvariantCulture,
- "The user '{0}' cannot be deleted because there must be at least one admin user in the system.",
- user.Name),
- nameof(user));
- }
-
- var configPath = GetConfigurationFilePath(user);
-
- _userRepository.DeleteUser(user);
-
- // Delete user config dir
- lock (_configSyncLock)
- lock (_policySyncLock)
- {
- try
- {
- Directory.Delete(user.ConfigurationDirectoryPath, true);
- }
- catch (IOException ex)
- {
- _logger.LogError(ex, "Error deleting user config dir: {Path}", user.ConfigurationDirectoryPath);
- }
- }
-
- _users.TryRemove(user.Id, out _);
-
- OnUserDeleted(user);
- }
-
- /// <summary>
- /// Resets the password by clearing it.
- /// </summary>
- /// <returns>Task.</returns>
- public Task ResetPassword(User user)
- {
- return ChangePassword(user, string.Empty);
- }
-
- public void ResetEasyPassword(User user)
- {
- ChangeEasyPassword(user, string.Empty, null);
- }
-
- public async Task ChangePassword(User user, string newPassword)
- {
- if (user == null)
- {
- throw new ArgumentNullException(nameof(user));
- }
-
- await GetAuthenticationProvider(user).ChangePassword(user, newPassword).ConfigureAwait(false);
-
- UpdateUser(user);
-
- UserPasswordChanged?.Invoke(this, new GenericEventArgs<User>(user));
- }
-
- public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash)
- {
- if (user == null)
- {
- throw new ArgumentNullException(nameof(user));
- }
-
- GetAuthenticationProvider(user).ChangeEasyPassword(user, newPassword, newPasswordHash);
-
- UpdateUser(user);
-
- UserPasswordChanged?.Invoke(this, new GenericEventArgs<User>(user));
- }
-
- /// <summary>
- /// Instantiates the new user.
- /// </summary>
- /// <param name="name">The name.</param>
- /// <returns>User.</returns>
- private static User InstantiateNewUser(string name)
- {
- return new User
- {
- Name = name,
- Id = Guid.NewGuid(),
- DateCreated = DateTime.UtcNow,
- DateModified = DateTime.UtcNow
- };
- }
-
- public async Task<ForgotPasswordResult> StartForgotPasswordProcess(string enteredUsername, bool isInNetwork)
- {
- var user = string.IsNullOrWhiteSpace(enteredUsername) ?
- null :
- GetUserByName(enteredUsername);
-
- var action = ForgotPasswordAction.InNetworkRequired;
-
- if (user != null && isInNetwork)
- {
- var passwordResetProvider = GetPasswordResetProvider(user);
- return await passwordResetProvider.StartForgotPasswordProcess(user, isInNetwork).ConfigureAwait(false);
- }
- else
- {
- return new ForgotPasswordResult
- {
- Action = action,
- PinFile = string.Empty
- };
- }
- }
-
- public async Task<PinRedeemResult> RedeemPasswordResetPin(string pin)
- {
- foreach (var provider in _passwordResetProviders)
- {
- var result = await provider.RedeemPasswordResetPin(pin).ConfigureAwait(false);
- if (result.Success)
- {
- return result;
- }
- }
-
- return new PinRedeemResult
- {
- Success = false,
- UsersReset = Array.Empty<string>()
- };
- }
-
- public UserPolicy GetUserPolicy(User user)
- {
- var path = GetPolicyFilePath(user);
- if (!File.Exists(path))
- {
- return GetDefaultPolicy();
- }
-
- try
- {
- lock (_policySyncLock)
- {
- return (UserPolicy)_xmlSerializer.DeserializeFromFile(typeof(UserPolicy), path);
- }
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error reading policy file: {Path}", path);
-
- return GetDefaultPolicy();
- }
- }
-
- private static UserPolicy GetDefaultPolicy()
- {
- return new UserPolicy
- {
- EnableContentDownloading = true,
- EnableSyncTranscoding = true
- };
- }
-
- public void UpdateUserPolicy(Guid userId, UserPolicy userPolicy)
- {
- var user = GetUserById(userId);
- UpdateUserPolicy(user, userPolicy, true);
- }
-
- private void UpdateUserPolicy(User user, UserPolicy userPolicy, bool fireEvent)
- {
- // The xml serializer will output differently if the type is not exact
- if (userPolicy.GetType() != typeof(UserPolicy))
- {
- var json = _jsonSerializer.SerializeToString(userPolicy);
- userPolicy = _jsonSerializer.DeserializeFromString<UserPolicy>(json);
- }
-
- var path = GetPolicyFilePath(user);
-
- Directory.CreateDirectory(Path.GetDirectoryName(path));
-
- lock (_policySyncLock)
- {
- _xmlSerializer.SerializeToFile(userPolicy, path);
- user.Policy = userPolicy;
- }
-
- if (fireEvent)
- {
- UserPolicyUpdated?.Invoke(this, new GenericEventArgs<User>(user));
- }
- }
-
- private static string GetPolicyFilePath(User user)
- {
- return Path.Combine(user.ConfigurationDirectoryPath, "policy.xml");
- }
-
- private static string GetConfigurationFilePath(User user)
- {
- return Path.Combine(user.ConfigurationDirectoryPath, "config.xml");
- }
-
- public UserConfiguration GetUserConfiguration(User user)
- {
- var path = GetConfigurationFilePath(user);
-
- if (!File.Exists(path))
- {
- return new UserConfiguration();
- }
-
- try
- {
- lock (_configSyncLock)
- {
- return (UserConfiguration)_xmlSerializer.DeserializeFromFile(typeof(UserConfiguration), path);
- }
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error reading policy file: {Path}", path);
-
- return new UserConfiguration();
- }
- }
-
- public void UpdateConfiguration(Guid userId, UserConfiguration config)
- {
- var user = GetUserById(userId);
- UpdateConfiguration(user, config);
- }
-
- public void UpdateConfiguration(User user, UserConfiguration config)
- {
- UpdateConfiguration(user, config, true);
- }
-
- private void UpdateConfiguration(User user, UserConfiguration config, bool fireEvent)
- {
- var path = GetConfigurationFilePath(user);
-
- // The xml serializer will output differently if the type is not exact
- if (config.GetType() != typeof(UserConfiguration))
- {
- var json = _jsonSerializer.SerializeToString(config);
- config = _jsonSerializer.DeserializeFromString<UserConfiguration>(json);
- }
-
- Directory.CreateDirectory(Path.GetDirectoryName(path));
-
- lock (_configSyncLock)
- {
- _xmlSerializer.SerializeToFile(config, path);
- user.Configuration = config;
- }
-
- if (fireEvent)
- {
- UserConfigurationUpdated?.Invoke(this, new GenericEventArgs<User>(user));
- }
- }
- }
-
- public class DeviceAccessEntryPoint : IServerEntryPoint
- {
- private IUserManager _userManager;
- private IAuthenticationRepository _authRepo;
- private IDeviceManager _deviceManager;
- private ISessionManager _sessionManager;
-
- public DeviceAccessEntryPoint(IUserManager userManager, IAuthenticationRepository authRepo, IDeviceManager deviceManager, ISessionManager sessionManager)
- {
- _userManager = userManager;
- _authRepo = authRepo;
- _deviceManager = deviceManager;
- _sessionManager = sessionManager;
- }
-
- public Task RunAsync()
- {
- _userManager.UserPolicyUpdated += _userManager_UserPolicyUpdated;
-
- return Task.CompletedTask;
- }
-
- private void _userManager_UserPolicyUpdated(object sender, GenericEventArgs<User> e)
- {
- var user = e.Argument;
- if (!user.Policy.EnableAllDevices)
- {
- UpdateDeviceAccess(user);
- }
- }
-
- private void UpdateDeviceAccess(User user)
- {
- var existing = _authRepo.Get(new AuthenticationInfoQuery
- {
- UserId = user.Id
-
- }).Items;
-
- foreach (var authInfo in existing)
- {
- if (!string.IsNullOrEmpty(authInfo.DeviceId) && !_deviceManager.CanAccessDevice(user, authInfo.DeviceId))
- {
- _sessionManager.Logout(authInfo);
- }
- }
- }
-
- public void Dispose()
- {
-
- }
- }
-}
diff --git a/Emby.Server.Implementations/Library/UserViewManager.cs b/Emby.Server.Implementations/Library/UserViewManager.cs
index 322819b05..f51657c63 100644
--- a/Emby.Server.Implementations/Library/UserViewManager.cs
+++ b/Emby.Server.Implementations/Library/UserViewManager.cs
@@ -5,6 +5,8 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
+using Jellyfin.Data.Entities;
+using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
@@ -17,6 +19,8 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Globalization;
using MediaBrowser.Model.Library;
using MediaBrowser.Model.Querying;
+using Genre = MediaBrowser.Controller.Entities.Genre;
+using Person = MediaBrowser.Controller.Entities.Person;
namespace Emby.Server.Implementations.Library
{
@@ -125,12 +129,12 @@ namespace Emby.Server.Implementations.Library
if (!query.IncludeHidden)
{
- list = list.Where(i => !user.Configuration.MyMediaExcludes.Contains(i.Id.ToString("N", CultureInfo.InvariantCulture))).ToList();
+ list = list.Where(i => !user.GetPreference(PreferenceKind.MyMediaExcludes).Contains(i.Id.ToString("N", CultureInfo.InvariantCulture))).ToList();
}
var sorted = _libraryManager.Sort(list, user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).ToList();
- var orders = user.Configuration.OrderedViews.ToList();
+ var orders = user.GetPreference(PreferenceKind.OrderedViews).ToList();
return list
.OrderBy(i =>
@@ -165,7 +169,13 @@ namespace Emby.Server.Implementations.Library
return GetUserSubViewWithName(name, parentId, type, sortName);
}
- private Folder GetUserView(List<ICollectionFolder> parents, string viewType, string localizationKey, string sortName, User user, string[] presetViews)
+ private Folder GetUserView(
+ List<ICollectionFolder> parents,
+ string viewType,
+ string localizationKey,
+ string sortName,
+ Jellyfin.Data.Entities.User user,
+ string[] presetViews)
{
if (parents.Count == 1 && parents.All(i => string.Equals(i.CollectionType, viewType, StringComparison.OrdinalIgnoreCase)))
{
@@ -270,7 +280,8 @@ namespace Emby.Server.Implementations.Library
{
parents = _libraryManager.GetUserRootFolder().GetChildren(user, true)
.Where(i => i is Folder)
- .Where(i => !user.Configuration.LatestItemsExcludes.Contains(i.Id.ToString("N", CultureInfo.InvariantCulture)))
+ .Where(i => !user.GetPreference(PreferenceKind.LatestItemExcludes)
+ .Contains(i.Id.ToString("N", CultureInfo.InvariantCulture)))
.ToList();
}
@@ -331,12 +342,11 @@ namespace Emby.Server.Implementations.Library
var excludeItemTypes = includeItemTypes.Length == 0 && mediaTypes.Count == 0 ? new[]
{
- typeof(Person).Name,
- typeof(Studio).Name,
- typeof(Year).Name,
- typeof(MusicGenre).Name,
- typeof(Genre).Name
-
+ nameof(Person),
+ nameof(Studio),
+ nameof(Year),
+ nameof(MusicGenre),
+ nameof(Genre)
} : Array.Empty<string>();
var query = new InternalItemsQuery(user)
diff --git a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs
index 8a6bd5e78..d4c8c35e6 100644
--- a/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs
+++ b/Emby.Server.Implementations/Library/Validators/ArtistsValidator.cs
@@ -98,7 +98,6 @@ namespace Emby.Server.Implementations.Library.Validators
_libraryManager.DeleteItem(item, new DeleteOptions
{
DeleteFileLocation = false
-
}, false);
}
diff --git a/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs b/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs
index 7a6cd11df..ca35adfff 100644
--- a/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs
+++ b/Emby.Server.Implementations/Library/Validators/StudiosValidator.cs
@@ -92,7 +92,6 @@ namespace Emby.Server.Implementations.Library.Validators
_libraryManager.DeleteItem(item, new DeleteOptions
{
DeleteFileLocation = false
-
}, false);
}
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
index 9fb5aec29..7b0fcbc9e 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EmbyTV.cs
@@ -1547,7 +1547,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
IsFolder = false,
Recursive = true,
DtoOptions = new DtoOptions(true)
-
})
.Where(i => i.IsFileProtocol && File.Exists(i.Path))
.Skip(seriesTimer.KeepUpTo - 1)
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
index 70dd8f321..d8ec107ec 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/EncodedRecorder.cs
@@ -183,7 +183,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
var subtitleArgs = CopySubtitles ? " -codec:s copy" : " -sn";
- //var outputParam = string.Equals(Path.GetExtension(targetFile), ".mp4", StringComparison.OrdinalIgnoreCase) ?
+ // var outputParam = string.Equals(Path.GetExtension(targetFile), ".mp4", StringComparison.OrdinalIgnoreCase) ?
// " -f mp4 -movflags frag_keyframe+empty_moov" :
// string.Empty;
@@ -206,13 +206,13 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
{
return "-codec:a:0 copy";
- //var audioChannels = 2;
- //var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
- //if (audioStream != null)
+ // var audioChannels = 2;
+ // var audioStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Audio);
+ // if (audioStream != null)
//{
// audioChannels = audioStream.Channels ?? audioChannels;
//}
- //return "-codec:a:0 aac -strict experimental -ab 320000";
+ // return "-codec:a:0 aac -strict experimental -ab 320000";
}
private static bool EncodeVideo(MediaSourceInfo mediaSource)
diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
index 0b0ff6cb3..142c59542 100644
--- a/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
+++ b/Emby.Server.Implementations/LiveTv/EmbyTV/RecordingHelper.cs
@@ -56,7 +56,6 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV
name += " " + info.EpisodeTitle;
}
}
-
else if (info.IsMovie && info.ProductionYear != null)
{
name += " (" + info.ProductionYear + ")";
diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
index a65b3ee03..3709f8fe4 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs
@@ -145,7 +145,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
var programsInfo = new List<ProgramInfo>();
foreach (ScheduleDirect.Program schedule in dailySchedules.SelectMany(d => d.programs))
{
- //_logger.LogDebug("Proccesing Schedule for statio ID " + stationID +
+ // _logger.LogDebug("Proccesing Schedule for statio ID " + stationID +
// " which corresponds to channel " + channelNumber + " and program id " +
// schedule.programID + " which says it has images? " +
// programDict[schedule.programID].hasImageArtwork);
@@ -178,7 +178,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
programEntry.backdropImage = GetProgramImage(ApiUrl, imagesWithoutText, true, WideAspect);
- //programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
+ // programEntry.bannerImage = GetProgramImage(ApiUrl, data, "Banner", false) ??
// GetProgramImage(ApiUrl, data, "Banner-L1", false) ??
// GetProgramImage(ApiUrl, data, "Banner-LO", false) ??
// GetProgramImage(ApiUrl, data, "Banner-LOT", false);
@@ -212,6 +212,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
channelNumber = map.channel;
}
+
if (string.IsNullOrWhiteSpace(channelNumber))
{
channelNumber = map.atscMajor + "." + map.atscMinor;
@@ -276,7 +277,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
CommunityRating = null,
EpisodeTitle = episodeTitle,
Audio = audioType,
- //IsNew = programInfo.@new ?? false,
+ // IsNew = programInfo.@new ?? false,
IsRepeat = programInfo.@new == null,
IsSeries = string.Equals(details.entityType, "episode", StringComparison.OrdinalIgnoreCase),
ImageUrl = details.primaryImage,
@@ -400,6 +401,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
date = DateTime.SpecifyKind(date, DateTimeKind.Utc);
}
+
return date;
}
@@ -622,6 +624,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
_lastErrorResponse = DateTime.UtcNow;
}
}
+
throw;
}
finally
@@ -701,7 +704,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
CancellationToken = cancellationToken,
LogErrorResponseBody = true
};
- //_logger.LogInformation("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " +
+ // _logger.LogInformation("Obtaining token from Schedules Direct from addres: " + httpOptions.Url + " with body " +
// httpOptions.RequestContent);
using (var response = await Post(httpOptions, false, null).ConfigureAwait(false))
@@ -805,11 +808,13 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
throw new ArgumentException("Username is required");
}
+
if (string.IsNullOrEmpty(info.Password))
{
throw new ArgumentException("Password is required");
}
}
+
if (validateListings)
{
if (string.IsNullOrEmpty(info.ListingsId))
@@ -932,24 +937,35 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class Token
{
public int code { get; set; }
+
public string message { get; set; }
+
public string serverID { get; set; }
+
public string token { get; set; }
}
+
public class Lineup
{
public string lineup { get; set; }
+
public string name { get; set; }
+
public string transport { get; set; }
+
public string location { get; set; }
+
public string uri { get; set; }
}
public class Lineups
{
public int code { get; set; }
+
public string serverID { get; set; }
+
public string datetime { get; set; }
+
public List<Lineup> lineups { get; set; }
}
@@ -957,8 +973,11 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class Headends
{
public string headend { get; set; }
+
public string transport { get; set; }
+
public string location { get; set; }
+
public List<Lineup> lineups { get; set; }
}
@@ -967,59 +986,83 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class Map
{
public string stationID { get; set; }
+
public string channel { get; set; }
+
public string logicalChannelNumber { get; set; }
+
public int uhfVhf { get; set; }
+
public int atscMajor { get; set; }
+
public int atscMinor { get; set; }
}
public class Broadcaster
{
public string city { get; set; }
+
public string state { get; set; }
+
public string postalcode { get; set; }
+
public string country { get; set; }
}
public class Logo
{
public string URL { get; set; }
+
public int height { get; set; }
+
public int width { get; set; }
+
public string md5 { get; set; }
}
public class Station
{
public string stationID { get; set; }
+
public string name { get; set; }
+
public string callsign { get; set; }
+
public List<string> broadcastLanguage { get; set; }
+
public List<string> descriptionLanguage { get; set; }
+
public Broadcaster broadcaster { get; set; }
+
public string affiliate { get; set; }
+
public Logo logo { get; set; }
+
public bool? isCommercialFree { get; set; }
}
public class Metadata
{
public string lineup { get; set; }
+
public string modified { get; set; }
+
public string transport { get; set; }
}
public class Channel
{
public List<Map> map { get; set; }
+
public List<Station> stations { get; set; }
+
public Metadata metadata { get; set; }
}
public class RequestScheduleForChannel
{
public string stationID { get; set; }
+
public List<string> date { get; set; }
}
@@ -1029,29 +1072,43 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class Rating
{
public string body { get; set; }
+
public string code { get; set; }
}
public class Multipart
{
public int partNumber { get; set; }
+
public int totalParts { get; set; }
}
public class Program
{
public string programID { get; set; }
+
public string airDateTime { get; set; }
+
public int duration { get; set; }
+
public string md5 { get; set; }
+
public List<string> audioProperties { get; set; }
+
public List<string> videoProperties { get; set; }
+
public List<Rating> ratings { get; set; }
+
public bool? @new { get; set; }
+
public Multipart multipart { get; set; }
+
public string liveTapeDelay { get; set; }
+
public bool premiere { get; set; }
+
public bool repeat { get; set; }
+
public string isPremiereOrFinale { get; set; }
}
@@ -1060,16 +1117,22 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class MetadataSchedule
{
public string modified { get; set; }
+
public string md5 { get; set; }
+
public string startDate { get; set; }
+
public string endDate { get; set; }
+
public int days { get; set; }
}
public class Day
{
public string stationID { get; set; }
+
public List<Program> programs { get; set; }
+
public MetadataSchedule metadata { get; set; }
public Day()
@@ -1092,24 +1155,28 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class Description100
{
public string descriptionLanguage { get; set; }
+
public string description { get; set; }
}
public class Description1000
{
public string descriptionLanguage { get; set; }
+
public string description { get; set; }
}
public class DescriptionsProgram
{
public List<Description100> description100 { get; set; }
+
public List<Description1000> description1000 { get; set; }
}
public class Gracenote
{
public int season { get; set; }
+
public int episode { get; set; }
}
@@ -1121,104 +1188,154 @@ namespace Emby.Server.Implementations.LiveTv.Listings
public class ContentRating
{
public string body { get; set; }
+
public string code { get; set; }
}
public class Cast
{
public string billingOrder { get; set; }
+
public string role { get; set; }
+
public string nameId { get; set; }
+
public string personId { get; set; }
+
public string name { get; set; }
+
public string characterName { get; set; }
}
public class Crew
{
public string billingOrder { get; set; }
+
public string role { get; set; }
+
public string nameId { get; set; }
+
public string personId { get; set; }
+
public string name { get; set; }
}
public class QualityRating
{
public string ratingsBody { get; set; }
+
public string rating { get; set; }
+
public string minRating { get; set; }
+
public string maxRating { get; set; }
+
public string increment { get; set; }
}
public class Movie
{
public string year { get; set; }
+
public int duration { get; set; }
+
public List<QualityRating> qualityRating { get; set; }
}
public class Recommendation
{
public string programID { get; set; }
+
public string title120 { get; set; }
}
public class ProgramDetails
{
public string audience { get; set; }
+
public string programID { get; set; }
+
public List<Title> titles { get; set; }
+
public EventDetails eventDetails { get; set; }
+
public DescriptionsProgram descriptions { get; set; }
+
public string originalAirDate { get; set; }
+
public List<string> genres { get; set; }
+
public string episodeTitle150 { get; set; }
+
public List<MetadataPrograms> metadata { get; set; }
+
public List<ContentRating> contentRating { get; set; }
+
public List<Cast> cast { get; set; }
+
public List<Crew> crew { get; set; }
+
public string entityType { get; set; }
+
public string showType { get; set; }
+
public bool hasImageArtwork { get; set; }
+
public string primaryImage { get; set; }
+
public string thumbImage { get; set; }
+
public string backdropImage { get; set; }
+
public string bannerImage { get; set; }
+
public string imageID { get; set; }
+
public string md5 { get; set; }
+
public List<string> contentAdvisory { get; set; }
+
public Movie movie { get; set; }
+
public List<Recommendation> recommendations { get; set; }
}
public class Caption
{
public string content { get; set; }
+
public string lang { get; set; }
}
public class ImageData
{
public string width { get; set; }
+
public string height { get; set; }
+
public string uri { get; set; }
+
public string size { get; set; }
+
public string aspect { get; set; }
+
public string category { get; set; }
+
public string text { get; set; }
+
public string primary { get; set; }
+
public string tier { get; set; }
+
public Caption caption { get; set; }
}
public class ShowImages
{
public string programID { get; set; }
+
public List<ImageData> data { get; set; }
}
-
}
}
}
diff --git a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
index 077b5c7e5..0a93c4674 100644
--- a/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
+++ b/Emby.Server.Implementations/LiveTv/Listings/XmlTvListingsProvider.cs
@@ -224,6 +224,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings
{
uniqueString = "-" + programInfo.SeasonNumber.Value.ToString(CultureInfo.InvariantCulture);
}
+
if (programInfo.EpisodeNumber.HasValue)
{
uniqueString = "-" + programInfo.EpisodeNumber.Value.ToString(CultureInfo.InvariantCulture);
diff --git a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
index a88e0f31f..4c1de3bcc 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -7,6 +7,8 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.Library;
+using Jellyfin.Data.Entities;
+using Jellyfin.Data.Enums;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Progress;
@@ -14,8 +16,6 @@ using MediaBrowser.Controller.Channels;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.Movies;
-using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.LiveTv;
using MediaBrowser.Controller.Persistence;
@@ -31,6 +31,8 @@ using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Tasks;
using Microsoft.Extensions.Logging;
+using Episode = MediaBrowser.Controller.Entities.TV.Episode;
+using Movie = MediaBrowser.Controller.Entities.Movies.Movie;
namespace Emby.Server.Implementations.LiveTv
{
@@ -404,8 +406,8 @@ namespace Emby.Server.Implementations.LiveTv
if (!(service is EmbyTV.EmbyTV))
{
// We can't trust that we'll be able to direct stream it through emby server, no matter what the provider says
- //mediaSource.SupportsDirectPlay = false;
- //mediaSource.SupportsDirectStream = false;
+ // mediaSource.SupportsDirectPlay = false;
+ // mediaSource.SupportsDirectStream = false;
mediaSource.SupportsTranscoding = true;
foreach (var stream in mediaSource.MediaStreams)
{
@@ -554,9 +556,10 @@ namespace Emby.Server.Implementations.LiveTv
{
forceUpdate = true;
}
+
item.ParentId = channel.Id;
- //item.ChannelType = channelType;
+ // item.ChannelType = channelType;
item.Audio = info.Audio;
item.ChannelId = channel.Id;
@@ -573,6 +576,7 @@ namespace Emby.Server.Implementations.LiveTv
{
forceUpdate = true;
}
+
item.ExternalSeriesId = seriesId;
var isSeries = info.IsSeries || !string.IsNullOrEmpty(info.EpisodeTitle);
@@ -587,30 +591,37 @@ namespace Emby.Server.Implementations.LiveTv
{
tags.Add("Live");
}
+
if (info.IsPremiere)
{
tags.Add("Premiere");
}
+
if (info.IsNews)
{
tags.Add("News");
}
+
if (info.IsSports)
{
tags.Add("Sports");
}
+
if (info.IsKids)
{
tags.Add("Kids");
}
+
if (info.IsRepeat)
{
tags.Add("Repeat");
}
+
if (info.IsMovie)
{
tags.Add("Movie");
}
+
if (isSeries)
{
tags.Add("Series");
@@ -633,6 +644,7 @@ namespace Emby.Server.Implementations.LiveTv
{
forceUpdate = true;
}
+
item.IsSeries = isSeries;
item.Name = info.Name;
@@ -650,12 +662,14 @@ namespace Emby.Server.Implementations.LiveTv
{
forceUpdate = true;
}
+
item.StartDate = info.StartDate;
if (item.EndDate != info.EndDate)
{
forceUpdate = true;
}
+
item.EndDate = info.EndDate;
item.ProductionYear = info.ProductionYear;
@@ -696,7 +710,6 @@ namespace Emby.Server.Implementations.LiveTv
{
Path = info.ThumbImageUrl,
Type = ImageType.Thumb
-
}, 0);
}
}
@@ -709,7 +722,6 @@ namespace Emby.Server.Implementations.LiveTv
{
Path = info.LogoImageUrl,
Type = ImageType.Logo
-
}, 0);
}
}
@@ -722,7 +734,6 @@ namespace Emby.Server.Implementations.LiveTv
{
Path = info.BackdropImageUrl,
Type = ImageType.Backdrop
-
}, 0);
}
}
@@ -760,7 +771,8 @@ namespace Emby.Server.Implementations.LiveTv
var dto = _dtoService.GetBaseItemDto(program, new DtoOptions(), user);
- var list = new List<Tuple<BaseItemDto, string, string>>() {
+ var list = new List<Tuple<BaseItemDto, string, string>>
+ {
new Tuple<BaseItemDto, string, string>(dto, program.ExternalId, program.ExternalSeriesId)
};
@@ -1168,7 +1180,6 @@ namespace Emby.Server.Implementations.LiveTv
IncludeItemTypes = new string[] { typeof(LiveTvProgram).Name },
ChannelIds = new Guid[] { currentChannel.Id },
DtoOptions = new DtoOptions(true)
-
}).Cast<LiveTvProgram>().ToDictionary(i => i.Id);
var newPrograms = new List<LiveTvProgram>();
@@ -1368,10 +1379,10 @@ namespace Emby.Server.Implementations.LiveTv
// limit = (query.Limit ?? 10) * 2;
limit = null;
- //var allActivePaths = EmbyTV.EmbyTV.Current.GetAllActiveRecordings().Select(i => i.Path).ToArray();
- //var items = allActivePaths.Select(i => _libraryManager.FindByPath(i, false)).Where(i => i != null).ToArray();
+ // var allActivePaths = EmbyTV.EmbyTV.Current.GetAllActiveRecordings().Select(i => i.Path).ToArray();
+ // var items = allActivePaths.Select(i => _libraryManager.FindByPath(i, false)).Where(i => i != null).ToArray();
- //return new QueryResult<BaseItem>
+ // return new QueryResult<BaseItem>
//{
// Items = items,
// TotalRecordCount = items.Length
@@ -1738,7 +1749,6 @@ namespace Emby.Server.Implementations.LiveTv
var results = await GetTimers(new TimerQuery
{
Id = id
-
}, cancellationToken).ConfigureAwait(false);
return results.Items.FirstOrDefault(i => string.Equals(i.Id, id, StringComparison.OrdinalIgnoreCase));
@@ -1790,7 +1800,6 @@ namespace Emby.Server.Implementations.LiveTv
.Select(i =>
{
return i.Item1;
-
})
.ToArray();
@@ -1845,7 +1854,6 @@ namespace Emby.Server.Implementations.LiveTv
}
return _tvDtoService.GetSeriesTimerInfoDto(i.Item1, i.Item2, channelName);
-
})
.ToArray();
@@ -1878,7 +1886,6 @@ namespace Emby.Server.Implementations.LiveTv
OrderBy = new[] { (ItemSortBy.StartDate, SortOrder.Ascending) },
TopParentIds = new[] { GetInternalLiveTvFolder(CancellationToken.None).Id },
DtoOptions = options
-
}) : new List<BaseItem>();
RemoveFields(options);
@@ -1956,7 +1963,7 @@ namespace Emby.Server.Implementations.LiveTv
OriginalAirDate = program.PremiereDate,
Overview = program.Overview,
StartDate = program.StartDate,
- //ImagePath = program.ExternalImagePath,
+ // ImagePath = program.ExternalImagePath,
Name = program.Name,
OfficialRating = program.OfficialRating
};
@@ -2167,20 +2174,19 @@ namespace Emby.Server.Implementations.LiveTv
var info = new LiveTvInfo
{
Services = services,
- IsEnabled = services.Length > 0
+ IsEnabled = services.Length > 0,
+ EnabledUsers = _userManager.Users
+ .Where(IsLiveTvEnabled)
+ .Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture))
+ .ToArray()
};
- info.EnabledUsers = _userManager.Users
- .Where(IsLiveTvEnabled)
- .Select(i => i.Id.ToString("N", CultureInfo.InvariantCulture))
- .ToArray();
-
return info;
}
private bool IsLiveTvEnabled(User user)
{
- return user.Policy.EnableLiveTvAccess && (Services.Count > 1 || GetConfiguration().TunerHosts.Length > 0);
+ return user.HasPermission(PermissionKind.EnableLiveTvAccess) && (Services.Count > 1 || GetConfiguration().TunerHosts.Length > 0);
}
public IEnumerable<User> GetEnabledUsers()
@@ -2457,7 +2463,6 @@ namespace Emby.Server.Implementations.LiveTv
UserId = user.Id,
IsRecordingsFolder = true,
RefreshLatestChannelItems = refreshChannels
-
}).Items);
return folders.Cast<BaseItem>().ToList();
diff --git a/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs b/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs
index 8e7d60a15..f1b61f7c7 100644
--- a/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs
+++ b/Emby.Server.Implementations/LiveTv/RefreshChannelsScheduledTask.cs
@@ -35,7 +35,7 @@ namespace Emby.Server.Implementations.LiveTv
}
/// <summary>
- /// Creates the triggers that define when the task will run
+ /// Creates the triggers that define when the task will run.
/// </summary>
/// <returns>IEnumerable{BaseTaskTrigger}.</returns>
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
index ba3594efd..a8d34d19c 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/BaseTunerHost.cs
@@ -54,7 +54,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
var result = await GetChannelsInternal(tuner, cancellationToken).ConfigureAwait(false);
var list = result.ToList();
- //logger.LogInformation("Channels from {0}: {1}", tuner.Url, JsonSerializer.SerializeToString(list));
+ // logger.LogInformation("Channels from {0}: {1}", tuner.Url, JsonSerializer.SerializeToString(list));
if (!string.IsNullOrEmpty(key) && list.Count > 0)
{
@@ -99,7 +99,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
}
catch (IOException)
{
-
}
}
}
@@ -116,7 +115,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
}
catch (IOException)
{
-
}
}
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
index 25b2c674c..dff113a2a 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunHost.cs
@@ -111,7 +111,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
ChannelType = ChannelType.TV,
IsLegacyTuner = (i.URL ?? string.Empty).StartsWith("hdhomerun", StringComparison.OrdinalIgnoreCase),
Path = i.URL
-
}).Cast<ChannelInfo>().ToList();
}
@@ -171,6 +170,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
_modelCache[cacheKey] = response;
}
}
+
return response;
}
@@ -202,6 +202,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var name = line.Substring(0, index - 1);
var currentChannel = line.Substring(index + 7);
if (currentChannel != "none") { status = LiveTvTunerStatus.LiveTv; } else { status = LiveTvTunerStatus.Available; }
+
tuners.Add(new LiveTvTunerInfo
{
Name = name,
@@ -230,11 +231,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
inside = true;
continue;
}
+
if (let == '>')
{
inside = false;
continue;
}
+
if (!inside)
{
buffer[bufferIndex] = let;
@@ -332,12 +335,19 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
private class Channels
{
public string GuideNumber { get; set; }
+
public string GuideName { get; set; }
+
public string VideoCodec { get; set; }
+
public string AudioCodec { get; set; }
+
public string URL { get; set; }
+
public bool Favorite { get; set; }
+
public bool DRM { get; set; }
+
public int HD { get; set; }
}
@@ -481,7 +491,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
Height = height,
BitRate = videoBitrate,
NalLengthSize = nal
-
},
new MediaStream
{
@@ -502,8 +511,8 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
SupportsTranscoding = true,
IsInfiniteStream = true,
IgnoreDts = true,
- //IgnoreIndex = true,
- //ReadAtNativeFramerate = true
+ // IgnoreIndex = true,
+ // ReadAtNativeFramerate = true
};
mediaSource.InferTotalBitrate();
@@ -659,13 +668,21 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
public class DiscoverResponse
{
public string FriendlyName { get; set; }
+
public string ModelNumber { get; set; }
+
public string FirmwareName { get; set; }
+
public string FirmwareVersion { get; set; }
+
public string DeviceID { get; set; }
+
public string DeviceAuth { get; set; }
+
public string BaseURL { get; set; }
+
public string LineupURL { get; set; }
+
public int TunerCount { get; set; }
public bool SupportsTranscoding
@@ -722,7 +739,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
}
}
}
-
}
catch (OperationCanceledException)
{
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
index 82b1f3cf1..6730751d5 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/HdHomerun/HdHomerunUdpStream.cs
@@ -117,17 +117,17 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
taskCompletionSource,
LiveStreamCancellationTokenSource.Token).ConfigureAwait(false);
- //OpenedMediaSource.Protocol = MediaProtocol.File;
- //OpenedMediaSource.Path = tempFile;
- //OpenedMediaSource.ReadAtNativeFramerate = true;
+ // OpenedMediaSource.Protocol = MediaProtocol.File;
+ // OpenedMediaSource.Path = tempFile;
+ // OpenedMediaSource.ReadAtNativeFramerate = true;
MediaSource.Path = _appHost.GetLoopbackHttpApiUrl() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
MediaSource.Protocol = MediaProtocol.Http;
- //OpenedMediaSource.SupportsDirectPlay = false;
- //OpenedMediaSource.SupportsDirectStream = true;
- //OpenedMediaSource.SupportsTranscoding = true;
+ // OpenedMediaSource.SupportsDirectPlay = false;
+ // OpenedMediaSource.SupportsDirectStream = true;
+ // OpenedMediaSource.SupportsTranscoding = true;
- //await Task.Delay(5000).ConfigureAwait(false);
+ // await Task.Delay(5000).ConfigureAwait(false);
await taskCompletionSource.Task.ConfigureAwait(false);
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
index 4e4f1d7f6..0333e723b 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/LiveStream.cs
@@ -58,12 +58,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
protected virtual int EmptyReadLimit => 1000;
public MediaSourceInfo OriginalMediaSource { get; set; }
+
public MediaSourceInfo MediaSource { get; set; }
public int ConsumerCount { get; set; }
public string OriginalStreamId { get; set; }
+
public bool EnableStreamSharing { get; set; }
+
public string UniqueId { get; }
public string TunerHostId { get; }
@@ -220,11 +223,9 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
}
catch (IOException)
{
-
}
catch (ArgumentException)
{
-
}
catch (Exception ex)
{
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
index f7c9c736e..ff42a9747 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3UTunerHost.cs
@@ -127,7 +127,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
{
using (var stream = await new M3uParser(Logger, _httpClient, _appHost).GetListingsStream(info.Url, CancellationToken.None).ConfigureAwait(false))
{
-
}
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
index 59451fccd..c798c0a85 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/M3uParser.cs
@@ -210,7 +210,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
}
}
}
-
}
if (!IsValidChannelNumber(numberString))
@@ -284,7 +283,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
if (double.TryParse(numberPart, NumberStyles.Any, CultureInfo.InvariantCulture, out var number))
{
- //channel.Number = number.ToString();
+ // channel.Number = number.ToString();
nameInExtInf = nameInExtInf.Substring(numberIndex + 1).Trim(new[] { ' ', '-' });
}
}
diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
index 322fbbbaa..bc4dcd894 100644
--- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
+++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs
@@ -103,21 +103,21 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
_ = StartStreaming(response, taskCompletionSource, LiveStreamCancellationTokenSource.Token);
- //OpenedMediaSource.Protocol = MediaProtocol.File;
- //OpenedMediaSource.Path = tempFile;
- //OpenedMediaSource.ReadAtNativeFramerate = true;
+ // OpenedMediaSource.Protocol = MediaProtocol.File;
+ // OpenedMediaSource.Path = tempFile;
+ // OpenedMediaSource.ReadAtNativeFramerate = true;
MediaSource.Path = _appHost.GetLoopbackHttpApiUrl() + "/LiveTv/LiveStreamFiles/" + UniqueId + "/stream.ts";
MediaSource.Protocol = MediaProtocol.Http;
- //OpenedMediaSource.Path = TempFilePath;
- //OpenedMediaSource.Protocol = MediaProtocol.File;
+ // OpenedMediaSource.Path = TempFilePath;
+ // OpenedMediaSource.Protocol = MediaProtocol.File;
- //OpenedMediaSource.Path = _tempFilePath;
- //OpenedMediaSource.Protocol = MediaProtocol.File;
- //OpenedMediaSource.SupportsDirectPlay = false;
- //OpenedMediaSource.SupportsDirectStream = true;
- //OpenedMediaSource.SupportsTranscoding = true;
+ // OpenedMediaSource.Path = _tempFilePath;
+ // OpenedMediaSource.Protocol = MediaProtocol.File;
+ // OpenedMediaSource.SupportsDirectPlay = false;
+ // OpenedMediaSource.SupportsDirectStream = true;
+ // OpenedMediaSource.SupportsTranscoding = true;
await taskCompletionSource.Task.ConfigureAwait(false);
if (taskCompletionSource.Task.Exception != null)
{
diff --git a/Emby.Server.Implementations/Localization/Core/bn.json b/Emby.Server.Implementations/Localization/Core/bn.json
index 77007845f..1f309f3ff 100644
--- a/Emby.Server.Implementations/Localization/Core/bn.json
+++ b/Emby.Server.Implementations/Localization/Core/bn.json
@@ -62,13 +62,13 @@
"NotificationOptionPluginInstalled": "প্লাগিন ইন্সটল করা হয়েছে",
"NotificationOptionPluginError": "প্লাগিন ব্যর্থ",
"NotificationOptionNewLibraryContent": "নতুন কন্টেন্ট যোগ করা হয়েছে",
- "NotificationOptionInstallationFailed": "ইন্সটল ব্যর্থ",
+ "NotificationOptionInstallationFailed": "ইন্সটল ব্যর্থ হয়েছে",
"NotificationOptionCameraImageUploaded": "ক্যামেরার ছবি আপলোড হয়েছে",
"NotificationOptionAudioPlaybackStopped": "গান বাজা বন্ধ হয়েছে",
"NotificationOptionAudioPlayback": "গান বাজা শুরু হয়েছে",
"NotificationOptionApplicationUpdateInstalled": "এপ্লিকেশনের আপডেট ইনস্টল করা হয়েছে",
"NotificationOptionApplicationUpdateAvailable": "এপ্লিকেশনের আপডেট রয়েছে",
- "NewVersionIsAvailable": "জেলিফিন সার্ভারের একটি নতুন ভার্শন ডাউনলোডের জন্য তৈরী",
+ "NewVersionIsAvailable": "জেলিফিন সার্ভারের একটি নতুন ভার্শন ডাউনলোডের জন্য তৈরী।",
"NameSeasonUnknown": "সিজন অজানা",
"NameSeasonNumber": "সিজন {0}",
"NameInstallFailed": "{0} ইন্সটল ব্যর্থ",
@@ -100,5 +100,18 @@
"TaskCleanCacheDescription": "সিস্টেমে আর প্রয়োজন নেই ক্যাশ, ফাইলগুলি মুছে ফেলুন।",
"TaskCleanCache": "ক্লিন ক্যাশ ডিরেক্টরি",
"TasksChannelsCategory": "ইন্টারনেট চ্যানেল",
- "TasksApplicationCategory": "আবেদন"
+ "TasksApplicationCategory": "আবেদন",
+ "TaskDownloadMissingSubtitlesDescription": "মেটাডেটা কনফিগারেশনের উপর ভিত্তি করে অনুপস্থিত সাবটাইটেলগুলির জন্য ইন্টারনেট অনুসন্ধান করে।",
+ "TaskDownloadMissingSubtitles": "অনুপস্থিত সাবটাইটেলগুলি ডাউনলোড করুন",
+ "TaskRefreshChannelsDescription": "ইন্টারনেট চ্যানেল তথ্য রিফ্রেশ করুন।",
+ "TaskRefreshChannels": "চ্যানেল রিফ্রেশ করুন",
+ "TaskCleanTranscodeDescription": "এক দিনেরও বেশি পুরানো ট্রান্সকোড ফাইলগুলি মুছে ফেলুন।",
+ "TaskCleanTranscode": "ট্রান্সকোড ডিরেক্টরি ক্লিন করুন",
+ "TaskUpdatePluginsDescription": "স্বয়ংক্রিয়ভাবে আপডেট কনফিগার করা প্লাগইনগুলির জন্য আপডেট ডাউনলোড এবং ইনস্টল করুন।",
+ "TaskUpdatePlugins": "প্লাগইন আপডেট করুন",
+ "TaskRefreshPeopleDescription": "আপনার মিডিয়া লাইব্রেরিতে অভিনেতা এবং পরিচালকদের জন্য মেটাডাটা আপডেট করুন।",
+ "TaskRefreshPeople": "পিপল রিফ্রেশ করুন",
+ "TaskCleanLogsDescription": "{0} দিনের বেশী পুরানো লগ ফাইলগুলি মুছে ফেলুন।",
+ "TaskCleanLogs": "লগ ডিরেক্টরি ক্লিন করুন",
+ "TaskRefreshLibraryDescription": "নতুন ফাইলের জন্য মিডিয়া লাইব্রেরি স্ক্যান এবং মেটাডাটা রিফ্রেশ করুন।"
}
diff --git a/Emby.Server.Implementations/Localization/Core/fr-CA.json b/Emby.Server.Implementations/Localization/Core/fr-CA.json
index 3dcfa6844..cd1c8144f 100644
--- a/Emby.Server.Implementations/Localization/Core/fr-CA.json
+++ b/Emby.Server.Implementations/Localization/Core/fr-CA.json
@@ -109,9 +109,10 @@
"TaskCleanLogs": "Nettoyer le répertoire des journaux",
"TaskRefreshLibraryDescription": "Analyse votre bibliothèque média pour trouver de nouveaux fichiers et rafraîchit les métadonnées.",
"TaskRefreshChapterImages": "Extraire les images de chapitre",
- "TaskRefreshChapterImagesDescription": "Créer des vignettes pour les vidéos qui ont des chapitres",
+ "TaskRefreshChapterImagesDescription": "Créer des vignettes pour les vidéos qui ont des chapitres.",
"TaskRefreshLibrary": "Analyser la bibliothèque de médias",
"TaskCleanCache": "Nettoyer le répertoire des fichiers temporaires",
"TasksApplicationCategory": "Application",
- "TaskCleanCacheDescription": "Supprime les fichiers temporaires qui ne sont plus nécessaire pour le système."
+ "TaskCleanCacheDescription": "Supprime les fichiers temporaires qui ne sont plus nécessaire pour le système.",
+ "TasksChannelsCategory": "Canaux Internet"
}
diff --git a/Emby.Server.Implementations/Net/SocketFactory.cs b/Emby.Server.Implementations/Net/SocketFactory.cs
index f347540c7..177721658 100644
--- a/Emby.Server.Implementations/Net/SocketFactory.cs
+++ b/Emby.Server.Implementations/Net/SocketFactory.cs
@@ -98,7 +98,6 @@ namespace Emby.Server.Implementations.Net
}
catch (SocketException)
{
-
}
try
@@ -109,12 +108,11 @@ namespace Emby.Server.Implementations.Net
}
catch (SocketException)
{
-
}
try
{
- //retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
+ // retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive);
var localIp = IPAddress.Any;
diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs
index 45864bb42..d12b5a937 100644
--- a/Emby.Server.Implementations/Networking/NetworkManager.cs
+++ b/Emby.Server.Implementations/Networking/NetworkManager.cs
@@ -167,7 +167,7 @@ namespace Emby.Server.Implementations.Networking
foreach (var subnet_Match in subnets)
{
- //logger.LogDebug("subnet_Match:" + subnet_Match);
+ // logger.LogDebug("subnet_Match:" + subnet_Match);
if (endpoint.StartsWith(subnet_Match + ".", StringComparison.OrdinalIgnoreCase))
{
@@ -411,7 +411,7 @@ namespace Emby.Server.Implementations.Networking
}
/// <summary>
- /// Gets a random port number that is currently available
+ /// Gets a random port number that is currently available.
/// </summary>
/// <returns>System.Int32.</returns>
public int GetRandomUnusedTcpPort()
diff --git a/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs b/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs
index 889760586..358606b0d 100644
--- a/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs
+++ b/Emby.Server.Implementations/Playlists/ManualPlaylistsFolder.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Serialization;
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Model.Querying;
@@ -44,7 +45,7 @@ namespace Emby.Server.Implementations.Playlists
}
query.Recursive = true;
- query.IncludeItemTypes = new string[] { "Playlist" };
+ query.IncludeItemTypes = new[] { "Playlist" };
query.Parent = null;
return LibraryManager.GetItemsResult(query);
}
diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
index 8d022d6c4..ac816ccd9 100644
--- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs
+++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
@@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -21,6 +22,8 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using PlaylistsNET.Content;
using PlaylistsNET.Models;
+using Genre = MediaBrowser.Controller.Entities.Genre;
+using MusicAlbum = MediaBrowser.Controller.Entities.Audio.MusicAlbum;
namespace Emby.Server.Implementations.Playlists
{
@@ -398,6 +401,7 @@ namespace Emby.Server.Implementations.Playlists
{
entry.Duration = TimeSpan.FromTicks(child.RunTimeTicks.Value);
}
+
playlist.PlaylistEntries.Add(entry);
}
@@ -463,7 +467,7 @@ namespace Emby.Server.Implementations.Playlists
playlist.PlaylistEntries.Add(entry);
}
- string text = new M3u8Content().ToText(playlist);
+ string text = new M3uContent().ToText(playlist);
File.WriteAllText(playlistPath, text);
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
index e58c335a8..8a900f42c 100644
--- a/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs
@@ -18,7 +18,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
- /// Class ScheduledTaskWorker
+ /// Class ScheduledTaskWorker.
/// </summary>
public class ScheduledTaskWorker : IScheduledTaskWorker
{
@@ -111,11 +111,11 @@ namespace Emby.Server.Implementations.ScheduledTasks
private bool _readFromFile = false;
/// <summary>
- /// The _last execution result
+ /// The _last execution result.
/// </summary>
private TaskResult _lastExecutionResult;
/// <summary>
- /// The _last execution result sync lock
+ /// The _last execution result sync lock.
/// </summary>
private readonly object _lastExecutionResultSyncLock = new object();
/// <summary>
@@ -143,12 +143,14 @@ namespace Emby.Server.Implementations.ScheduledTasks
Logger.LogError(ex, "Error deserializing {File}", path);
}
}
+
_readFromFile = true;
}
}
return _lastExecutionResult;
}
+
private set
{
_lastExecutionResult = value;
@@ -182,7 +184,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
public string Category => ScheduledTask.Category;
/// <summary>
- /// Gets the current cancellation token
+ /// Gets the current cancellation token.
/// </summary>
/// <value>The current cancellation token source.</value>
private CancellationTokenSource CurrentCancellationTokenSource { get; set; }
@@ -261,6 +263,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
var triggers = InternalTriggers;
return triggers.Select(i => i.Item1).ToArray();
}
+
set
{
if (value == null)
@@ -278,7 +281,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// The _id
+ /// The _id.
/// </summary>
private string _id;
@@ -358,7 +361,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
private Task _currentTask;
/// <summary>
- /// Executes the task
+ /// Executes the task.
/// </summary>
/// <param name="options">Task options.</param>
/// <returns>Task.</returns>
@@ -453,7 +456,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// Stops the task if it is currently executing
+ /// Stops the task if it is currently executing.
/// </summary>
/// <exception cref="InvalidOperationException">Cannot cancel a Task unless it is in the Running state.</exception>
public void Cancel()
@@ -640,6 +643,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
Logger.LogError(ex, "Error calling CancellationToken.Cancel();");
}
}
+
var task = _currentTask;
if (task != null)
{
@@ -675,6 +679,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
Logger.LogError(ex, "Error calling CancellationToken.Dispose();");
}
}
+
if (wassRunning)
{
OnTaskCompleted(startTime, DateTime.UtcNow, TaskCompletionStatus.Aborted, null);
@@ -683,7 +688,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// Converts a TaskTriggerInfo into a concrete BaseTaskTrigger
+ /// Converts a TaskTriggerInfo into a concrete BaseTaskTrigger.
/// </summary>
/// <param name="info">The info.</param>
/// <returns>BaseTaskTrigger.</returns>
@@ -753,7 +758,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// Disposes each trigger
+ /// Disposes each trigger.
/// </summary>
private void DisposeTriggers()
{
diff --git a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs
index 94220ac5d..0ad4253e4 100644
--- a/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/TaskManager.cs
@@ -15,7 +15,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
- /// Class TaskManager
+ /// Class TaskManager.
/// </summary>
public class TaskManager : ITaskManager
{
@@ -23,13 +23,13 @@ namespace Emby.Server.Implementations.ScheduledTasks
public event EventHandler<TaskCompletionEventArgs> TaskCompleted;
/// <summary>
- /// Gets the list of Scheduled Tasks
+ /// Gets the list of Scheduled Tasks.
/// </summary>
/// <value>The scheduled tasks.</value>
public IScheduledTaskWorker[] ScheduledTasks { get; private set; }
/// <summary>
- /// The _task queue
+ /// The _task queue.
/// </summary>
private readonly ConcurrentQueue<Tuple<Type, TaskOptions>> _taskQueue =
new ConcurrentQueue<Tuple<Type, TaskOptions>>();
@@ -81,7 +81,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// Cancels if running
+ /// Cancels if running.
/// </summary>
/// <typeparam name="T"></typeparam>
public void CancelIfRunning<T>()
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
index 9028222dd..3854be703 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/ChapterImagesTask.cs
@@ -163,7 +163,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
catch (ObjectDisposedException)
{
- //TODO Investigate and properly fix.
+ // TODO Investigate and properly fix.
break;
}
}
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
index 966b549b2..e29fcfb5f 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteCacheFileTask.cs
@@ -13,7 +13,7 @@ using MediaBrowser.Model.Globalization;
namespace Emby.Server.Implementations.ScheduledTasks.Tasks
{
/// <summary>
- /// Deletes old cache files
+ /// Deletes old cache files.
/// </summary>
public class DeleteCacheFileTask : IScheduledTask, IConfigurableScheduledTask
{
@@ -44,7 +44,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
}
/// <summary>
- /// Creates the triggers that define when the task will run
+ /// Creates the triggers that define when the task will run.
/// </summary>
/// <returns>IEnumerable{BaseTaskTrigger}.</returns>
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
@@ -57,7 +57,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
}
/// <summary>
- /// Returns the task to be executed
+ /// Returns the task to be executed.
/// </summary>
/// <param name="cancellationToken">The cancellation token.</param>
/// <param name="progress">The progress.</param>
@@ -93,7 +93,7 @@ namespace Emby.Server.Implementations.ScheduledTasks.Tasks
/// <summary>
- /// Deletes the cache files from directory with a last write time less than a given date
+ /// Deletes the cache files from directory with a last write time less than a given date.
/// </summary>
/// <param name="cancellationToken">The task cancellation token.</param>
/// <param name="directory">The directory.</param>
diff --git a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs
index 53cf9a0a5..691408167 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Tasks/DeleteTranscodeFileTask.cs
@@ -13,7 +13,7 @@ using MediaBrowser.Model.Globalization;
namespace Emby.Server.Implementations.ScheduledTasks.Tasks
{
/// <summary>
- /// Deletes all transcoding temp files
+ /// Deletes all transcoding temp files.
/// </summary>
public class DeleteTranscodeFileTask : IScheduledTask, IConfigurableScheduledTask
{
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
index c7819d4c0..eb628ec5f 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/DailyTrigger.cs
@@ -28,7 +28,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
private Timer Timer { get; set; }
/// <summary>
- /// Stars waiting for the trigger action
+ /// Stars waiting for the trigger action.
/// </summary>
/// <param name="lastResult">The last result.</param>
/// <param name="logger">The logger.</param>
@@ -51,7 +51,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// Stops waiting for the trigger action
+ /// Stops waiting for the trigger action.
/// </summary>
public void Stop()
{
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
index 74cd4ef1e..247a6785a 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/IntervalTrigger.cs
@@ -7,7 +7,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
- /// Represents a task trigger that runs repeatedly on an interval
+ /// Represents a task trigger that runs repeatedly on an interval.
/// </summary>
public class IntervalTrigger : ITaskTrigger
{
@@ -31,7 +31,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
private DateTime _lastStartDate;
/// <summary>
- /// Stars waiting for the trigger action
+ /// Stars waiting for the trigger action.
/// </summary>
/// <param name="lastResult">The last result.</param>
/// <param name="logger">The logger.</param>
@@ -70,7 +70,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// Stops waiting for the trigger action
+ /// Stops waiting for the trigger action.
/// </summary>
public void Stop()
{
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs
index e171a9e9f..96e5d8897 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/StartupTrigger.cs
@@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// Stars waiting for the trigger action
+ /// Stars waiting for the trigger action.
/// </summary>
/// <param name="lastResult">The last result.</param>
/// <param name="logger">The logger.</param>
@@ -42,7 +42,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// Stops waiting for the trigger action
+ /// Stops waiting for the trigger action.
/// </summary>
public void Stop()
{
diff --git a/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
index ad0b57af6..4f1bf5c19 100644
--- a/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
+++ b/Emby.Server.Implementations/ScheduledTasks/Triggers/WeeklyTrigger.cs
@@ -6,12 +6,12 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.ScheduledTasks
{
/// <summary>
- /// Represents a task trigger that fires on a weekly basis
+ /// Represents a task trigger that fires on a weekly basis.
/// </summary>
public class WeeklyTrigger : ITaskTrigger
{
/// <summary>
- /// Get the time of day to trigger the task to run
+ /// Get the time of day to trigger the task to run.
/// </summary>
/// <value>The time of day.</value>
public TimeSpan TimeOfDay { get; set; }
@@ -34,7 +34,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
private Timer Timer { get; set; }
/// <summary>
- /// Stars waiting for the trigger action
+ /// Stars waiting for the trigger action.
/// </summary>
/// <param name="lastResult">The last result.</param>
/// <param name="logger">The logger.</param>
@@ -77,7 +77,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
}
/// <summary>
- /// Stops waiting for the trigger action
+ /// Stops waiting for the trigger action.
/// </summary>
public void Stop()
{
diff --git a/Emby.Server.Implementations/Security/AuthenticationRepository.cs b/Emby.Server.Implementations/Security/AuthenticationRepository.cs
index 750890ec8..9c1be9a1a 100644
--- a/Emby.Server.Implementations/Security/AuthenticationRepository.cs
+++ b/Emby.Server.Implementations/Security/AuthenticationRepository.cs
@@ -61,7 +61,6 @@ namespace Emby.Server.Implementations.Security
AddColumn(db, "AccessTokens", "UserName", "TEXT", existingColumnNames);
AddColumn(db, "AccessTokens", "DateLastActivity", "DATETIME", existingColumnNames);
AddColumn(db, "AccessTokens", "AppVersion", "TEXT", existingColumnNames);
-
}, TransactionMode);
connection.RunQueries(new[]
@@ -107,7 +106,6 @@ namespace Emby.Server.Implementations.Security
statement.MoveNext();
}
-
}, TransactionMode);
}
}
@@ -367,7 +365,6 @@ namespace Emby.Server.Implementations.Security
return result;
}
-
}, ReadTransactionMode);
}
}
@@ -398,7 +395,6 @@ namespace Emby.Server.Implementations.Security
statement.MoveNext();
}
-
}, TransactionMode);
}
}
diff --git a/Emby.Server.Implementations/Services/ResponseHelper.cs b/Emby.Server.Implementations/Services/ResponseHelper.cs
index f2b1d06f3..3f1672e94 100644
--- a/Emby.Server.Implementations/Services/ResponseHelper.cs
+++ b/Emby.Server.Implementations/Services/ResponseHelper.cs
@@ -59,8 +59,8 @@ namespace Emby.Server.Implementations.Services
}
}
- //ContentType='text/html' is the default for a HttpResponse
- //Do not override if another has been set
+ // ContentType='text/html' is the default for a HttpResponse
+ // Do not override if another has been set
if (response.ContentType == null || response.ContentType == "text/html")
{
response.ContentType = defaultContentType;
diff --git a/Emby.Server.Implementations/Services/ServiceController.cs b/Emby.Server.Implementations/Services/ServiceController.cs
index e688278b5..b84e47140 100644
--- a/Emby.Server.Implementations/Services/ServiceController.cs
+++ b/Emby.Server.Implementations/Services/ServiceController.cs
@@ -59,8 +59,8 @@ namespace Emby.Server.Implementations.Services
ServiceExecGeneral.CreateServiceRunnersFor(requestType, actions);
- //var returnMarker = GetTypeWithGenericTypeDefinitionOf(requestType, typeof(IReturn<>));
- //var responseType = returnMarker != null ?
+ // var returnMarker = GetTypeWithGenericTypeDefinitionOf(requestType, typeof(IReturn<>));
+ // var responseType = returnMarker != null ?
// GetGenericArguments(returnMarker)[0]
// : mi.ReturnType != typeof(object) && mi.ReturnType != typeof(void) ?
// mi.ReturnType
@@ -182,7 +182,7 @@ namespace Emby.Server.Implementations.Services
serviceRequiresContext.Request = req;
}
- //Executes the service and returns the result
+ // Executes the service and returns the result
return ServiceExecGeneral.Execute(serviceType, req, service, requestDto, requestType.GetMethodName());
}
}
diff --git a/Emby.Server.Implementations/Services/ServiceHandler.cs b/Emby.Server.Implementations/Services/ServiceHandler.cs
index 7f44357e1..a42f88ea0 100644
--- a/Emby.Server.Implementations/Services/ServiceHandler.cs
+++ b/Emby.Server.Implementations/Services/ServiceHandler.cs
@@ -180,7 +180,7 @@ namespace Emby.Server.Implementations.Services
=> string.Equals(method, expected, StringComparison.OrdinalIgnoreCase);
/// <summary>
- /// Duplicate params have their values joined together in a comma-delimited string
+ /// Duplicate params have their values joined together in a comma-delimited string.
/// </summary>
private static Dictionary<string, string> GetFlattenedRequestParams(HttpRequest request)
{
diff --git a/Emby.Server.Implementations/Services/ServiceMethod.cs b/Emby.Server.Implementations/Services/ServiceMethod.cs
index 59ee5908f..5116cc04f 100644
--- a/Emby.Server.Implementations/Services/ServiceMethod.cs
+++ b/Emby.Server.Implementations/Services/ServiceMethod.cs
@@ -9,6 +9,7 @@ namespace Emby.Server.Implementations.Services
public string Id { get; set; }
public ActionInvokerFn ServiceAction { get; set; }
+
public MediaBrowser.Model.Services.IHasRequestFilter[] RequestFilters { get; set; }
public static string Key(Type serviceType, string method, string requestDtoName)
diff --git a/Emby.Server.Implementations/Services/ServicePath.cs b/Emby.Server.Implementations/Services/ServicePath.cs
index 278379a92..3b7ffaf2c 100644
--- a/Emby.Server.Implementations/Services/ServicePath.cs
+++ b/Emby.Server.Implementations/Services/ServicePath.cs
@@ -62,7 +62,9 @@ namespace Emby.Server.Implementations.Services
public string Path => this.restPath;
public string Summary { get; private set; }
+
public string Description { get; private set; }
+
public bool IsHidden { get; private set; }
public static string[] GetPathPartsForMatching(string pathInfo)
@@ -118,7 +120,7 @@ namespace Emby.Server.Implementations.Services
var componentsList = new List<string>();
- //We only split on '.' if the restPath has them. Allows for /{action}.{type}
+ // We only split on '.' if the restPath has them. Allows for /{action}.{type}
var hasSeparators = new List<bool>();
foreach (var component in this.restPath.Split(PathSeperatorChar))
{
@@ -159,6 +161,7 @@ namespace Emby.Server.Implementations.Services
this.isWildcard[i] = true;
variableName = variableName.Substring(0, variableName.Length - 1);
}
+
this.variablesNames[i] = variableName;
this.VariableArgsCount++;
}
@@ -298,12 +301,12 @@ namespace Emby.Server.Implementations.Services
return -1;
}
- //Routes with least wildcard matches get the highest score
+ // Routes with least wildcard matches get the highest score
var score = Math.Max((100 - wildcardMatchCount), 1) * 1000
- //Routes with less variable (and more literal) matches
+ // Routes with less variable (and more literal) matches
+ Math.Max((10 - VariableArgsCount), 1) * 100;
- //Exact verb match is better than ANY
+ // Exact verb match is better than ANY
if (Verbs.Length == 1 && string.Equals(httpMethod, Verbs[0], StringComparison.OrdinalIgnoreCase))
{
score += 10;
@@ -470,7 +473,7 @@ namespace Emby.Server.Implementations.Services
+ variableName + " on " + RequestType.GetMethodName());
}
- var value = requestComponents.Length > pathIx ? requestComponents[pathIx] : null; //wildcard has arg mismatch
+ var value = requestComponents.Length > pathIx ? requestComponents[pathIx] : null; // wildcard has arg mismatch
if (value != null && this.isWildcard[i])
{
if (i == this.TotalComponentsCount - 1)
@@ -519,8 +522,8 @@ namespace Emby.Server.Implementations.Services
if (queryStringAndFormData != null)
{
- //Query String and form data can override variable path matches
- //path variables < query string < form data
+ // Query String and form data can override variable path matches
+ // path variables < query string < form data
foreach (var name in queryStringAndFormData)
{
requestKeyValuesMap[name.Key] = name.Value;
diff --git a/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs b/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs
index ab22fe019..165bb0fc4 100644
--- a/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs
+++ b/Emby.Server.Implementations/Services/StringMapTypeDeserializer.cs
@@ -22,7 +22,9 @@ namespace Emby.Server.Implementations.Services
}
public Action<object, object> PropertySetFn { get; private set; }
+
public Func<string, object> PropertyParseStringFn { get; private set; }
+
public Type PropertyType { get; private set; }
}
@@ -83,7 +85,7 @@ namespace Emby.Server.Implementations.Services
if (propertySerializerEntry.PropertyType == typeof(bool))
{
- //InputExtensions.cs#530 MVC Checkbox helper emits extra hidden input field, generating 2 values, first is the real value
+ // InputExtensions.cs#530 MVC Checkbox helper emits extra hidden input field, generating 2 values, first is the real value
propertyTextValue = StringExtensions.LeftPart(propertyTextValue, ',').ToString();
}
diff --git a/Emby.Server.Implementations/Services/SwaggerService.cs b/Emby.Server.Implementations/Services/SwaggerService.cs
index 16142a70d..4f011a678 100644
--- a/Emby.Server.Implementations/Services/SwaggerService.cs
+++ b/Emby.Server.Implementations/Services/SwaggerService.cs
@@ -18,13 +18,21 @@ namespace Emby.Server.Implementations.Services
public class SwaggerSpec
{
public string swagger { get; set; }
+
public string[] schemes { get; set; }
+
public SwaggerInfo info { get; set; }
+
public string host { get; set; }
+
public string basePath { get; set; }
+
public SwaggerTag[] tags { get; set; }
+
public IDictionary<string, Dictionary<string, SwaggerMethod>> paths { get; set; }
+
public Dictionary<string, SwaggerDefinition> definitions { get; set; }
+
public SwaggerComponents components { get; set; }
}
@@ -36,15 +44,20 @@ namespace Emby.Server.Implementations.Services
public class SwaggerSecurityScheme
{
public string name { get; set; }
+
public string type { get; set; }
+
public string @in { get; set; }
}
public class SwaggerInfo
{
public string description { get; set; }
+
public string version { get; set; }
+
public string title { get; set; }
+
public string termsOfService { get; set; }
public SwaggerConcactInfo contact { get; set; }
@@ -53,36 +66,52 @@ namespace Emby.Server.Implementations.Services
public class SwaggerConcactInfo
{
public string email { get; set; }
+
public string name { get; set; }
+
public string url { get; set; }
}
public class SwaggerTag
{
public string description { get; set; }
+
public string name { get; set; }
}
public class SwaggerMethod
{
public string summary { get; set; }
+
public string description { get; set; }
+
public string[] tags { get; set; }
+
public string operationId { get; set; }
+
public string[] consumes { get; set; }
+
public string[] produces { get; set; }
+
public SwaggerParam[] parameters { get; set; }
+
public Dictionary<string, SwaggerResponse> responses { get; set; }
+
public Dictionary<string, string[]>[] security { get; set; }
}
public class SwaggerParam
{
public string @in { get; set; }
+
public string name { get; set; }
+
public string description { get; set; }
+
public bool required { get; set; }
+
public string type { get; set; }
+
public string collectionFormat { get; set; }
}
@@ -97,15 +126,20 @@ namespace Emby.Server.Implementations.Services
public class SwaggerDefinition
{
public string type { get; set; }
+
public Dictionary<string, SwaggerProperty> properties { get; set; }
}
public class SwaggerProperty
{
public string type { get; set; }
+
public string format { get; set; }
+
public string description { get; set; }
+
public string[] @enum { get; set; }
+
public string @default { get; set; }
}
diff --git a/Emby.Server.Implementations/Services/UrlExtensions.cs b/Emby.Server.Implementations/Services/UrlExtensions.cs
index e3b6aa197..92e36b60e 100644
--- a/Emby.Server.Implementations/Services/UrlExtensions.cs
+++ b/Emby.Server.Implementations/Services/UrlExtensions.cs
@@ -9,7 +9,7 @@ namespace Emby.Server.Implementations.Services
/// Donated by Ivan Korneliuk from his post:
/// http://korneliuk.blogspot.com/2012/08/servicestack-reusing-dtos.html
///
- /// Modified to only allow using routes matching the supplied HTTP Verb
+ /// Modified to only allow using routes matching the supplied HTTP Verb.
/// </summary>
public static class UrlExtensions
{
diff --git a/Emby.Server.Implementations/Session/SessionManager.cs b/Emby.Server.Implementations/Session/SessionManager.cs
index 506e6739f..75fdedd10 100644
--- a/Emby.Server.Implementations/Session/SessionManager.cs
+++ b/Emby.Server.Implementations/Session/SessionManager.cs
@@ -7,6 +7,8 @@ using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Jellyfin.Data.Entities;
+using Jellyfin.Data.Enums;
using MediaBrowser.Common.Events;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller;
@@ -15,7 +17,6 @@ using MediaBrowser.Controller.Devices;
using MediaBrowser.Controller.Drawing;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Net;
using MediaBrowser.Controller.Security;
@@ -28,7 +29,9 @@ using MediaBrowser.Model.Library;
using MediaBrowser.Model.Querying;
using MediaBrowser.Model.Session;
using MediaBrowser.Model.SyncPlay;
+using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
+using Episode = MediaBrowser.Controller.Entities.TV.Episode;
namespace Emby.Server.Implementations.Session
{
@@ -283,11 +286,18 @@ namespace Emby.Server.Implementations.Session
if (user != null)
{
var userLastActivityDate = user.LastActivityDate ?? DateTime.MinValue;
- user.LastActivityDate = activityDate;
if ((activityDate - userLastActivityDate).TotalSeconds > 60)
{
- _userManager.UpdateUser(user);
+ try
+ {
+ user.LastActivityDate = activityDate;
+ _userManager.UpdateUser(user);
+ }
+ catch (DbUpdateConcurrencyException e)
+ {
+ _logger.LogWarning(e, "Error updating user's last activity date.");
+ }
}
}
@@ -434,7 +444,13 @@ namespace Emby.Server.Implementations.Session
/// <param name="remoteEndPoint">The remote end point.</param>
/// <param name="user">The user.</param>
/// <returns>SessionInfo.</returns>
- private SessionInfo GetSessionInfo(string appName, string appVersion, string deviceId, string deviceName, string remoteEndPoint, User user)
+ private SessionInfo GetSessionInfo(
+ string appName,
+ string appVersion,
+ string deviceId,
+ string deviceName,
+ string remoteEndPoint,
+ User user)
{
CheckDisposed();
@@ -447,14 +463,13 @@ namespace Emby.Server.Implementations.Session
CheckDisposed();
- var sessionInfo = _activeConnections.GetOrAdd(key, k =>
- {
- return CreateSession(k, appName, appVersion, deviceId, deviceName, remoteEndPoint, user);
- });
+ var sessionInfo = _activeConnections.GetOrAdd(
+ key,
+ k => CreateSession(k, appName, appVersion, deviceId, deviceName, remoteEndPoint, user));
- sessionInfo.UserId = user == null ? Guid.Empty : user.Id;
- sessionInfo.UserName = user?.Name;
- sessionInfo.UserPrimaryImageTag = user == null ? null : GetImageCacheTag(user, ImageType.Primary);
+ sessionInfo.UserId = user?.Id ?? Guid.Empty;
+ sessionInfo.UserName = user?.Username;
+ sessionInfo.UserPrimaryImageTag = user?.ProfileImage == null ? null : GetImageCacheTag(user);
sessionInfo.RemoteEndPoint = remoteEndPoint;
sessionInfo.Client = appName;
@@ -473,7 +488,14 @@ namespace Emby.Server.Implementations.Session
return sessionInfo;
}
- private SessionInfo CreateSession(string key, string appName, string appVersion, string deviceId, string deviceName, string remoteEndPoint, User user)
+ private SessionInfo CreateSession(
+ string key,
+ string appName,
+ string appVersion,
+ string deviceId,
+ string deviceName,
+ string remoteEndPoint,
+ User user)
{
var sessionInfo = new SessionInfo(this, _logger)
{
@@ -483,11 +505,11 @@ namespace Emby.Server.Implementations.Session
Id = key.GetMD5().ToString("N", CultureInfo.InvariantCulture)
};
- var username = user?.Name;
+ var username = user?.Username;
sessionInfo.UserId = user?.Id ?? Guid.Empty;
sessionInfo.UserName = username;
- sessionInfo.UserPrimaryImageTag = user == null ? null : GetImageCacheTag(user, ImageType.Primary);
+ sessionInfo.UserPrimaryImageTag = user?.ProfileImage == null ? null : GetImageCacheTag(user);
sessionInfo.RemoteEndPoint = remoteEndPoint;
if (string.IsNullOrEmpty(deviceName))
@@ -535,10 +557,7 @@ namespace Emby.Server.Implementations.Session
private void StartIdleCheckTimer()
{
- if (_idleTimer == null)
- {
- _idleTimer = new Timer(CheckForIdlePlayback, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
- }
+ _idleTimer ??= new Timer(CheckForIdlePlayback, null, TimeSpan.FromMinutes(5), TimeSpan.FromMinutes(5));
}
private void StopIdleCheckTimer()
@@ -786,7 +805,7 @@ namespace Emby.Server.Implementations.Session
{
var changed = false;
- if (user.Configuration.RememberAudioSelections)
+ if (user.RememberAudioSelections)
{
if (data.AudioStreamIndex != info.AudioStreamIndex)
{
@@ -803,7 +822,7 @@ namespace Emby.Server.Implementations.Session
}
}
- if (user.Configuration.RememberSubtitleSelections)
+ if (user.RememberSubtitleSelections)
{
if (data.SubtitleStreamIndex != info.SubtitleStreamIndex)
{
@@ -824,7 +843,7 @@ namespace Emby.Server.Implementations.Session
}
/// <summary>
- /// Used to report that playback has ended for an item
+ /// Used to report that playback has ended for an item.
/// </summary>
/// <param name="info">The info.</param>
/// <returns>Task.</returns>
@@ -1114,13 +1133,13 @@ namespace Emby.Server.Implementations.Session
if (items.Any(i => i.GetPlayAccess(user) != PlayAccess.Full))
{
throw new ArgumentException(
- string.Format(CultureInfo.InvariantCulture, "{0} is not allowed to play media.", user.Name));
+ string.Format(CultureInfo.InvariantCulture, "{0} is not allowed to play media.", user.Username));
}
}
if (user != null
&& command.ItemIds.Length == 1
- && user.Configuration.EnableNextEpisodeAutoPlay
+ && user.EnableNextEpisodeAutoPlay
&& _libraryManager.GetItemById(command.ItemIds[0]) is Episode episode)
{
var series = episode.Series;
@@ -1191,7 +1210,7 @@ namespace Emby.Server.Implementations.Session
DtoOptions = new DtoOptions(false)
{
EnableImages = false,
- Fields = new ItemFields[]
+ Fields = new[]
{
ItemFields.SortName
}
@@ -1353,7 +1372,7 @@ namespace Emby.Server.Implementations.Session
list.Add(new SessionUserInfo
{
UserId = userId,
- UserName = user.Name
+ UserName = user.Username
});
session.AdditionalUsers = list.ToArray();
@@ -1513,7 +1532,7 @@ namespace Emby.Server.Implementations.Session
DeviceName = deviceName,
UserId = user.Id,
AccessToken = Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture),
- UserName = user.Name
+ UserName = user.Username
};
_logger.LogInformation("Creating new access token for user {0}", user.Id);
@@ -1710,15 +1729,15 @@ namespace Emby.Server.Implementations.Session
return info;
}
- private string GetImageCacheTag(BaseItem item, ImageType type)
+ private string GetImageCacheTag(User user)
{
try
{
- return _imageProcessor.GetImageCacheTag(item, type);
+ return _imageProcessor.GetImageCacheTag(user);
}
- catch (Exception ex)
+ catch (Exception e)
{
- _logger.LogError(ex, "Error getting image information for {Type}", type);
+ _logger.LogError(e, "Error getting image information for profile image");
return null;
}
}
@@ -1827,7 +1846,10 @@ namespace Emby.Server.Implementations.Session
{
CheckDisposed();
- var adminUserIds = _userManager.Users.Where(i => i.Policy.IsAdministrator).Select(i => i.Id).ToList();
+ var adminUserIds = _userManager.Users
+ .Where(i => i.HasPermission(PermissionKind.IsAdministrator))
+ .Select(i => i.Id)
+ .ToList();
return SendMessageToUserSessions(adminUserIds, name, data, cancellationToken);
}
diff --git a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs
index ef32c692c..b9db6ecd0 100644
--- a/Emby.Server.Implementations/Session/SessionWebSocketListener.cs
+++ b/Emby.Server.Implementations/Session/SessionWebSocketListener.cs
@@ -14,7 +14,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Session
{
/// <summary>
- /// Class SessionWebSocketListener
+ /// Class SessionWebSocketListener.
/// </summary>
public sealed class SessionWebSocketListener : IWebSocketListener, IDisposable
{
@@ -34,12 +34,12 @@ namespace Emby.Server.Implementations.Session
public const float ForceKeepAliveFactor = 0.75f;
/// <summary>
- /// The _session manager
+ /// The _session manager.
/// </summary>
private readonly ISessionManager _sessionManager;
/// <summary>
- /// The _logger
+ /// The _logger.
/// </summary>
private readonly ILogger<SessionWebSocketListener> _logger;
private readonly ILoggerFactory _loggerFactory;
@@ -167,6 +167,7 @@ namespace Emby.Server.Implementations.Session
_logger.LogWarning("Multiple attempts to keep alive single WebSocket {0}", webSocket);
return;
}
+
webSocket.Closed += OnWebSocketClosed;
webSocket.LastKeepAliveDate = DateTime.UtcNow;
diff --git a/Emby.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs b/Emby.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs
index 67e31f7f6..2b7d818be 100644
--- a/Emby.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs
+++ b/Emby.Server.Implementations/Sorting/AiredEpisodeOrderComparer.cs
@@ -34,7 +34,7 @@ namespace Emby.Server.Implementations.Sorting
if (val != 0)
{
- //return val;
+ // return val;
}
}
diff --git a/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs b/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs
index 0804b01fc..7657cc74e 100644
--- a/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs
+++ b/Emby.Server.Implementations/Sorting/AlbumArtistComparer.cs
@@ -8,7 +8,7 @@ using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Sorting
{
/// <summary>
- /// Class AlbumArtistComparer
+ /// Class AlbumArtistComparer.
/// </summary>
public class AlbumArtistComparer : IBaseItemComparer
{
diff --git a/Emby.Server.Implementations/Sorting/AlbumComparer.cs b/Emby.Server.Implementations/Sorting/AlbumComparer.cs
index 3831a0d2d..7dfdd9ecf 100644
--- a/Emby.Server.Implementations/Sorting/AlbumComparer.cs
+++ b/Emby.Server.Implementations/Sorting/AlbumComparer.cs
@@ -7,7 +7,7 @@ using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Sorting
{
/// <summary>
- /// Class AlbumComparer
+ /// Class AlbumComparer.
/// </summary>
public class AlbumComparer : IBaseItemComparer
{
diff --git a/Emby.Server.Implementations/Sorting/CriticRatingComparer.cs b/Emby.Server.Implementations/Sorting/CriticRatingComparer.cs
index adb78dec5..fa136c36d 100644
--- a/Emby.Server.Implementations/Sorting/CriticRatingComparer.cs
+++ b/Emby.Server.Implementations/Sorting/CriticRatingComparer.cs
@@ -5,7 +5,7 @@ using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Sorting
{
/// <summary>
- /// Class CriticRatingComparer
+ /// Class CriticRatingComparer.
/// </summary>
public class CriticRatingComparer : IBaseItemComparer
{
diff --git a/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs b/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs
index 8501bd9ee..ea981e840 100644
--- a/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs
+++ b/Emby.Server.Implementations/Sorting/DateCreatedComparer.cs
@@ -6,7 +6,7 @@ using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Sorting
{
/// <summary>
- /// Class DateCreatedComparer
+ /// Class DateCreatedComparer.
/// </summary>
public class DateCreatedComparer : IBaseItemComparer
{
diff --git a/Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs b/Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs
index 5c1503ed2..03ff19d21 100644
--- a/Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs
+++ b/Emby.Server.Implementations/Sorting/DateLastMediaAddedComparer.cs
@@ -1,6 +1,7 @@
#pragma warning disable CS1591
using System;
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Sorting;
diff --git a/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs b/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs
index 73f59f8cd..16bd2aff8 100644
--- a/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs
+++ b/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs
@@ -1,4 +1,5 @@
using System;
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Sorting;
@@ -7,7 +8,7 @@ using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Sorting
{
/// <summary>
- /// Class DatePlayedComparer
+ /// Class DatePlayedComparer.
/// </summary>
public class DatePlayedComparer : IUserBaseItemComparer
{
diff --git a/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs b/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs
index aba14c6ca..0c4e82d01 100644
--- a/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs
+++ b/Emby.Server.Implementations/Sorting/IsFavoriteOrLikeComparer.cs
@@ -1,5 +1,6 @@
#pragma warning disable CS1591
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Sorting;
diff --git a/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs b/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs
index 39d9bc68e..d95948406 100644
--- a/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs
+++ b/Emby.Server.Implementations/Sorting/IsPlayedComparer.cs
@@ -1,5 +1,6 @@
#pragma warning disable CS1591
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Sorting;
diff --git a/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs b/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs
index 478df4035..1632c5a7a 100644
--- a/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs
+++ b/Emby.Server.Implementations/Sorting/IsUnplayedComparer.cs
@@ -1,5 +1,6 @@
#pragma warning disable CS1591
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Sorting;
diff --git a/Emby.Server.Implementations/Sorting/NameComparer.cs b/Emby.Server.Implementations/Sorting/NameComparer.cs
index 4eb1549f5..da020d8d8 100644
--- a/Emby.Server.Implementations/Sorting/NameComparer.cs
+++ b/Emby.Server.Implementations/Sorting/NameComparer.cs
@@ -6,7 +6,7 @@ using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Sorting
{
/// <summary>
- /// Class NameComparer
+ /// Class NameComparer.
/// </summary>
public class NameComparer : IBaseItemComparer
{
diff --git a/Emby.Server.Implementations/Sorting/PlayCountComparer.cs b/Emby.Server.Implementations/Sorting/PlayCountComparer.cs
index eb74ce1bd..5c2830322 100644
--- a/Emby.Server.Implementations/Sorting/PlayCountComparer.cs
+++ b/Emby.Server.Implementations/Sorting/PlayCountComparer.cs
@@ -1,3 +1,4 @@
+using Jellyfin.Data.Entities;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Sorting;
@@ -6,7 +7,7 @@ using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Sorting
{
/// <summary>
- /// Class PlayCountComparer
+ /// Class PlayCountComparer.
/// </summary>
public class PlayCountComparer : IUserBaseItemComparer
{
diff --git a/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs b/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs
index 0c944a7a0..92ac04dc6 100644
--- a/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs
+++ b/Emby.Server.Implementations/Sorting/PremiereDateComparer.cs
@@ -6,7 +6,7 @@ using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Sorting
{
/// <summary>
- /// Class PremiereDateComparer
+ /// Class PremiereDateComparer.
/// </summary>
public class PremiereDateComparer : IBaseItemComparer
{
@@ -44,6 +44,7 @@ namespace Emby.Server.Implementations.Sorting
// Don't blow up if the item has a bad ProductionYear, just return MinValue
}
}
+
return DateTime.MinValue;
}
diff --git a/Emby.Server.Implementations/Sorting/ProductionYearComparer.cs b/Emby.Server.Implementations/Sorting/ProductionYearComparer.cs
index 472a07eb3..e2857df0b 100644
--- a/Emby.Server.Implementations/Sorting/ProductionYearComparer.cs
+++ b/Emby.Server.Implementations/Sorting/ProductionYearComparer.cs
@@ -5,7 +5,7 @@ using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Sorting
{
/// <summary>
- /// Class ProductionYearComparer
+ /// Class ProductionYearComparer.
/// </summary>
public class ProductionYearComparer : IBaseItemComparer
{
diff --git a/Emby.Server.Implementations/Sorting/RandomComparer.cs b/Emby.Server.Implementations/Sorting/RandomComparer.cs
index bde8b4534..7739d0418 100644
--- a/Emby.Server.Implementations/Sorting/RandomComparer.cs
+++ b/Emby.Server.Implementations/Sorting/RandomComparer.cs
@@ -6,7 +6,7 @@ using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Sorting
{
/// <summary>
- /// Class RandomComparer
+ /// Class RandomComparer.
/// </summary>
public class RandomComparer : IBaseItemComparer
{
diff --git a/Emby.Server.Implementations/Sorting/RuntimeComparer.cs b/Emby.Server.Implementations/Sorting/RuntimeComparer.cs
index 1d2bdde26..f165123ea 100644
--- a/Emby.Server.Implementations/Sorting/RuntimeComparer.cs
+++ b/Emby.Server.Implementations/Sorting/RuntimeComparer.cs
@@ -6,7 +6,7 @@ using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Sorting
{
/// <summary>
- /// Class RuntimeComparer
+ /// Class RuntimeComparer.
/// </summary>
public class RuntimeComparer : IBaseItemComparer
{
diff --git a/Emby.Server.Implementations/Sorting/SortNameComparer.cs b/Emby.Server.Implementations/Sorting/SortNameComparer.cs
index cc0571c78..93389fc3e 100644
--- a/Emby.Server.Implementations/Sorting/SortNameComparer.cs
+++ b/Emby.Server.Implementations/Sorting/SortNameComparer.cs
@@ -6,7 +6,7 @@ using MediaBrowser.Model.Querying;
namespace Emby.Server.Implementations.Sorting
{
/// <summary>
- /// Class SortNameComparer
+ /// Class SortNameComparer.
/// </summary>
public class SortNameComparer : IBaseItemComparer
{
diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs
index d0812a13f..b1f8fd330 100644
--- a/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs
+++ b/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs
@@ -102,20 +102,15 @@ namespace Emby.Server.Implementations.SyncPlay
return new SessionInfo[] { from };
case BroadcastType.AllGroup:
return _group.Participants.Values.Select(
- session => session.Session
- ).ToArray();
+ session => session.Session).ToArray();
case BroadcastType.AllExceptCurrentSession:
return _group.Participants.Values.Select(
- session => session.Session
- ).Where(
- session => !session.Id.Equals(from.Id)
- ).ToArray();
+ session => session.Session).Where(
+ session => !session.Id.Equals(from.Id)).ToArray();
case BroadcastType.AllReady:
return _group.Participants.Values.Where(
- session => !session.IsBuffering
- ).Select(
- session => session.Session
- ).ToArray();
+ session => !session.IsBuffering).Select(
+ session => session.Session).ToArray();
default:
return Array.Empty<SessionInfo>();
}
@@ -314,8 +309,7 @@ namespace Emby.Server.Implementations.SyncPlay
// Playback synchronization will mainly happen client side
_group.IsPaused = false;
_group.LastActivity = DateTime.UtcNow.AddMilliseconds(
- delay
- );
+ delay);
var command = NewSyncPlayCommand(SendCommandType.Play);
SendCommand(session, BroadcastType.AllGroup, command, cancellationToken);
@@ -449,8 +443,7 @@ namespace Emby.Server.Implementations.SyncPlay
{
// Client that was buffering is recovering, notifying others to resume
_group.LastActivity = currentTime.AddMilliseconds(
- delay
- );
+ delay);
var command = NewSyncPlayCommand(SendCommandType.Play);
SendCommand(session, BroadcastType.AllExceptCurrentSession, command, cancellationToken);
}
@@ -461,8 +454,7 @@ namespace Emby.Server.Implementations.SyncPlay
delay = delay < _group.DefaulPing ? _group.DefaulPing : delay;
_group.LastActivity = currentTime.AddMilliseconds(
- delay
- );
+ delay);
var command = NewSyncPlayCommand(SendCommandType.Play);
SendCommand(session, BroadcastType.AllGroup, command, cancellationToken);
diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs
index 1bfc9a9a5..45a43fd78 100644
--- a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs
+++ b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs
@@ -3,13 +3,13 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading;
-using Microsoft.Extensions.Logging;
-using MediaBrowser.Controller.Entities;
+using Jellyfin.Data.Entities;
+using Jellyfin.Data.Enums;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Session;
using MediaBrowser.Controller.SyncPlay;
-using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.SyncPlay;
+using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.SyncPlay
{
@@ -109,14 +109,6 @@ namespace Emby.Server.Implementations.SyncPlay
_disposed = true;
}
- private void CheckDisposed()
- {
- if (_disposed)
- {
- throw new ObjectDisposedException(GetType().Name);
- }
- }
-
private void OnSessionManagerSessionEnded(object sender, SessionEventArgs e)
{
var session = e.SessionInfo;
@@ -149,38 +141,24 @@ namespace Emby.Server.Implementations.SyncPlay
var item = _libraryManager.GetItemById(itemId);
// Check ParentalRating access
- var hasParentalRatingAccess = true;
- if (user.Policy.MaxParentalRating.HasValue)
- {
- hasParentalRatingAccess = item.InheritedParentalRatingValue <= user.Policy.MaxParentalRating;
- }
+ var hasParentalRatingAccess = !user.MaxParentalAgeRating.HasValue
+ || item.InheritedParentalRatingValue <= user.MaxParentalAgeRating;
- if (!user.Policy.EnableAllFolders && hasParentalRatingAccess)
+ if (!user.HasPermission(PermissionKind.EnableAllFolders) && hasParentalRatingAccess)
{
var collections = _libraryManager.GetCollectionFolders(item).Select(
- folder => folder.Id.ToString("N", CultureInfo.InvariantCulture)
- );
- var intersect = collections.Intersect(user.Policy.EnabledFolders);
- return intersect.Any();
- }
- else
- {
- return hasParentalRatingAccess;
+ folder => folder.Id.ToString("N", CultureInfo.InvariantCulture));
+
+ return collections.Intersect(user.GetPreference(PreferenceKind.EnabledFolders)).Any();
}
+
+ return hasParentalRatingAccess;
}
private Guid? GetSessionGroup(SessionInfo session)
{
- ISyncPlayController group;
- _sessionToGroupMap.TryGetValue(session.Id, out group);
- if (group != null)
- {
- return group.GetGroupId();
- }
- else
- {
- return null;
- }
+ _sessionToGroupMap.TryGetValue(session.Id, out var group);
+ return group?.GetGroupId();
}
/// <inheritdoc />
@@ -188,7 +166,7 @@ namespace Emby.Server.Implementations.SyncPlay
{
var user = _userManager.GetUserById(session.UserId);
- if (user.Policy.SyncPlayAccess != SyncPlayAccess.CreateAndJoinGroups)
+ if (user.SyncPlayAccess != SyncPlayAccess.CreateAndJoinGroups)
{
_logger.LogWarning("NewGroup: {0} does not have permission to create groups.", session.Id);
@@ -196,7 +174,7 @@ namespace Emby.Server.Implementations.SyncPlay
{
Type = GroupUpdateType.CreateGroupDenied
};
- _sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None);
+ _sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
return;
}
@@ -219,7 +197,7 @@ namespace Emby.Server.Implementations.SyncPlay
{
var user = _userManager.GetUserById(session.UserId);
- if (user.Policy.SyncPlayAccess == SyncPlayAccess.None)
+ if (user.SyncPlayAccess == SyncPlayAccess.None)
{
_logger.LogWarning("JoinGroup: {0} does not have access to SyncPlay.", session.Id);
@@ -227,7 +205,7 @@ namespace Emby.Server.Implementations.SyncPlay
{
Type = GroupUpdateType.JoinGroupDenied
};
- _sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None);
+ _sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
return;
}
@@ -244,7 +222,7 @@ namespace Emby.Server.Implementations.SyncPlay
{
Type = GroupUpdateType.GroupDoesNotExist
};
- _sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None);
+ _sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
return;
}
@@ -257,7 +235,7 @@ namespace Emby.Server.Implementations.SyncPlay
GroupId = group.GetGroupId().ToString(),
Type = GroupUpdateType.LibraryAccessDenied
};
- _sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None);
+ _sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
return;
}
@@ -281,8 +259,7 @@ namespace Emby.Server.Implementations.SyncPlay
// TODO: determine what happens to users that are in a group and get their permissions revoked
lock (_groupsLock)
{
- ISyncPlayController group;
- _sessionToGroupMap.TryGetValue(session.Id, out group);
+ _sessionToGroupMap.TryGetValue(session.Id, out var group);
if (group == null)
{
@@ -292,7 +269,7 @@ namespace Emby.Server.Implementations.SyncPlay
{
Type = GroupUpdateType.NotInGroup
};
- _sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None);
+ _sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
return;
}
@@ -311,7 +288,7 @@ namespace Emby.Server.Implementations.SyncPlay
{
var user = _userManager.GetUserById(session.UserId);
- if (user.Policy.SyncPlayAccess == SyncPlayAccess.None)
+ if (user.SyncPlayAccess == SyncPlayAccess.None)
{
return new List<GroupInfoView>();
}
@@ -320,19 +297,15 @@ namespace Emby.Server.Implementations.SyncPlay
if (!filterItemId.Equals(Guid.Empty))
{
return _groups.Values.Where(
- group => group.GetPlayingItemId().Equals(filterItemId) && HasAccessToItem(user, group.GetPlayingItemId())
- ).Select(
- group => group.GetInfo()
- ).ToList();
+ group => group.GetPlayingItemId().Equals(filterItemId) && HasAccessToItem(user, group.GetPlayingItemId())).Select(
+ group => group.GetInfo()).ToList();
}
// Otherwise show all available groups
else
{
return _groups.Values.Where(
- group => HasAccessToItem(user, group.GetPlayingItemId())
- ).Select(
- group => group.GetInfo()
- ).ToList();
+ group => HasAccessToItem(user, group.GetPlayingItemId())).Select(
+ group => group.GetInfo()).ToList();
}
}
@@ -341,7 +314,7 @@ namespace Emby.Server.Implementations.SyncPlay
{
var user = _userManager.GetUserById(session.UserId);
- if (user.Policy.SyncPlayAccess == SyncPlayAccess.None)
+ if (user.SyncPlayAccess == SyncPlayAccess.None)
{
_logger.LogWarning("HandleRequest: {0} does not have access to SyncPlay.", session.Id);
@@ -349,14 +322,13 @@ namespace Emby.Server.Implementations.SyncPlay
{
Type = GroupUpdateType.JoinGroupDenied
};
- _sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None);
+ _sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
return;
}
lock (_groupsLock)
{
- ISyncPlayController group;
- _sessionToGroupMap.TryGetValue(session.Id, out group);
+ _sessionToGroupMap.TryGetValue(session.Id, out var group);
if (group == null)
{
@@ -366,7 +338,7 @@ namespace Emby.Server.Implementations.SyncPlay
{
Type = GroupUpdateType.NotInGroup
};
- _sessionManager.SendSyncPlayGroupUpdate(session.Id.ToString(), error, CancellationToken.None);
+ _sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
return;
}
@@ -393,8 +365,7 @@ namespace Emby.Server.Implementations.SyncPlay
throw new InvalidOperationException("Session not in any group!");
}
- ISyncPlayController tempGroup;
- _sessionToGroupMap.Remove(session.Id, out tempGroup);
+ _sessionToGroupMap.Remove(session.Id, out var tempGroup);
if (!tempGroup.GetGroupId().Equals(group.GetGroupId()))
{
diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs
index 383615f74..21c12ae79 100644
--- a/Emby.Server.Implementations/TV/TVSeriesManager.cs
+++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs
@@ -4,13 +4,17 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
+using Jellyfin.Data.Entities;
+using Jellyfin.Data.Enums;
+using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Dto;
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Entities.TV;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.TV;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
+using Episode = MediaBrowser.Controller.Entities.TV.Episode;
+using Series = MediaBrowser.Controller.Entities.TV.Series;
namespace Emby.Server.Implementations.TV
{
@@ -73,7 +77,8 @@ namespace Emby.Server.Implementations.TV
{
parents = _libraryManager.GetUserRootFolder().GetChildren(user, true)
.Where(i => i is Folder)
- .Where(i => !user.Configuration.LatestItemsExcludes.Contains(i.Id.ToString("N", CultureInfo.InvariantCulture)))
+ .Where(i => !user.GetPreference(PreferenceKind.LatestItemExcludes)
+ .Contains(i.Id.ToString("N", CultureInfo.InvariantCulture)))
.ToArray();
}
@@ -144,7 +149,7 @@ namespace Emby.Server.Implementations.TV
var allNextUp = seriesKeys
.Select(i => GetNextUp(i, currentUser, dtoOptions));
- //allNextUp = allNextUp.OrderByDescending(i => i.Item1);
+ // allNextUp = allNextUp.OrderByDescending(i => i.Item1);
// If viewing all next up for all series, remove first episodes
// But if that returns empty, keep those first episodes (avoid completely empty view)
@@ -191,7 +196,7 @@ namespace Emby.Server.Implementations.TV
{
AncestorWithPresentationUniqueKey = null,
SeriesPresentationUniqueKey = seriesKey,
- IncludeItemTypes = new[] { typeof(Episode).Name },
+ IncludeItemTypes = new[] { nameof(Episode) },
OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Descending) },
IsPlayed = true,
Limit = 1,
@@ -204,7 +209,6 @@ namespace Emby.Server.Implementations.TV
},
EnableImages = false
}
-
}).FirstOrDefault();
Func<Episode> getEpisode = () =>
@@ -219,9 +223,8 @@ namespace Emby.Server.Implementations.TV
IsPlayed = false,
IsVirtualItem = false,
ParentIndexNumberNotEquals = 0,
- MinSortName = lastWatchedEpisode == null ? null : lastWatchedEpisode.SortName,
+ MinSortName = lastWatchedEpisode?.SortName,
DtoOptions = dtoOptions
-
}).Cast<Episode>().FirstOrDefault();
};
@@ -253,6 +256,7 @@ namespace Emby.Server.Implementations.TV
{
items = items.Skip(query.StartIndex.Value);
}
+
if (query.Limit.HasValue)
{
items = items.Take(query.Limit.Value);
diff --git a/Emby.Server.Implementations/Udp/UdpServer.cs b/Emby.Server.Implementations/Udp/UdpServer.cs
index a26f714b1..bf8a436b4 100644
--- a/Emby.Server.Implementations/Udp/UdpServer.cs
+++ b/Emby.Server.Implementations/Udp/UdpServer.cs
@@ -18,7 +18,7 @@ namespace Emby.Server.Implementations.Udp
public sealed class UdpServer : IDisposable
{
/// <summary>
- /// The _logger
+ /// The _logger.
/// </summary>
private readonly ILogger _logger;
private readonly IServerApplicationHost _appHost;