aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations
diff options
context:
space:
mode:
authorDavid <daullmer@gmail.com>2020-07-21 21:56:24 +0200
committerDavid <daullmer@gmail.com>2020-07-21 21:56:24 +0200
commitbe8cf1e9ef5f24903c406f5cdbe985e84ffeb102 (patch)
treeb3a925ec3cf8afd8a04eeaad94861b258dfec70f /Emby.Server.Implementations
parent9a2bcd6266fb222491abe6ea31d5e7e734699d5f (diff)
parent5b57c81ee14ce585161b9ac331e6e3528826b815 (diff)
Merge branch 'api-migration' into api-syncplay
# Conflicts: # MediaBrowser.Api/SyncPlay/SyncPlayService.cs
Diffstat (limited to 'Emby.Server.Implementations')
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs39
-rw-r--r--Emby.Server.Implementations/Channels/ChannelManager.cs2
-rw-r--r--Emby.Server.Implementations/Collections/CollectionManager.cs56
-rw-r--r--Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs57
-rw-r--r--Emby.Server.Implementations/ConfigurationOptions.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.cs6
-rw-r--r--Emby.Server.Implementations/Data/SqliteItemRepository.cs231
-rw-r--r--Emby.Server.Implementations/Data/SqliteUserDataRepository.cs11
-rw-r--r--Emby.Server.Implementations/Devices/DeviceManager.cs3
-rw-r--r--Emby.Server.Implementations/Dto/DtoService.cs40
-rw-r--r--Emby.Server.Implementations/Emby.Server.Implementations.csproj14
-rw-r--r--Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs1
-rw-r--r--Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs2
-rw-r--r--Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs14
-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.cs14
-rw-r--r--Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs181
-rw-r--r--Emby.Server.Implementations/HttpServer/ResponseFilter.cs4
-rw-r--r--Emby.Server.Implementations/IO/LibraryMonitor.cs2
-rw-r--r--Emby.Server.Implementations/IO/ManagedFileSystem.cs14
-rw-r--r--Emby.Server.Implementations/IStartupOptions.cs5
-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.cs14
-rw-r--r--Emby.Server.Implementations/Library/ExclusiveLiveStream.cs2
-rw-r--r--Emby.Server.Implementations/Library/IgnorePatterns.cs50
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs99
-rw-r--r--Emby.Server.Implementations/Library/LiveStreamHelper.cs7
-rw-r--r--Emby.Server.Implementations/Library/MediaSourceManager.cs14
-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/Books/BookResolver.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.cs5
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/SeriesResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/SearchEngine.cs2
-rw-r--r--Emby.Server.Implementations/Library/UserDataManager.cs4
-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.cs32
-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.cs37
-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/af.json10
-rw-r--r--Emby.Server.Implementations/Localization/Core/ar.json6
-rw-r--r--Emby.Server.Implementations/Localization/Core/bn.json19
-rw-r--r--Emby.Server.Implementations/Localization/Core/de.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/es-AR.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/es-MX.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/es_419.json2
-rw-r--r--Emby.Server.Implementations/Localization/Core/fr-CA.json5
-rw-r--r--Emby.Server.Implementations/Localization/Core/hr.json52
-rw-r--r--Emby.Server.Implementations/Localization/Core/mr.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/ms.json64
-rw-r--r--Emby.Server.Implementations/Localization/Core/ne.json86
-rw-r--r--Emby.Server.Implementations/Localization/Core/pt.json16
-rw-r--r--Emby.Server.Implementations/Localization/Core/th.json4
-rw-r--r--Emby.Server.Implementations/Localization/Core/zh-HK.json5
-rw-r--r--Emby.Server.Implementations/Net/SocketFactory.cs7
-rw-r--r--Emby.Server.Implementations/Net/UdpSocket.cs10
-rw-r--r--Emby.Server.Implementations/Networking/NetworkManager.cs200
-rw-r--r--Emby.Server.Implementations/Playlists/PlaylistManager.cs15
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/ScheduledTaskWorker.cs23
-rw-r--r--Emby.Server.Implementations/ScheduledTasks/TaskManager.cs10
-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.cs8
-rw-r--r--Emby.Server.Implementations/Services/ResponseHelper.cs6
-rw-r--r--Emby.Server.Implementations/Services/ServiceController.cs11
-rw-r--r--Emby.Server.Implementations/Services/ServiceExec.cs9
-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.cs28
-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.cs7
-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.cs6
-rw-r--r--Emby.Server.Implementations/Sorting/DatePlayedComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/NameComparer.cs2
-rw-r--r--Emby.Server.Implementations/Sorting/PlayCountComparer.cs2
-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.cs6
-rw-r--r--Emby.Server.Implementations/Sorting/SortNameComparer.cs6
-rw-r--r--Emby.Server.Implementations/SyncPlay/SyncPlayController.cs56
-rw-r--r--Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs22
-rw-r--r--Emby.Server.Implementations/TV/TVSeriesManager.cs33
-rw-r--r--Emby.Server.Implementations/Udp/UdpServer.cs13
-rw-r--r--Emby.Server.Implementations/Updates/InstallationManager.cs63
119 files changed, 1317 insertions, 803 deletions
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index 25ee7e9ec..17208d97d 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -43,9 +43,9 @@ using Emby.Server.Implementations.Security;
using Emby.Server.Implementations.Serialization;
using Emby.Server.Implementations.Services;
using Emby.Server.Implementations.Session;
+using Emby.Server.Implementations.SyncPlay;
using Emby.Server.Implementations.TV;
using Emby.Server.Implementations.Updates;
-using Emby.Server.Implementations.SyncPlay;
using MediaBrowser.Api;
using MediaBrowser.Common;
using MediaBrowser.Common.Configuration;
@@ -78,8 +78,8 @@ using MediaBrowser.Controller.Security;
using MediaBrowser.Controller.Session;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Controller.Subtitles;
-using MediaBrowser.Controller.TV;
using MediaBrowser.Controller.SyncPlay;
+using MediaBrowser.Controller.TV;
using MediaBrowser.LocalMetadata.Savers;
using MediaBrowser.MediaEncoding.BdInfo;
using MediaBrowser.Model.Configuration;
@@ -483,12 +483,10 @@ namespace Emby.Server.Implementations
foreach (var plugin in Plugins)
{
- pluginBuilder.AppendLine(
- string.Format(
- CultureInfo.InvariantCulture,
- "{0} {1}",
- plugin.Name,
- plugin.Version));
+ pluginBuilder.Append(plugin.Name)
+ .Append(' ')
+ .Append(plugin.Version)
+ .AppendLine();
}
Logger.LogInformation("Plugins: {Plugins}", pluginBuilder.ToString());
@@ -565,10 +563,8 @@ namespace Emby.Server.Implementations
serviceCollection.AddTransient(provider => new Lazy<IDtoService>(provider.GetRequiredService<IDtoService>));
// 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
serviceCollection.AddTransient(provider => new Lazy<EncodingHelper>(provider.GetRequiredService<EncodingHelper>));
- serviceCollection.AddSingleton<IMediaEncoder>(provider =>
- ActivatorUtilities.CreateInstance<MediaBrowser.MediaEncoding.Encoder.MediaEncoder>(provider, _startupOptions.FFmpegPath ?? string.Empty));
+ serviceCollection.AddSingleton<IMediaEncoder, MediaBrowser.MediaEncoding.Encoder.MediaEncoder>();
// TODO: Refactor to eliminate the circular dependencies here so that Lazy<T> isn't required
serviceCollection.AddTransient(provider => new Lazy<ILibraryMonitor>(provider.GetRequiredService<ILibraryMonitor>));
@@ -872,6 +868,11 @@ namespace Emby.Server.Implementations
Logger.LogError(ex, "Error getting exported types from {Assembly}", ass.FullName);
continue;
}
+ catch (TypeLoadException ex)
+ {
+ Logger.LogError(ex, "Error loading types from {Assembly}.", ass.FullName);
+ continue;
+ }
foreach (Type type in exportedTypes)
{
@@ -955,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()
{
@@ -1151,7 +1152,7 @@ namespace Emby.Server.Implementations
return null;
}
- return GetLocalApiUrl(addresses.First());
+ return GetLocalApiUrl(addresses[0]);
}
catch (Exception ex)
{
@@ -1224,13 +1225,13 @@ namespace Emby.Server.Implementations
var addresses = ServerConfigurationManager
.Configuration
.LocalNetworkAddresses
- .Select(NormalizeConfiguredLocalAddress)
+ .Select(x => NormalizeConfiguredLocalAddress(x))
.Where(i => i != null)
.ToList();
if (addresses.Count == 0)
{
- addresses.AddRange(_networkManager.GetLocalIpAddresses(ServerConfigurationManager.Configuration.IgnoreVirtualInterfaces));
+ addresses.AddRange(_networkManager.GetLocalIpAddresses());
}
var resultList = new List<IPAddress>();
@@ -1245,8 +1246,7 @@ namespace Emby.Server.Implementations
}
}
- var valid = await IsLocalIpAddressValidAsync(address, cancellationToken).ConfigureAwait(false);
- if (valid)
+ if (await IsLocalIpAddressValidAsync(address, cancellationToken).ConfigureAwait(false))
{
resultList.Add(address);
@@ -1260,13 +1260,12 @@ namespace Emby.Server.Implementations
return resultList;
}
- public IPAddress NormalizeConfiguredLocalAddress(string address)
+ public IPAddress NormalizeConfiguredLocalAddress(ReadOnlySpan<char> address)
{
var index = address.Trim('/').IndexOf('/');
-
if (index != -1)
{
- address = address.Substring(index + 1);
+ address = address.Slice(index + 1);
}
if (IPAddress.TryParse(address.Trim('/'), out IPAddress result))
diff --git a/Emby.Server.Implementations/Channels/ChannelManager.cs b/Emby.Server.Implementations/Channels/ChannelManager.cs
index 519c5bbef..c803d9d82 100644
--- a/Emby.Server.Implementations/Channels/ChannelManager.cs
+++ b/Emby.Server.Implementations/Channels/ChannelManager.cs
@@ -1072,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 8fb9520d6..ac2edc1e2 100644
--- a/Emby.Server.Implementations/Collections/CollectionManager.cs
+++ b/Emby.Server.Implementations/Collections/CollectionManager.cs
@@ -363,60 +363,4 @@ namespace Emby.Server.Implementations.Collections
return results.Values;
}
}
-
- /// <summary>
- /// The collection manager entry point.
- /// </summary>
- public sealed class CollectionManagerEntryPoint : IServerEntryPoint
- {
- private readonly CollectionManager _collectionManager;
- private readonly IServerConfigurationManager _config;
- private readonly ILogger<CollectionManagerEntryPoint> _logger;
-
- /// <summary>
- /// Initializes a new instance of the <see cref="CollectionManagerEntryPoint"/> class.
- /// </summary>
- /// <param name="collectionManager">The collection manager.</param>
- /// <param name="config">The server configuration manager.</param>
- /// <param name="logger">The logger.</param>
- public CollectionManagerEntryPoint(
- ICollectionManager collectionManager,
- IServerConfigurationManager config,
- ILogger<CollectionManagerEntryPoint> logger)
- {
- _collectionManager = (CollectionManager)collectionManager;
- _config = config;
- _logger = logger;
- }
-
- /// <inheritdoc />
- public async Task RunAsync()
- {
- if (!_config.Configuration.CollectionsUpgraded && _config.Configuration.IsStartupWizardCompleted)
- {
- var path = _collectionManager.GetCollectionsFolderPath();
-
- if (Directory.Exists(path))
- {
- try
- {
- await _collectionManager.EnsureLibraryFolder(path, true).ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, "Error creating camera uploads library");
- }
-
- _config.Configuration.CollectionsUpgraded = true;
- _config.SaveConfiguration();
- }
- }
- }
-
- /// <inheritdoc />
- public void Dispose()
- {
- // Nothing to dispose
- }
- }
}
diff --git a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
index 94ee1ced7..a15295fca 100644
--- a/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
+++ b/Emby.Server.Implementations/Configuration/ServerConfigurationManager.cs
@@ -109,7 +109,6 @@ namespace Emby.Server.Implementations.Configuration
if (!string.IsNullOrWhiteSpace(newPath)
&& !string.Equals(Configuration.CertificatePath, newPath, StringComparison.Ordinal))
{
- // Validate
if (!File.Exists(newPath))
{
throw new FileNotFoundException(
@@ -133,7 +132,6 @@ namespace Emby.Server.Implementations.Configuration
if (!string.IsNullOrWhiteSpace(newPath)
&& !string.Equals(Configuration.MetadataPath, newPath, StringComparison.Ordinal))
{
- // Validate
if (!Directory.Exists(newPath))
{
throw new DirectoryNotFoundException(
@@ -146,60 +144,5 @@ namespace Emby.Server.Implementations.Configuration
EnsureWriteAccess(newPath);
}
}
-
- /// <summary>
- /// Sets all configuration values to their optimal values.
- /// </summary>
- /// <returns>If the configuration changed.</returns>
- public bool SetOptimalValues()
- {
- var config = Configuration;
-
- var changed = false;
-
- if (!config.EnableCaseSensitiveItemIds)
- {
- config.EnableCaseSensitiveItemIds = true;
- changed = true;
- }
-
- if (!config.SkipDeserializationForBasicTypes)
- {
- config.SkipDeserializationForBasicTypes = true;
- changed = true;
- }
-
- if (!config.EnableSimpleArtistDetection)
- {
- config.EnableSimpleArtistDetection = true;
- changed = true;
- }
-
- if (!config.EnableNormalizedItemByNameIds)
- {
- config.EnableNormalizedItemByNameIds = true;
- changed = true;
- }
-
- if (!config.DisableLiveTvChannelUserDataName)
- {
- config.DisableLiveTvChannelUserDataName = true;
- changed = true;
- }
-
- if (!config.EnableNewOmdbSupport)
- {
- config.EnableNewOmdbSupport = true;
- changed = true;
- }
-
- if (!config.CollectionsUpgraded)
- {
- config.CollectionsUpgraded = true;
- changed = true;
- }
-
- return changed;
- }
}
}
diff --git a/Emby.Server.Implementations/ConfigurationOptions.cs b/Emby.Server.Implementations/ConfigurationOptions.cs
index dea9b6682..ff7ee085f 100644
--- a/Emby.Server.Implementations/ConfigurationOptions.cs
+++ b/Emby.Server.Implementations/ConfigurationOptions.cs
@@ -17,7 +17,6 @@ namespace Emby.Server.Implementations
{
{ HostWebClientKey, bool.TrueString },
{ HttpListenerHost.DefaultRedirectKey, "web/index.html" },
- { InstallationManager.PluginManifestUrlKey, "https://repo.jellyfin.org/releases/plugin/manifest-stable.json" },
{ FfmpegProbeSizeKey, "1G" },
{ FfmpegAnalyzeDurationKey, "200M" },
{ PlaylistsAllowDuplicatesKey, bool.TrueString }
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 63d0321b7..5597155a8 100644
--- a/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs
@@ -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..a6390b1ef 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 + "%");
@@ -2706,22 +2775,85 @@ namespace Emby.Server.Implementations.Data
private string FixUnicodeChars(string buffer)
{
- if (buffer.IndexOf('\u2013') > -1) buffer = buffer.Replace('\u2013', '-'); // en dash
- if (buffer.IndexOf('\u2014') > -1) buffer = buffer.Replace('\u2014', '-'); // em dash
- if (buffer.IndexOf('\u2015') > -1) buffer = buffer.Replace('\u2015', '-'); // horizontal bar
- if (buffer.IndexOf('\u2017') > -1) buffer = buffer.Replace('\u2017', '_'); // double low line
- if (buffer.IndexOf('\u2018') > -1) buffer = buffer.Replace('\u2018', '\''); // left single quotation mark
- if (buffer.IndexOf('\u2019') > -1) buffer = buffer.Replace('\u2019', '\''); // right single quotation mark
- if (buffer.IndexOf('\u201a') > -1) buffer = buffer.Replace('\u201a', ','); // single low-9 quotation mark
- if (buffer.IndexOf('\u201b') > -1) buffer = buffer.Replace('\u201b', '\''); // single high-reversed-9 quotation mark
- if (buffer.IndexOf('\u201c') > -1) buffer = buffer.Replace('\u201c', '\"'); // left double quotation mark
- if (buffer.IndexOf('\u201d') > -1) buffer = buffer.Replace('\u201d', '\"'); // right double quotation mark
- if (buffer.IndexOf('\u201e') > -1) buffer = buffer.Replace('\u201e', '\"'); // double low-9 quotation mark
- if (buffer.IndexOf('\u2026') > -1) buffer = buffer.Replace("\u2026", "..."); // horizontal ellipsis
- if (buffer.IndexOf('\u2032') > -1) buffer = buffer.Replace('\u2032', '\''); // prime
- if (buffer.IndexOf('\u2033') > -1) buffer = buffer.Replace('\u2033', '\"'); // double prime
- if (buffer.IndexOf('\u0060') > -1) buffer = buffer.Replace('\u0060', '\''); // grave accent
- if (buffer.IndexOf('\u00B4') > -1) buffer = buffer.Replace('\u00B4', '\''); // acute accent
+ if (buffer.IndexOf('\u2013') > -1)
+ {
+ buffer = buffer.Replace('\u2013', '-'); // en dash
+ }
+
+ if (buffer.IndexOf('\u2014') > -1)
+ {
+ buffer = buffer.Replace('\u2014', '-'); // em dash
+ }
+
+ if (buffer.IndexOf('\u2015') > -1)
+ {
+ buffer = buffer.Replace('\u2015', '-'); // horizontal bar
+ }
+
+ if (buffer.IndexOf('\u2017') > -1)
+ {
+ buffer = buffer.Replace('\u2017', '_'); // double low line
+ }
+
+ if (buffer.IndexOf('\u2018') > -1)
+ {
+ buffer = buffer.Replace('\u2018', '\''); // left single quotation mark
+ }
+
+ if (buffer.IndexOf('\u2019') > -1)
+ {
+ buffer = buffer.Replace('\u2019', '\''); // right single quotation mark
+ }
+
+ if (buffer.IndexOf('\u201a') > -1)
+ {
+ buffer = buffer.Replace('\u201a', ','); // single low-9 quotation mark
+ }
+
+ if (buffer.IndexOf('\u201b') > -1)
+ {
+ buffer = buffer.Replace('\u201b', '\''); // single high-reversed-9 quotation mark
+ }
+
+ if (buffer.IndexOf('\u201c') > -1)
+ {
+ buffer = buffer.Replace('\u201c', '\"'); // left double quotation mark
+ }
+
+ if (buffer.IndexOf('\u201d') > -1)
+ {
+ buffer = buffer.Replace('\u201d', '\"'); // right double quotation mark
+ }
+
+ if (buffer.IndexOf('\u201e') > -1)
+ {
+ buffer = buffer.Replace('\u201e', '\"'); // double low-9 quotation mark
+ }
+
+ if (buffer.IndexOf('\u2026') > -1)
+ {
+ buffer = buffer.Replace("\u2026", "..."); // horizontal ellipsis
+ }
+
+ if (buffer.IndexOf('\u2032') > -1)
+ {
+ buffer = buffer.Replace('\u2032', '\''); // prime
+ }
+
+ if (buffer.IndexOf('\u2033') > -1)
+ {
+ buffer = buffer.Replace('\u2033', '\"'); // double prime
+ }
+
+ if (buffer.IndexOf('\u0060') > -1)
+ {
+ buffer = buffer.Replace('\u0060', '\''); // grave accent
+ }
+
+ if (buffer.IndexOf('\u00B4') > -1)
+ {
+ buffer = buffer.Replace('\u00B4', '\''); // acute accent
+ }
return buffer;
}
@@ -2745,6 +2877,7 @@ namespace Emby.Server.Implementations.Data
{
items[i] = newItem;
}
+
return;
}
}
@@ -2837,6 +2970,7 @@ namespace Emby.Server.Implementations.Data
{
statementTexts.Add(commandText);
}
+
if (query.EnableTotalRecordCount)
{
commandText = string.Empty;
@@ -3241,6 +3375,7 @@ namespace Emby.Server.Implementations.Data
{
statementTexts.Add(commandText);
}
+
if (query.EnableTotalRecordCount)
{
commandText = string.Empty;
@@ -3594,11 +3729,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 +4021,7 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, artistId.ToByteArray());
}
+
index++;
}
@@ -3904,6 +4042,7 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, artistId.ToByteArray());
}
+
index++;
}
@@ -3924,8 +4063,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, artistId.ToByteArray());
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -3943,8 +4084,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, albumId.ToByteArray());
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -3962,8 +4105,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, artistId.ToByteArray());
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -3981,8 +4126,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, genreId.ToByteArray());
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -3998,8 +4145,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind("@Genre" + index, GetCleanValue(item));
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -4015,8 +4164,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind("@Tag" + index, GetCleanValue(item));
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -4032,8 +4183,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind("@ExcludeTag" + index, GetCleanValue(item));
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -4052,8 +4205,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, studioId.ToByteArray());
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -4069,8 +4224,10 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind("@OfficialRating" + index, item);
}
+
index++;
}
+
var clause = "(" + string.Join(" OR ", clauses) + ")";
whereClauses.Add(clause);
}
@@ -4245,6 +4402,7 @@ namespace Emby.Server.Implementations.Data
statement.TryBind("@IsVirtualItem", isVirtualItem.Value);
}
}
+
if (query.IsSpecialSeason.HasValue)
{
if (query.IsSpecialSeason.Value)
@@ -4256,6 +4414,7 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add("IndexNumber <> 0");
}
}
+
if (query.IsUnaired.HasValue)
{
if (query.IsUnaired.Value)
@@ -4267,6 +4426,7 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add("PremiereDate < DATETIME('now')");
}
}
+
var queryMediaTypes = query.MediaTypes.Where(IsValidMediaType).ToArray();
if (queryMediaTypes.Length == 1)
{
@@ -4282,6 +4442,7 @@ namespace Emby.Server.Implementations.Data
whereClauses.Add("MediaType in (" + val + ")");
}
+
if (query.ItemIds.Length > 0)
{
var includeIds = new List<string>();
@@ -4294,11 +4455,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 +4474,7 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind("@ExcludeId" + index, id);
}
+
index++;
}
@@ -4335,6 +4499,7 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, "%" + pair.Key + "=" + pair.Value + "%");
}
+
index++;
break;
@@ -4360,7 +4525,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 +4542,7 @@ namespace Emby.Server.Implementations.Data
{
statement.TryBind(paramName, "%" + pair.Key + "=" + pair.Value + "%");
}
+
index++;
break;
@@ -4427,6 +4593,7 @@ namespace Emby.Server.Implementations.Data
{
whereClauses.Add("(TopParentId=@TopParentId)");
}
+
if (statement != null)
{
statement.TryBind("@TopParentId", queryTopParentIds[0].ToString("N", CultureInfo.InvariantCulture));
@@ -4464,11 +4631,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 +4666,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 +4959,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
connection.RunInTransaction(db =>
{
connection.ExecuteAll(sql);
-
}, TransactionMode);
}
}
@@ -4972,6 +5141,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 +5150,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 +5167,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 +5184,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 +5193,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 +5333,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 +5355,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
}
}
}
-
}
LogQueryTime("GetItemValueNames", commandText, now);
@@ -5631,7 +5805,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 +5961,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 +6306,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);
}
}
@@ -6200,7 +6371,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
/// Gets the attachment.
/// </summary>
/// <param name="reader">The reader.</param>
- /// <returns>MediaAttachment</returns>
+ /// <returns>MediaAttachment.</returns>
private MediaAttachment GetMediaAttachment(IReadOnlyList<IResultSetValue> reader)
{
var item = new MediaAttachment
diff --git a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
index b99b74ef8..4a78aac8e 100644
--- a/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
+++ b/Emby.Server.Implementations/Data/SqliteUserDataRepository.cs
@@ -135,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));
@@ -153,6 +155,7 @@ namespace Emby.Server.Implementations.Data
{
throw new ArgumentNullException(nameof(userData));
}
+
if (internalUserId <= 0)
{
throw new ArgumentNullException(nameof(internalUserId));
@@ -235,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)
{
@@ -309,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>
@@ -339,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)
@@ -347,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/Devices/DeviceManager.cs b/Emby.Server.Implementations/Devices/DeviceManager.cs
index f8896d69f..e75745cc6 100644
--- a/Emby.Server.Implementations/Devices/DeviceManager.cs
+++ b/Emby.Server.Implementations/Devices/DeviceManager.cs
@@ -112,7 +112,7 @@ namespace Emby.Server.Implementations.Devices
{
IEnumerable<AuthenticationInfo> sessions = _authRepo.Get(new AuthenticationInfoQuery
{
- //UserId = query.UserId
+ // UserId = query.UserId
HasUser = true
}).Items;
@@ -169,6 +169,7 @@ namespace Emby.Server.Implementations.Devices
{
throw new ArgumentException("user not found");
}
+
if (string.IsNullOrEmpty(deviceId))
{
throw new ArgumentNullException(nameof(deviceId));
diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs
index 7e0cfe424..c967e9230 100644
--- a/Emby.Server.Implementations/Dto/DtoService.cs
+++ b/Emby.Server.Implementations/Dto/DtoService.cs
@@ -74,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>
@@ -277,6 +277,7 @@ namespace Emby.Server.Implementations.Dto
dto.EpisodeTitle = dto.Name;
dto.Name = dto.SeriesName;
}
+
liveTvManager.AddInfoToRecordingDto(item, dto, activeRecording, user);
}
@@ -292,6 +293,7 @@ namespace Emby.Server.Implementations.Dto
{
continue;
}
+
var containers = container.Split(new[] { ',' });
if (containers.Length < 2)
{
@@ -406,7 +408,6 @@ namespace Emby.Server.Implementations.Dto
dto.DateLastMediaAdded = folder.DateLastMediaAdded;
}
}
-
else
{
if (options.EnableUserData)
@@ -443,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>
@@ -457,6 +458,7 @@ namespace Emby.Server.Implementations.Dto
{
dto.SeriesName = item.SeriesName;
}
+
private static void SetPhotoProperties(BaseItemDto dto, Photo item)
{
dto.CameraMake = item.CameraMake;
@@ -538,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>
@@ -555,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;
@@ -594,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())
@@ -615,6 +621,7 @@ namespace Emby.Server.Implementations.Dto
{
baseItemPerson.PrimaryImageTag = GetTagAndFillBlurhash(dto, entity, ImageType.Primary);
baseItemPerson.Id = entity.Id.ToString("N", CultureInfo.InvariantCulture);
+ baseItemPerson.ImageBlurHashes = dto.ImageBlurHashes;
list.Add(baseItemPerson);
}
}
@@ -727,7 +734,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>
@@ -947,7 +954,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
//}
@@ -957,13 +964,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;
@@ -976,7 +983,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 =>
@@ -1001,7 +1008,6 @@ namespace Emby.Server.Implementations.Dto
}
return null;
-
}).Where(i => i != null).ToArray();
}
@@ -1010,13 +1016,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;
@@ -1052,7 +1058,6 @@ namespace Emby.Server.Implementations.Dto
}
return null;
-
}).Where(i => i != null).ToArray();
}
@@ -1166,7 +1171,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)
@@ -1212,7 +1217,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)
@@ -1350,6 +1355,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);
@@ -1360,6 +1366,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);
@@ -1370,6 +1377,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 5272e2692..adae920dc 100644
--- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj
+++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj
@@ -23,8 +23,8 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="IPNetwork2" Version="2.4.0.126" />
- <PackageReference Include="Jellyfin.XmlTv" Version="10.4.3" />
+ <PackageReference Include="IPNetwork2" Version="2.5.211" />
+ <PackageReference Include="Jellyfin.XmlTv" Version="10.6.0-pre1" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Server.Abstractions" Version="2.2.0" />
@@ -33,14 +33,14 @@
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.WebSockets" Version="2.2.1" />
- <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.5" />
- <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.5" />
- <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.5" />
- <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.5" />
+ <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.1.6" />
+ <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.1.6" />
+ <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.1.6" />
+ <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.6" />
<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 02ae55071..c1068522a 100644
--- a/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/LibraryChangedNotifier.cs
@@ -132,7 +132,6 @@ namespace Emby.Server.Implementations.EntryPoints
}
catch
{
-
}
}
}
diff --git a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs
index 083fe4237..826d4d8dc 100644
--- a/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs
+++ b/Emby.Server.Implementations/EntryPoints/ServerEventNotifier.cs
@@ -159,7 +159,6 @@ namespace Emby.Server.Implementations.EntryPoints
}
catch (Exception)
{
-
}
}
@@ -175,7 +174,6 @@ namespace Emby.Server.Implementations.EntryPoints
}
catch (Exception)
{
-
}
}
diff --git a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
index ecdce89ce..9486874d5 100644
--- a/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
+++ b/Emby.Server.Implementations/EntryPoints/UdpServerEntryPoint.cs
@@ -1,3 +1,4 @@
+using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Emby.Server.Implementations.Udp;
@@ -43,14 +44,21 @@ namespace Emby.Server.Implementations.EntryPoints
_logger = logger;
_appHost = appHost;
_config = configuration;
-
}
/// <inheritdoc />
public Task RunAsync()
{
- _udpServer = new UdpServer(_logger, _appHost, _config);
- _udpServer.Start(PortNumber, _cancellationTokenSource.Token);
+ try
+ {
+ _udpServer = new UdpServer(_logger, _appHost, _config);
+ _udpServer.Start(PortNumber, _cancellationTokenSource.Token);
+ }
+ catch (SocketException ex)
+ {
+ _logger.LogWarning(ex, "Unable to start AutoDiscovery listener on UDP port {PortNumber}", PortNumber);
+ }
+
return Task.CompletedTask;
}
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..970f5119c 100644
--- a/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
+++ b/Emby.Server.Implementations/HttpServer/HttpResultFactory.cs
@@ -426,7 +426,7 @@ namespace Emby.Server.Implementations.HttpServer
/// </summary>
private object GetCachedResult(IRequest requestContext, IDictionary<string, string> responseHeaders, StaticResultOptions options)
{
- bool noCache = (requestContext.Headers[HeaderNames.CacheControl].ToString()).IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1;
+ bool noCache = requestContext.Headers[HeaderNames.CacheControl].ToString().IndexOf("no-cache", StringComparison.OrdinalIgnoreCase) != -1;
AddCachingHeaders(responseHeaders, options.CacheDuration, noCache, options.DateLastModified);
if (!noCache)
@@ -580,13 +580,12 @@ namespace Emby.Server.Implementations.HttpServer
}
catch (NotSupportedException)
{
-
}
}
if (!string.IsNullOrWhiteSpace(rangeHeader) && totalContentLength.HasValue)
{
- var hasHeaders = new RangeRequestWriter(rangeHeader, totalContentLength.Value, stream, contentType, isHeadRequest, _logger)
+ var hasHeaders = new RangeRequestWriter(rangeHeader, totalContentLength.Value, stream, contentType, isHeadRequest)
{
OnComplete = options.OnComplete
};
@@ -623,8 +622,11 @@ namespace Emby.Server.Implementations.HttpServer
/// <summary>
/// Adds the caching responseHeaders.
/// </summary>
- private void AddCachingHeaders(IDictionary<string, string> responseHeaders, TimeSpan? cacheDuration,
- bool noCache, DateTime? lastModifiedDate)
+ private void AddCachingHeaders(
+ IDictionary<string, string> responseHeaders,
+ TimeSpan? cacheDuration,
+ bool noCache,
+ DateTime? lastModifiedDate)
{
if (noCache)
{
@@ -693,7 +695,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..980c2cd3a 100644
--- a/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs
+++ b/Emby.Server.Implementations/HttpServer/RangeRequestWriter.cs
@@ -1,6 +1,7 @@
#pragma warning disable CS1591
using System;
+using System.Buffers;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@@ -8,46 +9,17 @@ using System.Net;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Model.Services;
-using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
namespace Emby.Server.Implementations.HttpServer
{
public class RangeRequestWriter : IAsyncStreamWriter, IHttpResult
{
- /// <summary>
- /// Gets or sets the source stream.
- /// </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
- /// </summary>
private readonly Dictionary<string, string> _options = new Dictionary<string, string>();
- /// <summary>
- /// The us culture
- /// </summary>
- private static readonly CultureInfo UsCulture = new CultureInfo("en-US");
-
- /// <summary>
- /// Additional HTTP Headers
- /// </summary>
- /// <value>The headers.</value>
- public IDictionary<string, string> Headers => _options;
+ private List<KeyValuePair<long, long?>> _requestedRanges;
/// <summary>
/// Initializes a new instance of the <see cref="RangeRequestWriter" /> class.
@@ -57,8 +29,7 @@ namespace Emby.Server.Implementations.HttpServer
/// <param name="source">The source.</param>
/// <param name="contentType">Type of the content.</param>
/// <param name="isHeadRequest">if set to <c>true</c> [is head request].</param>
- /// <param name="logger">The logger instance.</param>
- public RangeRequestWriter(string rangeHeader, long contentLength, Stream source, string contentType, bool isHeadRequest, ILogger logger)
+ public RangeRequestWriter(string rangeHeader, long contentLength, Stream source, string contentType, bool isHeadRequest)
{
if (string.IsNullOrEmpty(contentType))
{
@@ -68,7 +39,6 @@ namespace Emby.Server.Implementations.HttpServer
RangeHeader = rangeHeader;
SourceStream = source;
IsHeadRequest = isHeadRequest;
- this._logger = logger;
ContentType = contentType;
Headers[HeaderNames.ContentType] = contentType;
@@ -79,40 +49,26 @@ namespace Emby.Server.Implementations.HttpServer
}
/// <summary>
- /// Sets the range values.
+ /// Gets or sets the source stream.
/// </summary>
- private void SetRangeValues(long contentLength)
- {
- var requestedRange = RequestedRanges[0];
-
- TotalContentLength = contentLength;
-
- // If the requested range is "0-", we can optimize by just doing a stream copy
- if (!requestedRange.Value.HasValue)
- {
- RangeEnd = TotalContentLength - 1;
- }
- else
- {
- RangeEnd = requestedRange.Value.Value;
- }
-
- RangeStart = requestedRange.Key;
- RangeLength = 1 + RangeEnd - RangeStart;
+ /// <value>The source stream.</value>
+ private Stream SourceStream { get; set; }
+ private string RangeHeader { get; set; }
+ private bool IsHeadRequest { get; set; }
- Headers[HeaderNames.ContentLength] = RangeLength.ToString(CultureInfo.InvariantCulture);
- Headers[HeaderNames.ContentRange] = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}";
+ private long RangeStart { get; set; }
+ private long RangeEnd { get; set; }
+ private long RangeLength { get; set; }
+ private long TotalContentLength { get; set; }
- if (RangeStart > 0 && SourceStream.CanSeek)
- {
- SourceStream.Position = RangeStart;
- }
- }
+ public Action OnComplete { get; set; }
/// <summary>
- /// The _requested ranges
+ /// Additional HTTP Headers
/// </summary>
- private List<KeyValuePair<long, long?>> _requestedRanges;
+ /// <value>The headers.</value>
+ public IDictionary<string, string> Headers => _options;
+
/// <summary>
/// Gets the requested ranges.
/// </summary>
@@ -137,11 +93,12 @@ namespace Emby.Server.Implementations.HttpServer
if (!string.IsNullOrEmpty(vals[0]))
{
- start = long.Parse(vals[0], UsCulture);
+ start = long.Parse(vals[0], CultureInfo.InvariantCulture);
}
+
if (!string.IsNullOrEmpty(vals[1]))
{
- end = long.Parse(vals[1], UsCulture);
+ end = long.Parse(vals[1], CultureInfo.InvariantCulture);
}
_requestedRanges.Add(new KeyValuePair<long, long?>(start, end));
@@ -152,6 +109,51 @@ namespace Emby.Server.Implementations.HttpServer
}
}
+ public string ContentType { get; set; }
+
+ public IRequest RequestContext { get; set; }
+
+ public object Response { get; set; }
+
+ public int Status { get; set; }
+
+ public HttpStatusCode StatusCode
+ {
+ get => (HttpStatusCode)Status;
+ set => Status = (int)value;
+ }
+
+ /// <summary>
+ /// Sets the range values.
+ /// </summary>
+ private void SetRangeValues(long contentLength)
+ {
+ var requestedRange = RequestedRanges[0];
+
+ TotalContentLength = contentLength;
+
+ // If the requested range is "0-", we can optimize by just doing a stream copy
+ if (!requestedRange.Value.HasValue)
+ {
+ RangeEnd = TotalContentLength - 1;
+ }
+ else
+ {
+ RangeEnd = requestedRange.Value.Value;
+ }
+
+ RangeStart = requestedRange.Key;
+ RangeLength = 1 + RangeEnd - RangeStart;
+
+ Headers[HeaderNames.ContentLength] = RangeLength.ToString(CultureInfo.InvariantCulture);
+ Headers[HeaderNames.ContentRange] = $"bytes {RangeStart}-{RangeEnd}/{TotalContentLength}";
+
+ if (RangeStart > 0 && SourceStream.CanSeek)
+ {
+ SourceStream.Position = RangeStart;
+ }
+ }
+
public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken)
{
try
@@ -167,59 +169,44 @@ namespace Emby.Server.Implementations.HttpServer
// If the requested range is "0-", we can optimize by just doing a stream copy
if (RangeEnd >= TotalContentLength - 1)
{
- await source.CopyToAsync(responseStream, BufferSize).ConfigureAwait(false);
+ await source.CopyToAsync(responseStream, BufferSize, cancellationToken).ConfigureAwait(false);
}
else
{
- await CopyToInternalAsync(source, responseStream, RangeLength).ConfigureAwait(false);
+ await CopyToInternalAsync(source, responseStream, RangeLength, cancellationToken).ConfigureAwait(false);
}
}
}
finally
{
- if (OnComplete != null)
- {
- OnComplete();
- }
+ OnComplete?.Invoke();
}
}
- private static async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength)
+ private static async Task CopyToInternalAsync(Stream source, Stream destination, long copyLength, CancellationToken cancellationToken)
{
- var array = new byte[BufferSize];
- int bytesRead;
- while ((bytesRead = await source.ReadAsync(array, 0, array.Length).ConfigureAwait(false)) != 0)
+ var array = ArrayPool<byte>.Shared.Rent(BufferSize);
+ try
{
- if (bytesRead == 0)
+ int bytesRead;
+ while ((bytesRead = await source.ReadAsync(array, 0, array.Length, cancellationToken).ConfigureAwait(false)) != 0)
{
- break;
- }
+ var bytesToCopy = Math.Min(bytesRead, copyLength);
- var bytesToCopy = Math.Min(bytesRead, copyLength);
+ await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToCopy), cancellationToken).ConfigureAwait(false);
- await destination.WriteAsync(array, 0, Convert.ToInt32(bytesToCopy)).ConfigureAwait(false);
+ copyLength -= bytesToCopy;
- copyLength -= bytesToCopy;
-
- if (copyLength <= 0)
- {
- break;
+ if (copyLength <= 0)
+ {
+ break;
+ }
}
}
- }
-
- public string ContentType { get; set; }
-
- public IRequest RequestContext { get; set; }
-
- public object Response { get; set; }
-
- public int Status { get; set; }
-
- public HttpStatusCode StatusCode
- {
- get => (HttpStatusCode)Status;
- set => Status = (int)value;
+ finally
+ {
+ ArrayPool<byte>.Shared.Return(array);
+ }
}
}
}
diff --git a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs
index 3ab5dbc16..a8cd2ac8f 100644
--- a/Emby.Server.Implementations/HttpServer/ResponseFilter.cs
+++ b/Emby.Server.Implementations/HttpServer/ResponseFilter.cs
@@ -41,11 +41,11 @@ namespace Emby.Server.Implementations.HttpServer
res.Headers.Add(key, value);
}
// Try to prevent compatibility view
- res.Headers["Access-Control-Allow-Headers"] = ("Accept, Accept-Language, Authorization, Cache-Control, " +
+ res.Headers["Access-Control-Allow-Headers"] = "Accept, Accept-Language, Authorization, Cache-Control, " +
"Content-Disposition, Content-Encoding, Content-Language, Content-Length, Content-MD5, Content-Range, " +
"Content-Type, Cookie, Date, Host, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, " +
"Origin, OriginToken, Pragma, Range, Slug, Transfer-Encoding, Want-Digest, X-MediaBrowser-Token, " +
- "X-Emby-Authorization");
+ "X-Emby-Authorization";
if (dto is Exception exception)
{
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..ab6483bf9 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;
//}
@@ -245,6 +245,16 @@ namespace Emby.Server.Implementations.IO
if (info is FileInfo fileInfo)
{
result.Length = fileInfo.Length;
+
+ // Issue #2354 get the size of files behind symbolic links
+ if (fileInfo.Attributes.HasFlag(FileAttributes.ReparsePoint))
+ {
+ using (Stream thisFileStream = File.OpenRead(fileInfo.FullName))
+ {
+ result.Length = thisFileStream.Length;
+ }
+ }
+
result.DirectoryName = fileInfo.DirectoryName;
}
@@ -628,6 +638,7 @@ namespace Emby.Server.Implementations.IO
{
return false;
}
+
return extensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
});
}
@@ -682,6 +693,7 @@ namespace Emby.Server.Implementations.IO
{
return false;
}
+
return extensions.Contains(ext, StringComparer.OrdinalIgnoreCase);
});
}
diff --git a/Emby.Server.Implementations/IStartupOptions.cs b/Emby.Server.Implementations/IStartupOptions.cs
index 0b9f80538..e7e72c686 100644
--- a/Emby.Server.Implementations/IStartupOptions.cs
+++ b/Emby.Server.Implementations/IStartupOptions.cs
@@ -37,11 +37,6 @@ namespace Emby.Server.Implementations
string RestartArgs { get; }
/// <summary>
- /// Gets the value of the --plugin-manifest-url command line option.
- /// </summary>
- string PluginManifestUrl { get; }
-
- /// <summary>
/// Gets the value of the --published-server-url command line option.
/// </summary>
Uri PublishedServerUrl { get; }
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..77b2c0a69 100644
--- a/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
+++ b/Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs
@@ -1,5 +1,6 @@
using System;
using System.IO;
+using MediaBrowser.Controller;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Resolvers;
@@ -8,24 +9,33 @@ 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
{
private readonly ILibraryManager _libraryManager;
+ private readonly IServerApplicationPaths _serverApplicationPaths;
/// <summary>
/// Initializes a new instance of the <see cref="CoreResolutionIgnoreRule"/> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
- public CoreResolutionIgnoreRule(ILibraryManager libraryManager)
+ /// <param name="serverApplicationPaths">The server application paths.</param>
+ public CoreResolutionIgnoreRule(ILibraryManager libraryManager, IServerApplicationPaths serverApplicationPaths)
{
_libraryManager = libraryManager;
+ _serverApplicationPaths = serverApplicationPaths;
}
/// <inheritdoc />
public bool ShouldIgnore(FileSystemMetadata fileInfo, BaseItem parent)
{
+ // Don't ignore application folders
+ if (fileInfo.FullName.Contains(_serverApplicationPaths.RootFolderPath, StringComparison.InvariantCulture))
+ {
+ return false;
+ }
+
// Don't ignore top level folders
if (fileInfo.IsDirectory && parent is AggregateFolder)
{
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..6e6ef1359 100644
--- a/Emby.Server.Implementations/Library/IgnorePatterns.cs
+++ b/Emby.Server.Implementations/Library/IgnorePatterns.cs
@@ -1,17 +1,20 @@
+#nullable enable
+
+using System;
using System.Linq;
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[]
+ private static readonly string[] _patterns =
{
"**/small.jpg",
"**/albumart.jpg",
@@ -19,32 +22,51 @@ namespace Emby.Server.Implementations.Library
// Directories
"**/metadata/**",
+ "**/metadata",
"**/ps3_update/**",
+ "**/ps3_update",
"**/ps3_vprm/**",
+ "**/ps3_vprm",
"**/extrafanart/**",
+ "**/extrafanart",
"**/extrathumbs/**",
+ "**/extrathumbs",
"**/.actors/**",
+ "**/.actors",
"**/.wd_tv/**",
+ "**/.wd_tv",
"**/lost+found/**",
+ "**/lost+found",
// WMC temp recording directories that will constantly be written to
"**/TempRec/**",
+ "**/TempRec",
"**/TempSBE/**",
+ "**/TempSBE",
// Synology
"**/eaDir/**",
+ "**/eaDir",
"**/@eaDir/**",
+ "**/@eaDir",
"**/#recycle/**",
+ "**/#recycle",
// Qnap
"**/@Recycle/**",
+ "**/@Recycle",
"**/.@__thumb/**",
+ "**/.@__thumb",
"**/$RECYCLE.BIN/**",
+ "**/$RECYCLE.BIN",
"**/System Volume Information/**",
+ "**/System Volume Information",
"**/.grab/**",
+ "**/.grab",
// Unix hidden files and directories
"**/.*/**",
+ "**/.*",
// thumbs.db
"**/thumbs.db",
@@ -56,19 +78,31 @@ namespace Emby.Server.Implementations.Library
private static readonly GlobOptions _globOptions = new GlobOptions
{
- Evaluation = {
+ Evaluation =
+ {
CaseInsensitive = true
}
};
- private static readonly Glob[] _globs = Patterns.Select(p => Glob.Parse(p, _globOptions)).ToArray();
+ 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)
+ /// <param name="path">The path to test.</param>
+ /// <returns>Whether to ignore the path.</returns>
+ public static bool ShouldIgnore(ReadOnlySpan<char> path)
{
- return _globs.Any(g => g.IsMatch(path));
+ int len = _globs.Length;
+ for (int i = 0; i < len; i++)
+ {
+ if (_globs[i].IsMatch(path))
+ {
+ return true;
+ }
+ }
+
+ return false;
}
}
}
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 7d74ced6c..c27b73c74 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -97,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; }
@@ -136,7 +136,7 @@ namespace Emby.Server.Implementations.Library
/// <summary>
/// Initializes a new instance of the <see cref="LibraryManager" /> class.
/// </summary>
- /// <param name="appHost">The application host</param>
+ /// <param name="appHost">The application host.</param>
/// <param name="logger">The logger.</param>
/// <param name="taskManager">The task manager.</param>
/// <param name="userManager">The user manager.</param>
@@ -209,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();
@@ -341,7 +341,7 @@ namespace Emby.Server.Implementations.Library
if (item is LiveTvProgram)
{
_logger.LogDebug(
- "Deleting item, Type: {0}, Name: {1}, Path: {2}, Id: {3}",
+ "Removing item, Type: {0}, Name: {1}, Path: {2}, Id: {3}",
item.GetType().Name,
item.Name ?? "Unknown name",
item.Path ?? string.Empty,
@@ -350,7 +350,7 @@ namespace Emby.Server.Implementations.Library
else
{
_logger.LogInformation(
- "Deleting item, Type: {0}, Name: {1}, Path: {2}, Id: {3}",
+ "Removing item, Type: {0}, Name: {1}, Path: {2}, Id: {3}",
item.GetType().Name,
item.Name ?? "Unknown name",
item.Path ?? string.Empty,
@@ -368,7 +368,12 @@ namespace Emby.Server.Implementations.Library
continue;
}
- _logger.LogDebug("Deleting path {MetadataPath}", metadataPath);
+ _logger.LogDebug(
+ "Deleting metadata path, Type: {0}, Name: {1}, Path: {2}, Id: {3}",
+ item.GetType().Name,
+ item.Name ?? "Unknown name",
+ metadataPath,
+ item.Id);
try
{
@@ -392,7 +397,13 @@ namespace Emby.Server.Implementations.Library
{
try
{
- _logger.LogDebug("Deleting path {path}", fileSystemInfo.FullName);
+ _logger.LogInformation(
+ "Deleting item path, Type: {0}, Name: {1}, Path: {2}, Id: {3}",
+ item.GetType().Name,
+ item.Name ?? "Unknown name",
+ fileSystemInfo.FullName,
+ item.Id);
+
if (fileSystemInfo.IsDirectory)
{
Directory.Delete(fileSystemInfo.FullName, true);
@@ -514,8 +525,8 @@ namespace Emby.Server.Implementations.Library
return key.GetMD5();
}
- public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null, bool allowIgnorePath = true)
- => ResolvePath(fileInfo, new DirectoryService(_fileSystem), null, parent, allowIgnorePath: allowIgnorePath);
+ public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null)
+ => ResolvePath(fileInfo, new DirectoryService(_fileSystem), null, parent);
private BaseItem ResolvePath(
FileSystemMetadata fileInfo,
@@ -523,8 +534,7 @@ namespace Emby.Server.Implementations.Library
IItemResolver[] resolvers,
Folder parent = null,
string collectionType = null,
- LibraryOptions libraryOptions = null,
- bool allowIgnorePath = true)
+ LibraryOptions libraryOptions = null)
{
if (fileInfo == null)
{
@@ -548,7 +558,7 @@ namespace Emby.Server.Implementations.Library
};
// Return null if ignore rules deem that we should do so
- if (allowIgnorePath && IgnoreFile(args.FileInfo, args.Parent))
+ if (IgnoreFile(args.FileInfo, args.Parent))
{
return null;
}
@@ -627,7 +637,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>
@@ -713,7 +723,7 @@ namespace Emby.Server.Implementations.Library
Directory.CreateDirectory(rootFolderPath);
var rootFolder = GetItemById(GetNewItemId(rootFolderPath, typeof(AggregateFolder))) as AggregateFolder ??
- ((Folder) ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath), allowIgnorePath: false))
+ ((Folder) ResolvePath(_fileSystem.GetDirectoryInfo(rootFolderPath)))
.DeepCopy<Folder, AggregateFolder>();
// In case program data folder was moved
@@ -795,7 +805,7 @@ namespace Emby.Server.Implementations.Library
if (tmpItem == null)
{
_logger.LogDebug("Creating new userRootFolder with DeepCopy");
- tmpItem = ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath), allowIgnorePath: false)).DeepCopy<Folder, UserRootFolder>();
+ tmpItem = ((Folder)ResolvePath(_fileSystem.GetDirectoryInfo(userRootPath))).DeepCopy<Folder, UserRootFolder>();
}
// In case program data folder was moved
@@ -909,7 +919,7 @@ namespace Emby.Server.Implementations.Library
}
/// <summary>
- /// Gets a Genre
+ /// Gets a Genre.
/// </summary>
/// <param name="name">The name.</param>
/// <returns>Task{Genre}.</returns>
@@ -990,7 +1000,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>
@@ -1793,7 +1803,7 @@ namespace Emby.Server.Implementations.Library
/// Creates the items.
/// </summary>
/// <param name="items">The items.</param>
- /// <param name="parent">The parent item</param>
+ /// <param name="parent">The parent item.</param>
/// <param name="cancellationToken">The cancellation token.</param>
public void CreateItems(IEnumerable<BaseItem> items, BaseItem parent, CancellationToken cancellationToken)
{
@@ -1894,9 +1904,19 @@ namespace Emby.Server.Implementations.Library
}
}
- ImageDimensions size = _imageProcessor.GetImageDimensions(item, image);
- image.Width = size.Width;
- image.Height = size.Height;
+ try
+ {
+ ImageDimensions size = _imageProcessor.GetImageDimensions(item, image);
+ image.Width = size.Width;
+ image.Height = size.Height;
+ }
+ catch (Exception ex)
+ {
+ _logger.LogError(ex, "Cannnot get image dimensions for {0}", image.Path);
+ image.Width = 0;
+ image.Height = 0;
+ continue;
+ }
try
{
@@ -2595,7 +2615,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;
}
@@ -2784,10 +2804,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));
@@ -2861,7 +2883,6 @@ namespace Emby.Server.Implementations.Library
_logger.LogError(ex, "Error getting person");
return null;
}
-
}).Where(i => i != null).ToList();
}
@@ -2896,7 +2917,8 @@ namespace Emby.Server.Implementations.Library
}
catch (HttpException ex)
{
- if (ex.StatusCode.HasValue && ex.StatusCode.Value == HttpStatusCode.NotFound)
+ if (ex.StatusCode.HasValue
+ && (ex.StatusCode.Value == HttpStatusCode.NotFound || ex.StatusCode.Value == HttpStatusCode.Forbidden))
{
continue;
}
@@ -2989,21 +3011,6 @@ namespace Emby.Server.Implementations.Library
});
}
- private static bool ValidateNetworkPath(string path)
- {
- //if (Environment.OSVersion.Platform == PlatformID.Win32NT)
- //{
- // // We can't validate protocol-based paths, so just allow them
- // if (path.IndexOf("://", StringComparison.OrdinalIgnoreCase) == -1)
- // {
- // return Directory.Exists(path);
- // }
- //}
-
- // Without native support for unc, we cannot validate this when running under mono
- return true;
- }
-
private const string ShortcutFileExtension = ".mblink";
public void AddMediaPath(string virtualFolderName, MediaPathInfo pathInfo)
@@ -3030,11 +3037,6 @@ namespace Emby.Server.Implementations.Library
throw new FileNotFoundException("The path does not exist.");
}
- if (!string.IsNullOrWhiteSpace(pathInfo.NetworkPath) && !ValidateNetworkPath(pathInfo.NetworkPath))
- {
- throw new FileNotFoundException("The network path does not exist.");
- }
-
var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
@@ -3073,11 +3075,6 @@ namespace Emby.Server.Implementations.Library
throw new ArgumentNullException(nameof(pathInfo));
}
- if (!string.IsNullOrWhiteSpace(pathInfo.NetworkPath) && !ValidateNetworkPath(pathInfo.NetworkPath))
- {
- throw new FileNotFoundException("The network path does not exist.");
- }
-
var rootFolderPath = _configurationManager.ApplicationPaths.DefaultUserViewsPath;
var virtualFolderPath = Path.Combine(rootFolderPath, virtualFolderName);
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 02add6600..ceb36b389 100644
--- a/Emby.Server.Implementations/Library/MediaSourceManager.cs
+++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs
@@ -205,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;
@@ -436,7 +441,6 @@ namespace Emby.Server.Implementations.Library
}
return 1;
-
}).ThenBy(i => i.Video3DFormat.HasValue ? 1 : 0)
.ThenByDescending(i =>
{
@@ -620,7 +624,6 @@ namespace Emby.Server.Implementations.Library
MediaSource = mediaSource,
ExtractChapters = false,
MediaType = DlnaProfileType.Video
-
}, cancellationToken).ConfigureAwait(false);
mediaSource.MediaStreams = info.MediaStreams;
@@ -646,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)
{
@@ -682,7 +685,7 @@ namespace Emby.Server.Implementations.Library
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);
}
}
@@ -748,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/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/Books/BookResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs
index 503de0b4e..86a5d8b7d 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs
@@ -19,7 +19,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books
// Only process items that are in a collection folder containing books
if (!string.Equals(collectionType, CollectionType.Books, StringComparison.OrdinalIgnoreCase))
+ {
return null;
+ }
if (args.IsDirectory)
{
@@ -55,7 +57,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books
// Don't return a Book if there is more (or less) than one document in the directory
if (bookFiles.Count != 1)
+ {
return null;
+ }
return new Book
{
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..c8e41001a 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/TV/SeasonResolver.cs
@@ -23,8 +23,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
/// </summary>
/// <param name="config">The config.</param>
/// <param name="libraryManager">The library manager.</param>
- /// <param name="localization">The localization</param>
- /// <param name="logger">The logger</param>
+ /// <param name="localization">The localization.</param>
+ /// <param name="logger">The logger.</param>
public SeasonResolver(
IServerConfigurationManager config,
ILibraryManager libraryManager,
@@ -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 f37cb3e9d..3df9cc06f 100644
--- a/Emby.Server.Implementations/Library/SearchEngine.cs
+++ b/Emby.Server.Implementations/Library/SearchEngine.cs
@@ -194,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>();
@@ -207,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 9e17fa672..175b3af57 100644
--- a/Emby.Server.Implementations/Library/UserDataManager.cs
+++ b/Emby.Server.Implementations/Library/UserDataManager.cs
@@ -103,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>
@@ -188,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/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 e39092f97..4c1de3bcc 100644
--- a/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/Emby.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -406,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)
{
@@ -556,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;
@@ -575,6 +576,7 @@ namespace Emby.Server.Implementations.LiveTv
{
forceUpdate = true;
}
+
item.ExternalSeriesId = seriesId;
var isSeries = info.IsSeries || !string.IsNullOrEmpty(info.EpisodeTitle);
@@ -589,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");
@@ -635,6 +644,7 @@ namespace Emby.Server.Implementations.LiveTv
{
forceUpdate = true;
}
+
item.IsSeries = isSeries;
item.Name = info.Name;
@@ -652,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;
@@ -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
};
@@ -2456,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..2e2488e6e 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;
}
@@ -201,7 +201,15 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
var index = line.IndexOf("Channel", StringComparison.OrdinalIgnoreCase);
var name = line.Substring(0, index - 1);
var currentChannel = line.Substring(index + 7);
- if (currentChannel != "none") { status = LiveTvTunerStatus.LiveTv; } else { status = LiveTvTunerStatus.Available; }
+ if (currentChannel != "none")
+ {
+ status = LiveTvTunerStatus.LiveTv;
+ }
+ else
+ {
+ status = LiveTvTunerStatus.Available;
+ }
+
tuners.Add(new LiveTvTunerInfo
{
Name = name,
@@ -230,11 +238,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
inside = true;
continue;
}
+
if (let == '>')
{
inside = false;
continue;
}
+
if (!inside)
{
buffer[bufferIndex] = let;
@@ -332,12 +342,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 +498,6 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
Height = height,
BitRate = videoBitrate,
NalLengthSize = nal
-
},
new MediaStream
{
@@ -502,8 +518,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 +675,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
@@ -674,7 +698,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts.HdHomerun
{
var model = ModelNumber ?? string.Empty;
- if ((model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1))
+ if (model.IndexOf("hdtc", StringComparison.OrdinalIgnoreCase) != -1)
{
return true;
}
@@ -722,7 +746,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/af.json b/Emby.Server.Implementations/Localization/Core/af.json
index 20447347b..e587c37d5 100644
--- a/Emby.Server.Implementations/Localization/Core/af.json
+++ b/Emby.Server.Implementations/Localization/Core/af.json
@@ -19,8 +19,8 @@
"Sync": "Sinkroniseer",
"HeaderFavoriteSongs": "Gunsteling Liedjies",
"Songs": "Liedjies",
- "DeviceOnlineWithName": "{0} is verbind",
- "DeviceOfflineWithName": "{0} het afgesluit",
+ "DeviceOnlineWithName": "{0} gekoppel is",
+ "DeviceOfflineWithName": "{0} is ontkoppel",
"Collections": "Versamelings",
"Inherit": "Ontvang",
"HeaderLiveTV": "Live TV",
@@ -91,5 +91,9 @@
"ChapterNameValue": "Hoofstuk",
"CameraImageUploadedFrom": "'n Nuwe kamera photo opgelaai van {0}",
"AuthenticationSucceededWithUserName": "{0} suksesvol geverifieer",
- "Albums": "Albums"
+ "Albums": "Albums",
+ "TasksChannelsCategory": "Internet kanale",
+ "TasksApplicationCategory": "aansoek",
+ "TasksLibraryCategory": "biblioteek",
+ "TasksMaintenanceCategory": "onderhoud"
}
diff --git a/Emby.Server.Implementations/Localization/Core/ar.json b/Emby.Server.Implementations/Localization/Core/ar.json
index d68928fce..4eac8e75d 100644
--- a/Emby.Server.Implementations/Localization/Core/ar.json
+++ b/Emby.Server.Implementations/Localization/Core/ar.json
@@ -1,5 +1,5 @@
{
- "Albums": "ألبومات",
+ "Albums": "البومات",
"AppDeviceValues": "تطبيق: {0}, جهاز: {1}",
"Application": "تطبيق",
"Artists": "الفنانين",
@@ -14,7 +14,7 @@
"FailedLoginAttemptWithUserName": "عملية تسجيل الدخول فشلت من {0}",
"Favorites": "المفضلة",
"Folders": "المجلدات",
- "Genres": "الأنواع",
+ "Genres": "التضنيفات",
"HeaderAlbumArtists": "فناني الألبومات",
"HeaderCameraUploads": "تحميلات الكاميرا",
"HeaderContinueWatching": "استئناف",
@@ -50,7 +50,7 @@
"NotificationOptionAudioPlayback": "بدأ تشغيل المقطع الصوتي",
"NotificationOptionAudioPlaybackStopped": "تم إيقاف تشغيل المقطع الصوتي",
"NotificationOptionCameraImageUploaded": "تم رفع صورة الكاميرا",
- "NotificationOptionInstallationFailed": "فشل في التثبيت",
+ "NotificationOptionInstallationFailed": "فشل التثبيت",
"NotificationOptionNewLibraryContent": "تم إضافة محتوى جديد",
"NotificationOptionPluginError": "فشل في البرنامج المضاف",
"NotificationOptionPluginInstalled": "تم تثبيت الملحق",
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/de.json b/Emby.Server.Implementations/Localization/Core/de.json
index 82df43be1..a6e9779c9 100644
--- a/Emby.Server.Implementations/Localization/Core/de.json
+++ b/Emby.Server.Implementations/Localization/Core/de.json
@@ -3,7 +3,7 @@
"AppDeviceValues": "App: {0}, Gerät: {1}",
"Application": "Anwendung",
"Artists": "Interpreten",
- "AuthenticationSucceededWithUserName": "{0} hat sich erfolgreich authentifiziert",
+ "AuthenticationSucceededWithUserName": "{0} hat sich erfolgreich angemeldet",
"Books": "Bücher",
"CameraImageUploadedFrom": "Ein neues Foto wurde von {0} hochgeladen",
"Channels": "Kanäle",
diff --git a/Emby.Server.Implementations/Localization/Core/es-AR.json b/Emby.Server.Implementations/Localization/Core/es-AR.json
index fc9a10f27..ac96c788c 100644
--- a/Emby.Server.Implementations/Localization/Core/es-AR.json
+++ b/Emby.Server.Implementations/Localization/Core/es-AR.json
@@ -20,7 +20,7 @@
"HeaderContinueWatching": "Seguir viendo",
"HeaderFavoriteAlbums": "Álbumes favoritos",
"HeaderFavoriteArtists": "Artistas favoritos",
- "HeaderFavoriteEpisodes": "Episodios favoritos",
+ "HeaderFavoriteEpisodes": "Capítulos favoritos",
"HeaderFavoriteShows": "Programas favoritos",
"HeaderFavoriteSongs": "Canciones favoritas",
"HeaderLiveTV": "TV en vivo",
diff --git a/Emby.Server.Implementations/Localization/Core/es-MX.json b/Emby.Server.Implementations/Localization/Core/es-MX.json
index 20b37ec9f..4ba324aa1 100644
--- a/Emby.Server.Implementations/Localization/Core/es-MX.json
+++ b/Emby.Server.Implementations/Localization/Core/es-MX.json
@@ -31,7 +31,7 @@
"ItemAddedWithName": "{0} fue agregado a la biblioteca",
"ItemRemovedWithName": "{0} fue removido de la biblioteca",
"LabelIpAddressValue": "Dirección IP: {0}",
- "LabelRunningTimeValue": "Duración: {0}",
+ "LabelRunningTimeValue": "Tiempo de reproducción: {0}",
"Latest": "Recientes",
"MessageApplicationUpdated": "El servidor Jellyfin ha sido actualizado",
"MessageApplicationUpdatedTo": "El servidor Jellyfin ha sido actualizado a {0}",
diff --git a/Emby.Server.Implementations/Localization/Core/es_419.json b/Emby.Server.Implementations/Localization/Core/es_419.json
index b0fdc8386..0959ef2ca 100644
--- a/Emby.Server.Implementations/Localization/Core/es_419.json
+++ b/Emby.Server.Implementations/Localization/Core/es_419.json
@@ -1,5 +1,5 @@
{
- "LabelRunningTimeValue": "Duración: {0}",
+ "LabelRunningTimeValue": "Tiempo en ejecución: {0}",
"ValueSpecialEpisodeName": "Especial - {0}",
"Sync": "Sincronizar",
"Songs": "Canciones",
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/Localization/Core/hr.json b/Emby.Server.Implementations/Localization/Core/hr.json
index c169a35e7..97c77017b 100644
--- a/Emby.Server.Implementations/Localization/Core/hr.json
+++ b/Emby.Server.Implementations/Localization/Core/hr.json
@@ -5,23 +5,23 @@
"Artists": "Izvođači",
"AuthenticationSucceededWithUserName": "{0} uspješno ovjerena",
"Books": "Knjige",
- "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
+ "CameraImageUploadedFrom": "Nova fotografija sa kamere je uploadana iz {0}",
"Channels": "Kanali",
"ChapterNameValue": "Poglavlje {0}",
"Collections": "Kolekcije",
"DeviceOfflineWithName": "{0} se odspojilo",
"DeviceOnlineWithName": "{0} je spojeno",
"FailedLoginAttemptWithUserName": "Neuspjeli pokušaj prijave za {0}",
- "Favorites": "Omiljeni",
+ "Favorites": "Favoriti",
"Folders": "Mape",
"Genres": "Žanrovi",
- "HeaderAlbumArtists": "Izvođači albuma",
- "HeaderCameraUploads": "Camera Uploads",
- "HeaderContinueWatching": "Continue Watching",
+ "HeaderAlbumArtists": "Izvođači na albumu",
+ "HeaderCameraUploads": "Uvoz sa kamere",
+ "HeaderContinueWatching": "Nastavi gledati",
"HeaderFavoriteAlbums": "Omiljeni albumi",
"HeaderFavoriteArtists": "Omiljeni izvođači",
"HeaderFavoriteEpisodes": "Omiljene epizode",
- "HeaderFavoriteShows": "Omiljene emisije",
+ "HeaderFavoriteShows": "Omiljene serije",
"HeaderFavoriteSongs": "Omiljene pjesme",
"HeaderLiveTV": "TV uživo",
"HeaderNextUp": "Sljedeće je",
@@ -34,23 +34,23 @@
"LabelRunningTimeValue": "Vrijeme rada: {0}",
"Latest": "Najnovije",
"MessageApplicationUpdated": "Jellyfin Server je ažuriran",
- "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}",
+ "MessageApplicationUpdatedTo": "Jellyfin Server je ažuriran na {0}",
"MessageNamedServerConfigurationUpdatedWithValue": "Odjeljak postavka servera {0} je ažuriran",
"MessageServerConfigurationUpdated": "Postavke servera su ažurirane",
"MixedContent": "Miješani sadržaj",
"Movies": "Filmovi",
"Music": "Glazba",
"MusicVideos": "Glazbeni spotovi",
- "NameInstallFailed": "{0} installation failed",
+ "NameInstallFailed": "{0} neuspješnih instalacija",
"NameSeasonNumber": "Sezona {0}",
- "NameSeasonUnknown": "Season Unknown",
- "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.",
+ "NameSeasonUnknown": "Nepoznata sezona",
+ "NewVersionIsAvailable": "Nova verzija Jellyfin servera je dostupna za preuzimanje.",
"NotificationOptionApplicationUpdateAvailable": "Dostupno ažuriranje aplikacije",
"NotificationOptionApplicationUpdateInstalled": "Instalirano ažuriranje aplikacije",
"NotificationOptionAudioPlayback": "Reprodukcija glazbe započeta",
"NotificationOptionAudioPlaybackStopped": "Reprodukcija audiozapisa je zaustavljena",
"NotificationOptionCameraImageUploaded": "Slike kamere preuzete",
- "NotificationOptionInstallationFailed": "Instalacija nije izvršena",
+ "NotificationOptionInstallationFailed": "Instalacija neuspješna",
"NotificationOptionNewLibraryContent": "Novi sadržaj je dodan",
"NotificationOptionPluginError": "Dodatak otkazao",
"NotificationOptionPluginInstalled": "Dodatak instaliran",
@@ -62,7 +62,7 @@
"NotificationOptionVideoPlayback": "Reprodukcija videa započeta",
"NotificationOptionVideoPlaybackStopped": "Reprodukcija videozapisa je zaustavljena",
"Photos": "Slike",
- "Playlists": "Popisi",
+ "Playlists": "Popis za reprodukciju",
"Plugin": "Dodatak",
"PluginInstalledWithName": "{0} je instalirano",
"PluginUninstalledWithName": "{0} je deinstalirano",
@@ -70,15 +70,15 @@
"ProviderValue": "Pružitelj: {0}",
"ScheduledTaskFailedWithName": "{0} neuspjelo",
"ScheduledTaskStartedWithName": "{0} pokrenuto",
- "ServerNameNeedsToBeRestarted": "{0} needs to be restarted",
- "Shows": "Shows",
+ "ServerNameNeedsToBeRestarted": "{0} treba biti ponovno pokrenuto",
+ "Shows": "Serije",
"Songs": "Pjesme",
"StartupEmbyServerIsLoading": "Jellyfin Server se učitava. Pokušajte ponovo kasnije.",
"SubtitleDownloadFailureForItem": "Titlovi prijevoda nisu preuzeti za {0}",
- "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}",
+ "SubtitleDownloadFailureFromForItem": "Prijevodi nisu uspješno preuzeti {0} od {1}",
"Sync": "Sink.",
"System": "Sistem",
- "TvShows": "TV Shows",
+ "TvShows": "Serije",
"User": "Korisnik",
"UserCreatedWithName": "Korisnik {0} je stvoren",
"UserDeletedWithName": "Korisnik {0} je obrisan",
@@ -87,10 +87,10 @@
"UserOfflineFromDevice": "{0} se odspojilo od {1}",
"UserOnlineFromDevice": "{0} je online od {1}",
"UserPasswordChangedWithName": "Lozinka je promijenjena za korisnika {0}",
- "UserPolicyUpdatedWithName": "User policy has been updated for {0}",
+ "UserPolicyUpdatedWithName": "Pravila za korisnika su ažurirana za {0}",
"UserStartedPlayingItemWithValues": "{0} je pokrenuo {1}",
"UserStoppedPlayingItemWithValues": "{0} je zaustavio {1}",
- "ValueHasBeenAddedToLibrary": "{0} has been added to your media library",
+ "ValueHasBeenAddedToLibrary": "{0} je dodano u medijsku biblioteku",
"ValueSpecialEpisodeName": "Specijal - {0}",
"VersionNumber": "Verzija {0}",
"TaskRefreshLibraryDescription": "Skenira vašu medijsku knjižnicu sa novim datotekama i osvježuje metapodatke.",
@@ -100,5 +100,19 @@
"TaskCleanCacheDescription": "Briše priručne datoteke nepotrebne za sistem.",
"TaskCleanCache": "Očisti priručnu memoriju",
"TasksApplicationCategory": "Aplikacija",
- "TasksMaintenanceCategory": "Održavanje"
+ "TasksMaintenanceCategory": "Održavanje",
+ "TaskDownloadMissingSubtitlesDescription": "Pretraživanje interneta za prijevodima koji nedostaju bazirano na konfiguraciji meta podataka.",
+ "TaskDownloadMissingSubtitles": "Preuzimanje prijevoda koji nedostaju",
+ "TaskRefreshChannelsDescription": "Osvježava informacije o internet kanalima.",
+ "TaskRefreshChannels": "Osvježi kanale",
+ "TaskCleanTranscodeDescription": "Briše transkodirane fajlove starije od jednog dana.",
+ "TaskCleanTranscode": "Očisti direktorij za transkodiranje",
+ "TaskUpdatePluginsDescription": "Preuzima i instalira ažuriranja za dodatke koji su podešeni da se ažuriraju automatski.",
+ "TaskUpdatePlugins": "Ažuriraj dodatke",
+ "TaskRefreshPeopleDescription": "Ažurira meta podatke za glumce i redatelje u vašoj medijskoj biblioteci.",
+ "TaskRefreshPeople": "Osvježi ljude",
+ "TaskCleanLogsDescription": "Briši logove koji su stariji od {0} dana.",
+ "TaskCleanLogs": "Očisti direktorij sa logovima",
+ "TasksChannelsCategory": "Internet kanali",
+ "TasksLibraryCategory": "Biblioteka"
}
diff --git a/Emby.Server.Implementations/Localization/Core/mr.json b/Emby.Server.Implementations/Localization/Core/mr.json
index 50b6360d8..b6db2b0f2 100644
--- a/Emby.Server.Implementations/Localization/Core/mr.json
+++ b/Emby.Server.Implementations/Localization/Core/mr.json
@@ -57,5 +57,7 @@
"HeaderCameraUploads": "कॅमेरा अपलोड",
"CameraImageUploadedFrom": "एक नवीन कॅमेरा चित्र {0} येथून अपलोड केले आहे",
"Application": "अ‍ॅप्लिकेशन",
- "AppDeviceValues": "अ‍ॅप: {0}, यंत्र: {1}"
+ "AppDeviceValues": "अ‍ॅप: {0}, यंत्र: {1}",
+ "Collections": "संग्रह",
+ "ChapterNameValue": "धडा {0}"
}
diff --git a/Emby.Server.Implementations/Localization/Core/ms.json b/Emby.Server.Implementations/Localization/Core/ms.json
index 79d078d4a..7f8df1289 100644
--- a/Emby.Server.Implementations/Localization/Core/ms.json
+++ b/Emby.Server.Implementations/Localization/Core/ms.json
@@ -5,47 +5,47 @@
"Artists": "Artis",
"AuthenticationSucceededWithUserName": "{0} berjaya disahkan",
"Books": "Buku-buku",
- "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}",
+ "CameraImageUploadedFrom": "Ada gambar dari kamera yang baru dimuat naik melalui {0}",
"Channels": "Saluran",
- "ChapterNameValue": "Chapter {0}",
+ "ChapterNameValue": "Bab {0}",
"Collections": "Koleksi",
- "DeviceOfflineWithName": "{0} has disconnected",
- "DeviceOnlineWithName": "{0} is connected",
+ "DeviceOfflineWithName": "{0} telah diputuskan sambungan",
+ "DeviceOnlineWithName": "{0} telah disambung",
"FailedLoginAttemptWithUserName": "Cubaan log masuk gagal dari {0}",
- "Favorites": "Favorites",
- "Folders": "Folders",
+ "Favorites": "Kegemaran",
+ "Folders": "Fail-fail",
"Genres": "Genre-genre",
- "HeaderAlbumArtists": "Album Artists",
+ "HeaderAlbumArtists": "Album Artis-artis",
"HeaderCameraUploads": "Muatnaik Kamera",
"HeaderContinueWatching": "Terus Menonton",
- "HeaderFavoriteAlbums": "Favorite Albums",
- "HeaderFavoriteArtists": "Favorite Artists",
- "HeaderFavoriteEpisodes": "Favorite Episodes",
- "HeaderFavoriteShows": "Favorite Shows",
- "HeaderFavoriteSongs": "Favorite Songs",
- "HeaderLiveTV": "Live TV",
- "HeaderNextUp": "Next Up",
- "HeaderRecordingGroups": "Recording Groups",
- "HomeVideos": "Home videos",
- "Inherit": "Inherit",
- "ItemAddedWithName": "{0} was added to the library",
- "ItemRemovedWithName": "{0} was removed from the library",
+ "HeaderFavoriteAlbums": "Album-album Kegemaran",
+ "HeaderFavoriteArtists": "Artis-artis Kegemaran",
+ "HeaderFavoriteEpisodes": "Episod-episod Kegemaran",
+ "HeaderFavoriteShows": "Rancangan-rancangan Kegemaran",
+ "HeaderFavoriteSongs": "Lagu-lagu Kegemaran",
+ "HeaderLiveTV": "TV Siaran Langsung",
+ "HeaderNextUp": "Seterusnya",
+ "HeaderRecordingGroups": "Kumpulan-kumpulan Rakaman",
+ "HomeVideos": "Video Personal",
+ "Inherit": "Mewarisi",
+ "ItemAddedWithName": "{0} telah ditambahkan ke dalam pustaka",
+ "ItemRemovedWithName": "{0} telah dibuang daripada pustaka",
"LabelIpAddressValue": "Alamat IP: {0}",
- "LabelRunningTimeValue": "Running time: {0}",
- "Latest": "Latest",
- "MessageApplicationUpdated": "Jellyfin Server has been updated",
- "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}",
- "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated",
- "MessageServerConfigurationUpdated": "Server configuration has been updated",
- "MixedContent": "Mixed content",
- "Movies": "Movies",
+ "LabelRunningTimeValue": "Masa berjalan: {0}",
+ "Latest": "Terbaru",
+ "MessageApplicationUpdated": "Jellyfin Server telah dikemas kini",
+ "MessageApplicationUpdatedTo": "Jellyfin Server telah dikemas kini ke {0}",
+ "MessageNamedServerConfigurationUpdatedWithValue": "Konfigurasi pelayan di bahagian {0} telah dikemas kini",
+ "MessageServerConfigurationUpdated": "Konfigurasi pelayan telah dikemas kini",
+ "MixedContent": "Kandungan campuran",
+ "Movies": "Filem",
"Music": "Muzik",
"MusicVideos": "Video muzik",
- "NameInstallFailed": "{0} installation failed",
- "NameSeasonNumber": "Season {0}",
- "NameSeasonUnknown": "Season Unknown",
- "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.",
- "NotificationOptionApplicationUpdateAvailable": "Application update available",
+ "NameInstallFailed": "{0} pemasangan gagal",
+ "NameSeasonNumber": "Musim {0}",
+ "NameSeasonUnknown": "Musim Tidak Diketahui",
+ "NewVersionIsAvailable": "Versi terbaru Jellyfin Server bersedia untuk dimuat turunkan.",
+ "NotificationOptionApplicationUpdateAvailable": "Kemas kini aplikasi telah sedia",
"NotificationOptionApplicationUpdateInstalled": "Application update installed",
"NotificationOptionAudioPlayback": "Audio playback started",
"NotificationOptionAudioPlaybackStopped": "Audio playback stopped",
diff --git a/Emby.Server.Implementations/Localization/Core/ne.json b/Emby.Server.Implementations/Localization/Core/ne.json
new file mode 100644
index 000000000..38c073709
--- /dev/null
+++ b/Emby.Server.Implementations/Localization/Core/ne.json
@@ -0,0 +1,86 @@
+{
+ "NotificationOptionUserLockedOut": "प्रयोगकर्ता प्रतिबन्धित",
+ "NotificationOptionTaskFailed": "निर्धारित कार्य विफलता",
+ "NotificationOptionServerRestartRequired": "सर्भर रिस्टार्ट आवाश्यक छ",
+ "NotificationOptionPluginUpdateInstalled": "प्लगइन अद्यावधिक स्थापना भयो",
+ "NotificationOptionPluginUninstalled": "प्लगइन विस्थापित",
+ "NotificationOptionPluginInstalled": "प्लगइन स्थापना भयो",
+ "NotificationOptionPluginError": "प्लगइन असफलता",
+ "NotificationOptionNewLibraryContent": "नयाँ सामग्री थपियो",
+ "NotificationOptionInstallationFailed": "स्थापना असफलता",
+ "NotificationOptionCameraImageUploaded": "क्यामेरा फोटो अपलोड गरियो",
+ "NotificationOptionAudioPlaybackStopped": "ध्वनि प्रक्षेपण रोकियो",
+ "NotificationOptionAudioPlayback": "ध्वनि प्रक्षेपण शुरू भयो",
+ "NotificationOptionApplicationUpdateInstalled": "अनुप्रयोग अद्यावधिक स्थापना भयो",
+ "NotificationOptionApplicationUpdateAvailable": "अनुप्रयोग अपडेट उपलब्ध छ",
+ "NewVersionIsAvailable": "जेलीफिन सर्भर को नयाँ संस्करण डाउनलोड को लागी उपलब्ध छ।",
+ "NameSeasonUnknown": "अज्ञात श्रृंखला",
+ "NameSeasonNumber": "श्रृंखला {0}",
+ "NameInstallFailed": "{0} स्थापना असफल भयो",
+ "MusicVideos": "सांगीतिक भिडियोहरू",
+ "Music": "संगीत",
+ "Movies": "चलचित्रहरू",
+ "MixedContent": "मिश्रित सामग्री",
+ "MessageServerConfigurationUpdated": "सर्भर कन्फिगरेसन अद्यावधिक गरिएको छ",
+ "MessageNamedServerConfigurationUpdatedWithValue": "सर्भर कन्फिगरेसन विभाग {0} अद्यावधिक गरिएको छ",
+ "MessageApplicationUpdatedTo": "जेलीफिन सर्भर {0} मा अद्यावधिक गरिएको छ",
+ "MessageApplicationUpdated": "जेलीफिन सर्भर अपडेट गरिएको छ",
+ "Latest": "नविनतम",
+ "LabelRunningTimeValue": "कुल समय: {0}",
+ "LabelIpAddressValue": "आईपी ठेगाना: {0}",
+ "ItemRemovedWithName": "{0}लाई पुस्तकालयबाट हटाईयो",
+ "ItemAddedWithName": "{0} लाईब्रेरीमा थपियो",
+ "Inherit": "इनहेरिट",
+ "HomeVideos": "घरेलु भिडियोहरू",
+ "HeaderRecordingGroups": "रेकर्ड समूहहरू",
+ "HeaderNextUp": "आगामी",
+ "HeaderLiveTV": "प्रत्यक्ष टिभी",
+ "HeaderFavoriteSongs": "मनपर्ने गीतहरू",
+ "HeaderFavoriteShows": "मनपर्ने कार्यक्रमहरू",
+ "HeaderFavoriteEpisodes": "मनपर्ने एपिसोडहरू",
+ "HeaderFavoriteArtists": "मनपर्ने कलाकारहरू",
+ "HeaderFavoriteAlbums": "मनपर्ने एल्बमहरू",
+ "HeaderContinueWatching": "हेर्न जारी राख्नुहोस्",
+ "HeaderCameraUploads": "क्यामेरा अपलोडहरू",
+ "HeaderAlbumArtists": "एल्बमका कलाकारहरू",
+ "Genres": "विधाहरू",
+ "Folders": "फोल्डरहरू",
+ "Favorites": "मनपर्ने",
+ "FailedLoginAttemptWithUserName": "{0}को लग इन प्रयास असफल",
+ "DeviceOnlineWithName": "{0}को साथ जडित",
+ "DeviceOfflineWithName": "{0}बाट विच्छेदन भयो",
+ "Collections": "संग्रह",
+ "ChapterNameValue": "अध्याय {0}",
+ "Channels": "च्यानलहरू",
+ "AppDeviceValues": "अनुप्रयोग: {0}, उपकरण: {1}",
+ "AuthenticationSucceededWithUserName": "{0} सफलतापूर्वक प्रमाणीकरण गरियो",
+ "CameraImageUploadedFrom": "{0}बाट नयाँ क्यामेरा छवि अपलोड गरिएको छ",
+ "Books": "पुस्तकहरु",
+ "Artists": "कलाकारहरू",
+ "Application": "अनुप्रयोगहरू",
+ "Albums": "एल्बमहरू",
+ "TasksLibraryCategory": "पुस्तकालय",
+ "TasksApplicationCategory": "अनुप्रयोग",
+ "TasksMaintenanceCategory": "मर्मत",
+ "UserPolicyUpdatedWithName": "प्रयोगकर्ता नीति को लागी अद्यावधिक गरिएको छ {0}",
+ "UserPasswordChangedWithName": "पासवर्ड प्रयोगकर्ताका लागि परिवर्तन गरिएको छ {0}",
+ "UserOnlineFromDevice": "{0} बाट अनलाइन छ {1}",
+ "UserOfflineFromDevice": "{0} बाट विच्छेदन भएको छ {1}",
+ "UserLockedOutWithName": "प्रयोगकर्ता {0} लक गरिएको छ",
+ "UserDeletedWithName": "प्रयोगकर्ता {0} हटाइएको छ",
+ "UserCreatedWithName": "प्रयोगकर्ता {0} सिर्जना गरिएको छ",
+ "User": "प्रयोगकर्ता",
+ "PluginInstalledWithName": "",
+ "StartupEmbyServerIsLoading": "Jellyfin सर्भर लोड हुँदैछ। कृपया छिट्टै फेरि प्रयास गर्नुहोस्।",
+ "Songs": "गीतहरू",
+ "Shows": "शोहरू",
+ "ServerNameNeedsToBeRestarted": "{0} लाई पुन: सुरु गर्नु पर्छ",
+ "ScheduledTaskStartedWithName": "{0} सुरु भयो",
+ "ScheduledTaskFailedWithName": "{0} असफल",
+ "ProviderValue": "प्रदायक: {0}",
+ "Plugin": "प्लगइनहरू",
+ "Playlists": "प्लेलिस्टहरू",
+ "Photos": "तस्बिरहरु",
+ "NotificationOptionVideoPlaybackStopped": "भिडियो प्लेब्याक रोकियो",
+ "NotificationOptionVideoPlayback": "भिडियो प्लेब्याक सुरु भयो"
+}
diff --git a/Emby.Server.Implementations/Localization/Core/pt.json b/Emby.Server.Implementations/Localization/Core/pt.json
index 25c5b9053..b534d0bbe 100644
--- a/Emby.Server.Implementations/Localization/Core/pt.json
+++ b/Emby.Server.Implementations/Localization/Core/pt.json
@@ -101,7 +101,17 @@
"TaskCleanLogsDescription": "Deletar arquivos de log que existe a mais de {0} dias.",
"TaskCleanLogs": "Limpar diretório de log",
"TaskRefreshLibrary": "Escanear biblioteca de mídias",
- "TaskRefreshChapterImagesDescription": "Criar miniaturas para videos que tem capítulos.",
- "TaskCleanCacheDescription": "Deletar arquivos de cache que não são mais usados pelo sistema.",
- "TasksChannelsCategory": "Canais de Internet"
+ "TaskRefreshChapterImagesDescription": "Cria miniaturas para vídeos que têm capítulos.",
+ "TaskCleanCacheDescription": "Apaga ficheiros em cache que já não são usados pelo sistema.",
+ "TasksChannelsCategory": "Canais de Internet",
+ "TaskRefreshChapterImages": "Extrair Imagens do Capítulo",
+ "TaskDownloadMissingSubtitlesDescription": "Pesquisa na Internet as legendas em falta com base na configuração de metadados.",
+ "TaskDownloadMissingSubtitles": "Download das legendas em falta",
+ "TaskRefreshChannelsDescription": "Atualiza as informações do canal da Internet.",
+ "TaskCleanTranscodeDescription": "Apagar os ficheiros com mais de um dia, de Transcode.",
+ "TaskCleanTranscode": "Limpar o diretório de Transcode",
+ "TaskUpdatePluginsDescription": "Download e instala as atualizações para plug-ins configurados para atualização automática.",
+ "TaskRefreshPeopleDescription": "Atualiza os metadados para atores e diretores na tua biblioteca de media.",
+ "TaskRefreshPeople": "Atualizar pessoas",
+ "TaskRefreshLibraryDescription": "Pesquisa a tua biblioteca de media por novos ficheiros e atualiza os metadados."
}
diff --git a/Emby.Server.Implementations/Localization/Core/th.json b/Emby.Server.Implementations/Localization/Core/th.json
index 32538ac03..576aaeb1b 100644
--- a/Emby.Server.Implementations/Localization/Core/th.json
+++ b/Emby.Server.Implementations/Localization/Core/th.json
@@ -67,5 +67,7 @@
"Artists": "นักแสดง",
"Application": "แอปพลิเคชั่น",
"AppDeviceValues": "App: {0}, อุปกรณ์: {1}",
- "Albums": "อัลบั้ม"
+ "Albums": "อัลบั้ม",
+ "ScheduledTaskStartedWithName": "{0} เริ่มต้น",
+ "ScheduledTaskFailedWithName": "{0} ล้มเหลว"
}
diff --git a/Emby.Server.Implementations/Localization/Core/zh-HK.json b/Emby.Server.Implementations/Localization/Core/zh-HK.json
index 0804fc927..1ac62baca 100644
--- a/Emby.Server.Implementations/Localization/Core/zh-HK.json
+++ b/Emby.Server.Implementations/Localization/Core/zh-HK.json
@@ -1,6 +1,6 @@
{
"Albums": "專輯",
- "AppDeviceValues": "軟件: {0}, 設備: {1}",
+ "AppDeviceValues": "程式: {0}, 設備: {1}",
"Application": "應用程式",
"Artists": "藝人",
"AuthenticationSucceededWithUserName": "{0} 授權成功",
@@ -113,5 +113,6 @@
"TaskCleanCacheDescription": "刪除系統不再需要的緩存文件。",
"TaskCleanCache": "清理緩存目錄",
"TasksChannelsCategory": "互聯網頻道",
- "TasksLibraryCategory": "庫"
+ "TasksLibraryCategory": "庫",
+ "TaskRefreshPeople": "刷新人物"
}
diff --git a/Emby.Server.Implementations/Net/SocketFactory.cs b/Emby.Server.Implementations/Net/SocketFactory.cs
index f347540c7..0781a0e33 100644
--- a/Emby.Server.Implementations/Net/SocketFactory.cs
+++ b/Emby.Server.Implementations/Net/SocketFactory.cs
@@ -19,6 +19,7 @@ namespace Emby.Server.Implementations.Net
var retVal = new Socket(AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp);
try
{
+ retVal.EnableBroadcast = true;
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
@@ -46,6 +47,7 @@ namespace Emby.Server.Implementations.Net
var retVal = new Socket(AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Dgram, System.Net.Sockets.ProtocolType.Udp);
try
{
+ retVal.EnableBroadcast = true;
retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 4);
@@ -98,7 +100,6 @@ namespace Emby.Server.Implementations.Net
}
catch (SocketException)
{
-
}
try
@@ -109,12 +110,12 @@ namespace Emby.Server.Implementations.Net
}
catch (SocketException)
{
-
}
try
{
- //retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
+ retVal.EnableBroadcast = 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/Net/UdpSocket.cs b/Emby.Server.Implementations/Net/UdpSocket.cs
index 848f82d85..b51c03446 100644
--- a/Emby.Server.Implementations/Net/UdpSocket.cs
+++ b/Emby.Server.Implementations/Net/UdpSocket.cs
@@ -37,7 +37,10 @@ namespace Emby.Server.Implementations.Net
public UdpSocket(Socket socket, int localPort, IPAddress ip)
{
- if (socket == null) throw new ArgumentNullException(nameof(socket));
+ if (socket == null)
+ {
+ throw new ArgumentNullException(nameof(socket));
+ }
_socket = socket;
_localPort = localPort;
@@ -103,7 +106,10 @@ namespace Emby.Server.Implementations.Net
public UdpSocket(Socket socket, IPEndPoint endPoint)
{
- if (socket == null) throw new ArgumentNullException(nameof(socket));
+ if (socket == null)
+ {
+ throw new ArgumentNullException(nameof(socket));
+ }
_socket = socket;
_socket.Connect(endPoint);
diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs
index 45864bb42..50cb44b28 100644
--- a/Emby.Server.Implementations/Networking/NetworkManager.cs
+++ b/Emby.Server.Implementations/Networking/NetworkManager.cs
@@ -2,7 +2,6 @@
using System;
using System.Collections.Generic;
-using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
@@ -13,6 +12,9 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Networking
{
+ /// <summary>
+ /// Class to take care of network interface management.
+ /// </summary>
public class NetworkManager : INetworkManager
{
private readonly ILogger<NetworkManager> _logger;
@@ -21,8 +23,14 @@ namespace Emby.Server.Implementations.Networking
private readonly object _localIpAddressSyncLock = new object();
private readonly object _subnetLookupLock = new object();
- private Dictionary<string, List<string>> _subnetLookup = new Dictionary<string, List<string>>(StringComparer.Ordinal);
+ private readonly Dictionary<string, List<string>> _subnetLookup = new Dictionary<string, List<string>>(StringComparer.Ordinal);
+ private List<PhysicalAddress> _macAddresses;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="NetworkManager"/> class.
+ /// </summary>
+ /// <param name="logger">Logger to use for messages.</param>
public NetworkManager(ILogger<NetworkManager> logger)
{
_logger = logger;
@@ -31,8 +39,10 @@ namespace Emby.Server.Implementations.Networking
NetworkChange.NetworkAvailabilityChanged += OnNetworkAvailabilityChanged;
}
+ /// <inheritdoc/>
public event EventHandler NetworkChanged;
+ /// <inheritdoc/>
public Func<string[]> LocalSubnetsFn { get; set; }
private void OnNetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
@@ -58,13 +68,14 @@ namespace Emby.Server.Implementations.Networking
NetworkChanged?.Invoke(this, EventArgs.Empty);
}
- public IPAddress[] GetLocalIpAddresses(bool ignoreVirtualInterface = true)
+ /// <inheritdoc/>
+ public IPAddress[] GetLocalIpAddresses()
{
lock (_localIpAddressSyncLock)
{
if (_localIpAddresses == null)
{
- var addresses = GetLocalIpAddressesInternal(ignoreVirtualInterface).ToArray();
+ var addresses = GetLocalIpAddressesInternal().ToArray();
_localIpAddresses = addresses;
}
@@ -73,42 +84,47 @@ namespace Emby.Server.Implementations.Networking
}
}
- private List<IPAddress> GetLocalIpAddressesInternal(bool ignoreVirtualInterface)
+ private List<IPAddress> GetLocalIpAddressesInternal()
{
- var list = GetIPsDefault(ignoreVirtualInterface).ToList();
+ var list = GetIPsDefault().ToList();
if (list.Count == 0)
{
list = GetLocalIpAddressesFallback().GetAwaiter().GetResult().ToList();
}
- var listClone = list.ToList();
+ var listClone = new List<IPAddress>();
- return list
- .OrderBy(i => i.AddressFamily == AddressFamily.InterNetwork ? 0 : 1)
- .ThenBy(i => listClone.IndexOf(i))
- .Where(FilterIpAddress)
- .GroupBy(i => i.ToString())
- .Select(x => x.First())
- .ToList();
- }
+ var subnets = LocalSubnetsFn();
- private static bool FilterIpAddress(IPAddress address)
- {
- if (address.IsIPv6LinkLocal
- || address.ToString().StartsWith("169.", StringComparison.OrdinalIgnoreCase))
+ foreach (var i in list)
{
- return false;
+ if (i.IsIPv6LinkLocal || i.ToString().StartsWith("169.254.", StringComparison.OrdinalIgnoreCase))
+ {
+ continue;
+ }
+
+ if (Array.IndexOf(subnets, $"[{i}]") == -1)
+ {
+ listClone.Add(i);
+ }
}
- return true;
+ return listClone
+ .OrderBy(i => i.AddressFamily == AddressFamily.InterNetwork ? 0 : 1)
+ // .ThenBy(i => listClone.IndexOf(i))
+ .GroupBy(i => i.ToString())
+ .Select(x => x.First())
+ .ToList();
}
+ /// <inheritdoc/>
public bool IsInPrivateAddressSpace(string endpoint)
{
return IsInPrivateAddressSpace(endpoint, true);
}
+ // Checks if the address in endpoint is an RFC1918, RFC1122, or RFC3927 address
private bool IsInPrivateAddressSpace(string endpoint, bool checkSubnets)
{
if (string.Equals(endpoint, "::1", StringComparison.OrdinalIgnoreCase))
@@ -116,12 +132,12 @@ namespace Emby.Server.Implementations.Networking
return true;
}
- // ipv6
+ // IPV6
if (endpoint.Split('.').Length > 4)
{
// Handle ipv4 mapped to ipv6
var originalEndpoint = endpoint;
- endpoint = endpoint.Replace("::ffff:", string.Empty);
+ endpoint = endpoint.Replace("::ffff:", string.Empty, StringComparison.OrdinalIgnoreCase);
if (string.Equals(endpoint, originalEndpoint, StringComparison.OrdinalIgnoreCase))
{
@@ -130,23 +146,26 @@ namespace Emby.Server.Implementations.Networking
}
// Private address space:
- // http://en.wikipedia.org/wiki/Private_network
- if (endpoint.StartsWith("172.", StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(endpoint, "localhost", StringComparison.OrdinalIgnoreCase))
{
- return Is172AddressPrivate(endpoint);
+ return true;
}
- if (endpoint.StartsWith("localhost", StringComparison.OrdinalIgnoreCase) ||
- endpoint.StartsWith("127.", StringComparison.OrdinalIgnoreCase) ||
- endpoint.StartsWith("169.", StringComparison.OrdinalIgnoreCase))
+ if (!IPAddress.TryParse(endpoint, out var ipAddress))
{
- return true;
+ return false;
}
- if (checkSubnets && endpoint.StartsWith("192.168", StringComparison.OrdinalIgnoreCase))
+ byte[] octet = ipAddress.GetAddressBytes();
+
+ if ((octet[0] == 10) ||
+ (octet[0] == 172 && (octet[1] >= 16 && octet[1] <= 31)) || // RFC1918
+ (octet[0] == 192 && octet[1] == 168) || // RFC1918
+ (octet[0] == 127) || // RFC1122
+ (octet[0] == 169 && octet[1] == 254)) // RFC3927
{
- return true;
+ return false;
}
if (checkSubnets && IsInPrivateAddressSpaceAndLocalSubnet(endpoint))
@@ -157,6 +176,7 @@ namespace Emby.Server.Implementations.Networking
return false;
}
+ /// <inheritdoc/>
public bool IsInPrivateAddressSpaceAndLocalSubnet(string endpoint)
{
if (endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase))
@@ -167,7 +187,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))
{
@@ -179,6 +199,7 @@ namespace Emby.Server.Implementations.Networking
return false;
}
+ // Gives a list of possible subnets from the system whose interface ip starts with endpointFirstPart
private List<string> GetSubnets(string endpointFirstPart)
{
lock (_subnetLookupLock)
@@ -224,46 +245,81 @@ namespace Emby.Server.Implementations.Networking
}
}
- private static bool Is172AddressPrivate(string endpoint)
- {
- for (var i = 16; i <= 31; i++)
- {
- if (endpoint.StartsWith("172." + i.ToString(CultureInfo.InvariantCulture) + ".", StringComparison.OrdinalIgnoreCase))
- {
- return true;
- }
- }
-
- return false;
- }
-
+ /// <inheritdoc/>
public bool IsInLocalNetwork(string endpoint)
{
return IsInLocalNetworkInternal(endpoint, true);
}
+ /// <inheritdoc/>
public bool IsAddressInSubnets(string addressString, string[] subnets)
{
return IsAddressInSubnets(IPAddress.Parse(addressString), addressString, subnets);
}
+ /// <inheritdoc/>
+ public bool IsAddressInSubnets(IPAddress address, bool excludeInterfaces, bool excludeRFC)
+ {
+ byte[] octet = address.GetAddressBytes();
+
+ if ((octet[0] == 127) || // RFC1122
+ (octet[0] == 169 && octet[1] == 254)) // RFC3927
+ {
+ // don't use on loopback or 169 interfaces
+ return false;
+ }
+
+ string addressString = address.ToString();
+ string excludeAddress = "[" + addressString + "]";
+ var subnets = LocalSubnetsFn();
+
+ // Include any address if LAN subnets aren't specified
+ if (subnets.Length == 0)
+ {
+ return true;
+ }
+
+ // Exclude any addresses if they appear in the LAN list in [ ]
+ if (Array.IndexOf(subnets, excludeAddress) != -1)
+ {
+ return false;
+ }
+
+ return IsAddressInSubnets(address, addressString, subnets);
+ }
+
+ /// <summary>
+ /// Checks if the give address falls within the ranges given in [subnets]. The addresses in subnets can be hosts or subnets in the CIDR format.
+ /// </summary>
+ /// <param name="address">IPAddress version of the address.</param>
+ /// <param name="addressString">The address to check.</param>
+ /// <param name="subnets">If true, check against addresses in the LAN settings which have [] arroud and return true if it matches the address give in address.</param>
+ /// <returns><c>false</c>if the address isn't in the subnets, <c>true</c> otherwise.</returns>
private static bool IsAddressInSubnets(IPAddress address, string addressString, string[] subnets)
{
foreach (var subnet in subnets)
{
var normalizedSubnet = subnet.Trim();
-
+ // Is the subnet a host address and does it match the address being passes?
if (string.Equals(normalizedSubnet, addressString, StringComparison.OrdinalIgnoreCase))
{
return true;
}
+ // Parse CIDR subnets and see if address falls within it.
if (normalizedSubnet.Contains('/', StringComparison.Ordinal))
{
- var ipNetwork = IPNetwork.Parse(normalizedSubnet);
- if (ipNetwork.Contains(address))
+ try
{
- return true;
+ var ipNetwork = IPNetwork.Parse(normalizedSubnet);
+ if (ipNetwork.Contains(address))
+ {
+ return true;
+ }
+ }
+ catch
+ {
+ // Ignoring - invalid subnet passed encountered.
}
}
}
@@ -288,7 +344,7 @@ namespace Emby.Server.Implementations.Networking
var localSubnets = localSubnetsFn();
foreach (var subnet in localSubnets)
{
- // only validate if there's at least one valid entry
+ // Only validate if there's at least one valid entry.
if (!string.IsNullOrWhiteSpace(subnet))
{
return IsAddressInSubnets(address, addressString, localSubnets) || IsInPrivateAddressSpace(addressString, false);
@@ -345,7 +401,7 @@ namespace Emby.Server.Implementations.Networking
}
catch (InvalidOperationException)
{
- // Can happen with reverse proxy or IIS url rewriting
+ // Can happen with reverse proxy or IIS url rewriting?
}
catch (Exception ex)
{
@@ -362,7 +418,7 @@ namespace Emby.Server.Implementations.Networking
return Dns.GetHostAddressesAsync(hostName);
}
- private IEnumerable<IPAddress> GetIPsDefault(bool ignoreVirtualInterface)
+ private IEnumerable<IPAddress> GetIPsDefault()
{
IEnumerable<NetworkInterface> interfaces;
@@ -382,15 +438,7 @@ namespace Emby.Server.Implementations.Networking
{
var ipProperties = network.GetIPProperties();
- // Try to exclude virtual adapters
- // http://stackoverflow.com/questions/8089685/c-sharp-finding-my-machines-local-ip-address-and-not-the-vms
- var addr = ipProperties.GatewayAddresses.FirstOrDefault();
- if (addr == null
- || (ignoreVirtualInterface
- && (addr.Address.Equals(IPAddress.Any) || addr.Address.Equals(IPAddress.IPv6Any))))
- {
- return Enumerable.Empty<IPAddress>();
- }
+ // Exclude any addresses if they appear in the LAN list in [ ]
return ipProperties.UnicastAddresses
.Select(i => i.Address)
@@ -411,7 +459,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()
@@ -423,33 +471,29 @@ namespace Emby.Server.Implementations.Networking
return port;
}
+ /// <inheritdoc/>
public int GetRandomUnusedUdpPort()
{
var localEndPoint = new IPEndPoint(IPAddress.Any, 0);
using (var udpClient = new UdpClient(localEndPoint))
{
- var port = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port;
- return port;
+ return ((IPEndPoint)udpClient.Client.LocalEndPoint).Port;
}
}
- private List<PhysicalAddress> _macAddresses;
+ /// <inheritdoc/>
public List<PhysicalAddress> GetMacAddresses()
{
- if (_macAddresses == null)
- {
- _macAddresses = GetMacAddressesInternal().ToList();
- }
-
- return _macAddresses;
+ return _macAddresses ??= GetMacAddressesInternal().ToList();
}
private static IEnumerable<PhysicalAddress> GetMacAddressesInternal()
=> NetworkInterface.GetAllNetworkInterfaces()
.Where(i => i.NetworkInterfaceType != NetworkInterfaceType.Loopback)
.Select(x => x.GetPhysicalAddress())
- .Where(x => x != null && x != PhysicalAddress.None);
+ .Where(x => !x.Equals(PhysicalAddress.None));
+ /// <inheritdoc/>
public bool IsInSameSubnet(IPAddress address1, IPAddress address2, IPAddress subnetMask)
{
IPAddress network1 = GetNetworkAddress(address1, subnetMask);
@@ -476,6 +520,7 @@ namespace Emby.Server.Implementations.Networking
return new IPAddress(broadcastAddress);
}
+ /// <inheritdoc/>
public IPAddress GetLocalIpSubnetMask(IPAddress address)
{
NetworkInterface[] interfaces;
@@ -496,14 +541,11 @@ namespace Emby.Server.Implementations.Networking
foreach (NetworkInterface ni in interfaces)
{
- if (ni.GetIPProperties().GatewayAddresses.FirstOrDefault() != null)
+ foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses)
{
- foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses)
+ if (ip.Address.Equals(address) && ip.IPv4Mask != null)
{
- if (ip.Address.Equals(address) && ip.IPv4Mask != null)
- {
- return ip.IPv4Mask;
- }
+ return ip.IPv4Mask;
}
}
}
diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
index 9feef5d8d..5dd1af4b8 100644
--- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs
+++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs
@@ -401,6 +401,7 @@ namespace Emby.Server.Implementations.Playlists
{
entry.Duration = TimeSpan.FromTicks(child.RunTimeTicks.Value);
}
+
playlist.PlaylistEntries.Add(entry);
}
@@ -466,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);
}
@@ -538,13 +539,21 @@ namespace Emby.Server.Implementations.Playlists
private static string UnEscape(string content)
{
- if (content == null) return content;
+ if (content == null)
+ {
+ return content;
+ }
+
return content.Replace("&amp;", "&").Replace("&apos;", "'").Replace("&quot;", "\"").Replace("&gt;", ">").Replace("&lt;", "<");
}
private static string Escape(string content)
{
- if (content == null) return null;
+ if (content == null)
+ {
+ return null;
+ }
+
return content.Replace("&", "&amp;").Replace("'", "&apos;").Replace("\"", "&quot;").Replace(">", "&gt;").Replace("<", "&lt;");
}
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..3fe15ec68 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>()
@@ -95,7 +95,7 @@ namespace Emby.Server.Implementations.ScheduledTasks
/// Queues the scheduled task.
/// </summary>
/// <typeparam name="T"></typeparam>
- /// <param name="options">Task options</param>
+ /// <param name="options">Task options.</param>
public void QueueScheduledTask<T>(TaskOptions options)
where T : IScheduledTask
{
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..4dfadc703 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[]
@@ -99,7 +98,7 @@ namespace Emby.Server.Implementations.Security
statement.TryBind("@AppName", info.AppName);
statement.TryBind("@AppVersion", info.AppVersion);
statement.TryBind("@DeviceName", info.DeviceName);
- statement.TryBind("@UserId", (info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N", CultureInfo.InvariantCulture)));
+ statement.TryBind("@UserId", info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N", CultureInfo.InvariantCulture));
statement.TryBind("@UserName", info.UserName);
statement.TryBind("@IsActive", true);
statement.TryBind("@DateCreated", info.DateCreated.ToDateTimeParamValue());
@@ -107,7 +106,6 @@ namespace Emby.Server.Implementations.Security
statement.MoveNext();
}
-
}, TransactionMode);
}
}
@@ -133,7 +131,7 @@ namespace Emby.Server.Implementations.Security
statement.TryBind("@AppName", info.AppName);
statement.TryBind("@AppVersion", info.AppVersion);
statement.TryBind("@DeviceName", info.DeviceName);
- statement.TryBind("@UserId", (info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N", CultureInfo.InvariantCulture)));
+ statement.TryBind("@UserId", info.UserId.Equals(Guid.Empty) ? null : info.UserId.ToString("N", CultureInfo.InvariantCulture));
statement.TryBind("@UserName", info.UserName);
statement.TryBind("@DateCreated", info.DateCreated.ToDateTimeParamValue());
statement.TryBind("@DateLastActivity", info.DateLastActivity.ToDateTimeParamValue());
@@ -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..a329b531d 100644
--- a/Emby.Server.Implementations/Services/ResponseHelper.cs
+++ b/Emby.Server.Implementations/Services/ResponseHelper.cs
@@ -40,7 +40,9 @@ namespace Emby.Server.Implementations.Services
if (httpResult != null)
{
if (httpResult.RequestContext == null)
+ {
httpResult.RequestContext = request;
+ }
response.StatusCode = httpResult.Status;
}
@@ -59,8 +61,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..857df591a 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
@@ -144,7 +144,10 @@ namespace Emby.Server.Implementations.Services
var yieldedWildcardMatches = RestPath.GetFirstMatchWildCardHashKeys(matchUsingPathParts);
foreach (var potentialHashMatch in yieldedWildcardMatches)
{
- if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches)) continue;
+ if (!this.RestPathMap.TryGetValue(potentialHashMatch, out firstMatches))
+ {
+ continue;
+ }
var bestScore = -1;
RestPath bestMatch = null;
@@ -182,7 +185,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/ServiceExec.cs b/Emby.Server.Implementations/Services/ServiceExec.cs
index 606f2a240..cbc4b754d 100644
--- a/Emby.Server.Implementations/Services/ServiceExec.cs
+++ b/Emby.Server.Implementations/Services/ServiceExec.cs
@@ -42,11 +42,15 @@ namespace Emby.Server.Implementations.Services
}
if (mi.GetParameters().Length != 1)
+ {
continue;
+ }
var actionName = mi.Name;
if (!AllVerbs.Contains(actionName, StringComparer.OrdinalIgnoreCase))
+ {
continue;
+ }
list.Add(mi);
}
@@ -63,7 +67,10 @@ namespace Emby.Server.Implementations.Services
{
foreach (var actionCtx in actions)
{
- if (execMap.ContainsKey(actionCtx.Id)) continue;
+ if (execMap.ContainsKey(actionCtx.Id))
+ {
+ continue;
+ }
execMap[actionCtx.Id] = actionCtx;
}
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..89538ae72 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,11 +120,14 @@ 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))
{
- if (string.IsNullOrEmpty(component)) continue;
+ if (string.IsNullOrEmpty(component))
+ {
+ continue;
+ }
if (component.IndexOf(VariablePrefix, StringComparison.OrdinalIgnoreCase) != -1
&& component.IndexOf(ComponentSeperator) != -1)
@@ -159,6 +164,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 +304,12 @@ namespace Emby.Server.Implementations.Services
return -1;
}
- //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
- + Math.Max((10 - VariableArgsCount), 1) * 100;
+ // 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
+ + 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;
@@ -439,12 +445,14 @@ namespace Emby.Server.Implementations.Services
&& requestComponents.Length >= this.TotalComponentsCount - this.wildcardCount;
if (!isValidWildCardPath)
+ {
throw new ArgumentException(
string.Format(
CultureInfo.InvariantCulture,
"Path Mismatch: Request Path '{0}' has invalid number of components compared to: '{1}'",
pathInfo,
this.restPath));
+ }
}
var requestKeyValuesMap = new Dictionary<string, string>();
@@ -470,7 +478,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 +527,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 07e443ef5..ca9f95c70 100644
--- a/Emby.Server.Implementations/Session/SessionManager.cs
+++ b/Emby.Server.Implementations/Session/SessionManager.cs
@@ -296,7 +296,7 @@ namespace Emby.Server.Implementations.Session
}
catch (DbUpdateConcurrencyException e)
{
- _logger.LogWarning(e, "Error updating user's last activity date.");
+ _logger.LogDebug(e, "Error updating user's last activity date.");
}
}
}
@@ -502,7 +502,8 @@ namespace Emby.Server.Implementations.Session
Client = appName,
DeviceId = deviceId,
ApplicationVersion = appVersion,
- Id = key.GetMD5().ToString("N", CultureInfo.InvariantCulture)
+ Id = key.GetMD5().ToString("N", CultureInfo.InvariantCulture),
+ ServerId = _appHost.SystemId
};
var username = user?.Username;
@@ -843,7 +844,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>
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..cbca300d2 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
{
@@ -19,10 +19,14 @@ namespace Emby.Server.Implementations.Sorting
public int Compare(BaseItem x, BaseItem y)
{
if (x == null)
+ {
throw new ArgumentNullException(nameof(x));
+ }
if (y == null)
+ {
throw new ArgumentNullException(nameof(y));
+ }
return DateTime.Compare(x.DateCreated, y.DateCreated);
}
diff --git a/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs b/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs
index 5e527ea25..16bd2aff8 100644
--- a/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs
+++ b/Emby.Server.Implementations/Sorting/DatePlayedComparer.cs
@@ -8,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/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 afbaaf6ab..5c2830322 100644
--- a/Emby.Server.Implementations/Sorting/PlayCountComparer.cs
+++ b/Emby.Server.Implementations/Sorting/PlayCountComparer.cs
@@ -7,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..dde44333d 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
{
@@ -19,10 +19,14 @@ namespace Emby.Server.Implementations.Sorting
public int Compare(BaseItem x, BaseItem y)
{
if (x == null)
+ {
throw new ArgumentNullException(nameof(x));
+ }
if (y == null)
+ {
throw new ArgumentNullException(nameof(y));
+ }
return (x.RunTimeTicks ?? 0).CompareTo(y.RunTimeTicks ?? 0);
}
diff --git a/Emby.Server.Implementations/Sorting/SortNameComparer.cs b/Emby.Server.Implementations/Sorting/SortNameComparer.cs
index cc0571c78..f745e193b 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
{
@@ -19,10 +19,14 @@ namespace Emby.Server.Implementations.Sorting
public int Compare(BaseItem x, BaseItem y)
{
if (x == null)
+ {
throw new ArgumentNullException(nameof(x));
+ }
if (y == null)
+ {
throw new ArgumentNullException(nameof(y));
+ }
return string.Compare(x.SortName, y.SortName, StringComparison.CurrentCultureIgnoreCase);
}
diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayController.cs
index d0812a13f..39d17833f 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>();
}
@@ -199,26 +194,24 @@ namespace Emby.Server.Implementations.SyncPlay
}
/// <inheritdoc />
- public void InitGroup(SessionInfo session, CancellationToken cancellationToken)
+ public void CreateGroup(SessionInfo session, CancellationToken cancellationToken)
{
_group.AddSession(session);
_syncPlayManager.AddSessionToGroup(session, this);
_group.PlayingItem = session.FullNowPlayingItem;
- _group.IsPaused = true;
+ _group.IsPaused = session.PlayState.IsPaused;
_group.PositionTicks = session.PlayState.PositionTicks ?? 0;
_group.LastActivity = DateTime.UtcNow;
var updateSession = NewSyncPlayGroupUpdate(GroupUpdateType.GroupJoined, DateToUTCString(DateTime.UtcNow));
SendGroupUpdate(session, BroadcastType.CurrentSession, updateSession, cancellationToken);
- var pauseCommand = NewSyncPlayCommand(SendCommandType.Pause);
- SendCommand(session, BroadcastType.CurrentSession, pauseCommand, cancellationToken);
}
/// <inheritdoc />
public void SessionJoin(SessionInfo session, JoinGroupRequest request, CancellationToken cancellationToken)
{
- if (session.NowPlayingItem?.Id == _group.PlayingItem.Id && request.PlayingItemId == _group.PlayingItem.Id)
+ if (session.NowPlayingItem?.Id == _group.PlayingItem.Id)
{
_group.AddSession(session);
_syncPlayManager.AddSessionToGroup(session, this);
@@ -229,7 +222,7 @@ namespace Emby.Server.Implementations.SyncPlay
var updateOthers = NewSyncPlayGroupUpdate(GroupUpdateType.UserJoined, session.UserName);
SendGroupUpdate(session, BroadcastType.AllExceptCurrentSession, updateOthers, cancellationToken);
- // Client join and play, syncing will happen client side
+ // Syncing will happen client-side
if (!_group.IsPaused)
{
var playCommand = NewSyncPlayCommand(SendCommandType.Play);
@@ -267,10 +260,9 @@ namespace Emby.Server.Implementations.SyncPlay
/// <inheritdoc />
public void HandleRequest(SessionInfo session, PlaybackRequest request, CancellationToken cancellationToken)
{
- // The server's job is to mantain a consistent state to which clients refer to,
- // as also to notify clients of state changes.
- // The actual syncing of media playback happens client side.
- // Clients are aware of the server's time and use it to sync.
+ // The server's job is to maintain a consistent state for clients to reference
+ // and notify clients of state changes. The actual syncing of media playback
+ // happens client side. Clients are aware of the server's time and use it to sync.
switch (request.Type)
{
case PlaybackRequestType.Play:
@@ -282,13 +274,13 @@ namespace Emby.Server.Implementations.SyncPlay
case PlaybackRequestType.Seek:
HandleSeekRequest(session, request, cancellationToken);
break;
- case PlaybackRequestType.Buffering:
+ case PlaybackRequestType.Buffer:
HandleBufferingRequest(session, request, cancellationToken);
break;
- case PlaybackRequestType.BufferingDone:
+ case PlaybackRequestType.Ready:
HandleBufferingDoneRequest(session, request, cancellationToken);
break;
- case PlaybackRequestType.UpdatePing:
+ case PlaybackRequestType.Ping:
HandlePingUpdateRequest(session, request);
break;
}
@@ -306,7 +298,7 @@ namespace Emby.Server.Implementations.SyncPlay
{
// Pick a suitable time that accounts for latency
var delay = _group.GetHighestPing() * 2;
- delay = delay < _group.DefaulPing ? _group.DefaulPing : delay;
+ delay = delay < _group.DefaultPing ? _group.DefaultPing : delay;
// Unpause group and set starting point in future
// Clients will start playback at LastActivity (datetime) from PositionTicks (playback position)
@@ -314,8 +306,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);
@@ -343,8 +334,9 @@ namespace Emby.Server.Implementations.SyncPlay
var currentTime = DateTime.UtcNow;
var elapsedTime = currentTime - _group.LastActivity;
_group.LastActivity = currentTime;
+
// Seek only if playback actually started
- // (a pause request may be issued during the delay added to account for latency)
+ // Pause request may be issued during the delay added to account for latency
_group.PositionTicks += elapsedTime.Ticks > 0 ? elapsedTime.Ticks : 0;
var command = NewSyncPlayCommand(SendCommandType.Pause);
@@ -449,8 +441,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);
}
@@ -458,11 +449,10 @@ namespace Emby.Server.Implementations.SyncPlay
{
// Client, that was buffering, resumed playback but did not update others in time
delay = _group.GetHighestPing() * 2;
- delay = delay < _group.DefaulPing ? _group.DefaulPing : delay;
+ delay = delay < _group.DefaultPing ? _group.DefaultPing : delay;
_group.LastActivity = currentTime.AddMilliseconds(
- delay
- );
+ delay);
var command = NewSyncPlayCommand(SendCommandType.Play);
SendCommand(session, BroadcastType.AllGroup, command, cancellationToken);
@@ -503,7 +493,7 @@ namespace Emby.Server.Implementations.SyncPlay
private void HandlePingUpdateRequest(SessionInfo session, PlaybackRequest request)
{
// Collected pings are used to account for network latency when unpausing playback
- _group.UpdatePing(session, request.Ping ?? _group.DefaulPing);
+ _group.UpdatePing(session, request.Ping ?? _group.DefaultPing);
}
/// <inheritdoc />
diff --git a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs
index ecc3eeb39..966ed5024 100644
--- a/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs
+++ b/Emby.Server.Implementations/SyncPlay/SyncPlayManager.cs
@@ -170,10 +170,11 @@ namespace Emby.Server.Implementations.SyncPlay
{
_logger.LogWarning("NewGroup: {0} does not have permission to create groups.", session.Id);
- var error = new GroupUpdate<string>()
+ var error = new GroupUpdate<string>
{
Type = GroupUpdateType.CreateGroupDenied
};
+
_sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
return;
}
@@ -188,7 +189,7 @@ namespace Emby.Server.Implementations.SyncPlay
var group = new SyncPlayController(_sessionManager, this);
_groups[group.GetGroupId()] = group;
- group.InitGroup(session, cancellationToken);
+ group.CreateGroup(session, cancellationToken);
}
}
@@ -205,6 +206,7 @@ namespace Emby.Server.Implementations.SyncPlay
{
Type = GroupUpdateType.JoinGroupDenied
};
+
_sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
return;
}
@@ -297,19 +299,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
{
+ // Otherwise show all available groups
return _groups.Values.Where(
- group => HasAccessToItem(user, group.GetPlayingItemId())
- ).Select(
- group => group.GetInfo()
- ).ToList();
+ group => HasAccessToItem(user, group.GetPlayingItemId())).Select(
+ group => group.GetInfo()).ToList();
}
}
@@ -326,6 +324,7 @@ namespace Emby.Server.Implementations.SyncPlay
{
Type = GroupUpdateType.JoinGroupDenied
};
+
_sessionManager.SendSyncPlayGroupUpdate(session.Id, error, CancellationToken.None);
return;
}
@@ -370,7 +369,6 @@ namespace Emby.Server.Implementations.SyncPlay
}
_sessionToGroupMap.Remove(session.Id, out var tempGroup);
-
if (!tempGroup.GetGroupId().Equals(group.GetGroupId()))
{
throw new InvalidOperationException("Session was in wrong group!");
diff --git a/Emby.Server.Implementations/TV/TVSeriesManager.cs b/Emby.Server.Implementations/TV/TVSeriesManager.cs
index 6999668d1..d1818deff 100644
--- a/Emby.Server.Implementations/TV/TVSeriesManager.cs
+++ b/Emby.Server.Implementations/TV/TVSeriesManager.cs
@@ -117,23 +117,20 @@ namespace Emby.Server.Implementations.TV
limit = limit.Value + 10;
}
- var items = _libraryManager.GetItemList(new InternalItemsQuery(user)
- {
- IncludeItemTypes = new[] { typeof(Episode).Name },
- OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.DatePlayed, SortOrder.Descending) },
- SeriesPresentationUniqueKey = presentationUniqueKey,
- Limit = limit,
- DtoOptions = new DtoOptions
- {
- Fields = new ItemFields[]
+ var items = _libraryManager
+ .GetItemList(
+ new InternalItemsQuery(user)
{
- ItemFields.SeriesPresentationUniqueKey
- },
- EnableImages = false
- },
- GroupBySeriesPresentationUniqueKey = true
-
- }, parentsFolders.ToList()).Cast<Episode>().Select(GetUniqueSeriesKey);
+ IncludeItemTypes = new[] { typeof(Episode).Name },
+ OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.DatePlayed, SortOrder.Descending) },
+ SeriesPresentationUniqueKey = presentationUniqueKey,
+ Limit = limit,
+ DtoOptions = new DtoOptions { Fields = new[] { ItemFields.SeriesPresentationUniqueKey }, EnableImages = false },
+ GroupBySeriesPresentationUniqueKey = true
+ }, parentsFolders.ToList())
+ .Cast<Episode>()
+ .Where(episode => !string.IsNullOrEmpty(episode.SeriesPresentationUniqueKey))
+ .Select(GetUniqueSeriesKey);
// Avoid implicitly captured closure
var episodes = GetNextUpEpisodes(request, user, items, dtoOptions);
@@ -149,7 +146,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)
@@ -225,7 +222,6 @@ namespace Emby.Server.Implementations.TV
ParentIndexNumberNotEquals = 0,
MinSortName = lastWatchedEpisode?.SortName,
DtoOptions = dtoOptions
-
}).Cast<Episode>().FirstOrDefault();
};
@@ -257,6 +253,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..73fcbcec3 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;
@@ -101,11 +101,18 @@ namespace Emby.Server.Implementations.Udp
{
while (!cancellationToken.IsCancellationRequested)
{
+ var infiniteTask = Task.Delay(-1, cancellationToken);
try
{
- var result = await _udpSocket.ReceiveFromAsync(_receiveBuffer, SocketFlags.None, _endpoint).ConfigureAwait(false);
+ var task = _udpSocket.ReceiveFromAsync(_receiveBuffer, SocketFlags.None, _endpoint);
+ await Task.WhenAny(task, infiniteTask).ConfigureAwait(false);
- cancellationToken.ThrowIfCancellationRequested();
+ if (!task.IsCompleted)
+ {
+ return;
+ }
+
+ var result = task.Result;
var text = Encoding.UTF8.GetString(_receiveBuffer, 0, result.ReceivedBytes);
if (text.Contains("who is JellyfinServer?", StringComparison.OrdinalIgnoreCase))
diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs
index 80326fddf..4f54c06dd 100644
--- a/Emby.Server.Implementations/Updates/InstallationManager.cs
+++ b/Emby.Server.Implementations/Updates/InstallationManager.cs
@@ -1,7 +1,6 @@
#pragma warning disable CS1591
using System;
-using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
@@ -17,11 +16,10 @@ using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Updates;
using MediaBrowser.Controller.Configuration;
-using MediaBrowser.Model.Events;
using MediaBrowser.Model.IO;
+using MediaBrowser.Model.Net;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Updates;
-using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Updates
@@ -32,11 +30,6 @@ namespace Emby.Server.Implementations.Updates
public class InstallationManager : IInstallationManager
{
/// <summary>
- /// The key for a setting that specifies a URL for the plugin repository JSON manifest.
- /// </summary>
- public const string PluginManifestUrlKey = "InstallationManager:PluginManifestUrl";
-
- /// <summary>
/// The logger.
/// </summary>
private readonly ILogger<InstallationManager> _logger;
@@ -53,7 +46,6 @@ namespace Emby.Server.Implementations.Updates
private readonly IApplicationHost _applicationHost;
private readonly IZipClient _zipClient;
- private readonly IConfiguration _appConfig;
private readonly object _currentInstallationsLock = new object();
@@ -75,8 +67,7 @@ namespace Emby.Server.Implementations.Updates
IJsonSerializer jsonSerializer,
IServerConfigurationManager config,
IFileSystem fileSystem,
- IZipClient zipClient,
- IConfiguration appConfig)
+ IZipClient zipClient)
{
if (logger == null)
{
@@ -94,7 +85,6 @@ namespace Emby.Server.Implementations.Updates
_config = config;
_fileSystem = fileSystem;
_zipClient = zipClient;
- _appConfig = appConfig;
}
/// <inheritdoc />
@@ -122,16 +112,14 @@ namespace Emby.Server.Implementations.Updates
public IEnumerable<InstallationInfo> CompletedInstallations => _completedInstallationsInternal;
/// <inheritdoc />
- public async Task<IReadOnlyList<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken = default)
+ public async Task<IReadOnlyList<PackageInfo>> GetPackages(string manifest, CancellationToken cancellationToken = default)
{
- var manifestUrl = _appConfig.GetValue<string>(PluginManifestUrlKey);
-
try
{
using (var response = await _httpClient.SendAsync(
new HttpRequestOptions
{
- Url = manifestUrl,
+ Url = manifest,
CancellationToken = cancellationToken,
CacheMode = CacheMode.Unconditional,
CacheLength = TimeSpan.FromMinutes(3)
@@ -145,23 +133,38 @@ namespace Emby.Server.Implementations.Updates
}
catch (SerializationException ex)
{
- const string LogTemplate =
- "Failed to deserialize the plugin manifest retrieved from {PluginManifestUrl}. If you " +
- "have specified a custom plugin repository manifest URL with --plugin-manifest-url or " +
- PluginManifestUrlKey + ", please ensure that it is correct.";
- _logger.LogError(ex, LogTemplate, manifestUrl);
- throw;
+ _logger.LogError(ex, "Failed to deserialize the plugin manifest retrieved from {Manifest}", manifest);
+ return Array.Empty<PackageInfo>();
}
}
}
catch (UriFormatException ex)
{
- const string LogTemplate =
- "The URL configured for the plugin repository manifest URL is not valid: {PluginManifestUrl}. " +
- "Please check the URL configured by --plugin-manifest-url or " + PluginManifestUrlKey;
- _logger.LogError(ex, LogTemplate, manifestUrl);
- throw;
+ _logger.LogError(ex, "The URL configured for the plugin repository manifest URL is not valid: {Manifest}", manifest);
+ return Array.Empty<PackageInfo>();
+ }
+ catch (HttpException ex)
+ {
+ _logger.LogError(ex, "An error occurred while accessing the plugin manifest: {Manifest}", manifest);
+ return Array.Empty<PackageInfo>();
+ }
+ catch (HttpRequestException ex)
+ {
+ _logger.LogError(ex, "An error occurred while accessing the plugin manifest: {Manifest}", manifest);
+ return Array.Empty<PackageInfo>();
+ }
+ }
+
+ /// <inheritdoc />
+ public async Task<IReadOnlyList<PackageInfo>> GetAvailablePackages(CancellationToken cancellationToken = default)
+ {
+ var result = new List<PackageInfo>();
+ foreach (RepositoryInfo repository in _config.Configuration.PluginRepositories)
+ {
+ result.AddRange(await GetPackages(repository.Url, cancellationToken).ConfigureAwait(true));
}
+
+ return result;
}
/// <inheritdoc />
@@ -402,6 +405,12 @@ namespace Emby.Server.Implementations.Updates
/// <param name="plugin">The plugin.</param>
public void UninstallPlugin(IPlugin plugin)
{
+ if (!plugin.CanUninstall)
+ {
+ _logger.LogWarning("Attempt to delete non removable plugin {0}, ignoring request", plugin.Name);
+ return;
+ }
+
plugin.OnUninstalling();
// Remove it the quick way for now