Merge branch 'master' into embytv

This commit is contained in:
Bond_009
2020-01-10 21:16:46 +01:00
410 changed files with 5390 additions and 12613 deletions

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -39,6 +41,19 @@ namespace Emby.Server.Implementations.Activity
private readonly IServerApplicationHost _appHost;
private readonly IDeviceManager _deviceManager;
/// <summary>
/// Initializes a new instance of the <see cref="ActivityLogEntryPoint"/> class.
/// </summary>
/// <param name="logger"></param>
/// <param name="sessionManager"></param>
/// <param name="deviceManager"></param>
/// <param name="taskManager"></param>
/// <param name="activityManager"></param>
/// <param name="localization"></param>
/// <param name="installationManager"></param>
/// <param name="subManager"></param>
/// <param name="userManager"></param>
/// <param name="appHost"></param>
public ActivityLogEntryPoint(
ILogger<ActivityLogEntryPoint> logger,
ISessionManager sessionManager,

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Linq;
using MediaBrowser.Controller.Library;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;

View File

@@ -84,6 +84,7 @@ namespace Emby.Server.Implementations.AppBase
/// </summary>
/// <value>The logger.</value>
protected ILogger Logger { get; private set; }
/// <summary>
/// Gets the XML serializer.
/// </summary>
@@ -97,7 +98,7 @@ namespace Emby.Server.Implementations.AppBase
public IApplicationPaths CommonApplicationPaths { get; private set; }
/// <summary>
/// Gets the system configuration.
/// Gets or sets the system configuration.
/// </summary>
/// <value>The configuration.</value>
public BaseApplicationConfiguration CommonConfiguration
@@ -123,6 +124,7 @@ namespace Emby.Server.Implementations.AppBase
return _configuration;
}
}
protected set
{
_configuration = value;
@@ -131,6 +133,10 @@ namespace Emby.Server.Implementations.AppBase
}
}
/// <summary>
/// Adds parts.
/// </summary>
/// <param name="factories">The configuration factories.</param>
public virtual void AddParts(IEnumerable<IConfigurationFactory> factories)
{
_configurationFactories = factories.ToArray();
@@ -215,7 +221,7 @@ namespace Emby.Server.Implementations.AppBase
cachePath = CommonConfiguration.CachePath;
}
Logger.LogInformation("Setting cache path to " + cachePath);
Logger.LogInformation("Setting cache path: {Path}", cachePath);
((BaseApplicationPaths)CommonApplicationPaths).CachePath = cachePath;
}
@@ -223,7 +229,7 @@ namespace Emby.Server.Implementations.AppBase
/// Replaces the cache path.
/// </summary>
/// <param name="newConfig">The new configuration.</param>
/// <exception cref="DirectoryNotFoundException"></exception>
/// <exception cref="DirectoryNotFoundException">The new cache path doesn't exist.</exception>
private void ValidateCachePath(BaseApplicationConfiguration newConfig)
{
var newPath = newConfig.CachePath;
@@ -234,7 +240,7 @@ namespace Emby.Server.Implementations.AppBase
// Validate
if (!Directory.Exists(newPath))
{
throw new FileNotFoundException(
throw new DirectoryNotFoundException(
string.Format(
CultureInfo.InvariantCulture,
"{0} does not exist.",
@@ -245,6 +251,10 @@ namespace Emby.Server.Implementations.AppBase
}
}
/// <summary>
/// Ensures that we have write access to the path.
/// </summary>
/// <param name="path">The path.</param>
protected void EnsureWriteAccess(string path)
{
var file = Path.Combine(path, Guid.NewGuid().ToString());
@@ -257,6 +267,7 @@ namespace Emby.Server.Implementations.AppBase
return Path.Combine(CommonApplicationPaths.ConfigurationDirectoryPath, key.ToLowerInvariant() + ".xml");
}
/// <inheritdoc />
public object GetConfiguration(string key)
{
return _configurations.GetOrAdd(key, k =>
@@ -303,6 +314,7 @@ namespace Emby.Server.Implementations.AppBase
}
}
/// <inheritdoc />
public void SaveConfiguration(string key, object configuration)
{
var configurationStore = GetConfigurationStore(key);
@@ -339,6 +351,11 @@ namespace Emby.Server.Implementations.AppBase
OnNamedConfigurationUpdated(key, configuration);
}
/// <summary>
/// Event handler for when a named configuration has been updated.
/// </summary>
/// <param name="key">The key of the configuration.</param>
/// <param name="configuration">The old configuration.</param>
protected virtual void OnNamedConfigurationUpdated(string key, object configuration)
{
NamedConfigurationUpdated?.Invoke(this, new ConfigurationUpdateEventArgs
@@ -348,6 +365,7 @@ namespace Emby.Server.Implementations.AppBase
});
}
/// <inheritdoc />
public Type GetConfigurationType(string key)
{
return GetConfigurationStore(key)

View File

@@ -103,14 +103,11 @@ using MediaBrowser.Providers.Subtitles;
using MediaBrowser.Providers.TV.TheTVDB;
using MediaBrowser.WebDashboard.Api;
using MediaBrowser.XbmcMetadata.Providers;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using OperatingSystem = MediaBrowser.Common.System.OperatingSystem;
namespace Emby.Server.Implementations
@@ -764,9 +761,8 @@ namespace Emby.Server.Implementations
LibraryManager = new LibraryManager(this, LoggerFactory, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager);
serviceCollection.AddSingleton(LibraryManager);
// TODO wtaylor: investigate use of second music manager
var musicManager = new MusicManager(LibraryManager);
serviceCollection.AddSingleton<IMusicManager>(new MusicManager(LibraryManager));
serviceCollection.AddSingleton<IMusicManager>(musicManager);
LibraryMonitor = new LibraryMonitor(LoggerFactory, LibraryManager, ServerConfigurationManager, FileSystemManager);
serviceCollection.AddSingleton(LibraryMonitor);
@@ -841,16 +837,14 @@ namespace Emby.Server.Implementations
serviceCollection.AddSingleton(ChapterManager);
MediaEncoder = new MediaBrowser.MediaEncoding.Encoder.MediaEncoder(
LoggerFactory,
JsonSerializer,
StartupOptions.FFmpegPath,
LoggerFactory.CreateLogger<MediaBrowser.MediaEncoding.Encoder.MediaEncoder>(),
ServerConfigurationManager,
FileSystemManager,
() => SubtitleEncoder,
() => MediaSourceManager,
ProcessFactory,
5000,
LocalizationManager);
LocalizationManager,
() => SubtitleEncoder,
_configuration,
StartupOptions.FFmpegPath);
serviceCollection.AddSingleton(MediaEncoder);
EncodingManager = new MediaEncoder.EncodingManager(FileSystemManager, LoggerFactory, MediaEncoder, ChapterManager, LibraryManager);
@@ -867,10 +861,21 @@ namespace Emby.Server.Implementations
AuthService = new AuthService(LoggerFactory.CreateLogger<AuthService>(), authContext, ServerConfigurationManager, SessionManager, NetworkManager);
serviceCollection.AddSingleton(AuthService);
SubtitleEncoder = new MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder(LibraryManager, LoggerFactory, ApplicationPaths, FileSystemManager, MediaEncoder, JsonSerializer, HttpClient, MediaSourceManager, ProcessFactory);
SubtitleEncoder = new MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder(
LibraryManager,
LoggerFactory.CreateLogger<MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>(),
ApplicationPaths,
FileSystemManager,
MediaEncoder,
HttpClient,
MediaSourceManager,
ProcessFactory);
serviceCollection.AddSingleton(SubtitleEncoder);
serviceCollection.AddSingleton(typeof(IResourceFileManager), typeof(ResourceFileManager));
serviceCollection.AddSingleton<EncodingHelper>();
serviceCollection.AddSingleton(typeof(IAttachmentExtractor), typeof(MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor));
_displayPreferencesRepository.Initialize();
@@ -1472,7 +1477,7 @@ namespace Emby.Server.Implementations
/// </summary>
/// <param name="address">The IPv6 address.</param>
/// <returns>The IPv6 address without the scope id.</returns>
private string RemoveScopeId(string address)
private ReadOnlySpan<char> RemoveScopeId(ReadOnlySpan<char> address)
{
var index = address.IndexOf('%');
if (index == -1)
@@ -1480,33 +1485,50 @@ namespace Emby.Server.Implementations
return address;
}
return address.Substring(0, index);
return address.Slice(0, index);
}
/// <inheritdoc />
public string GetLocalApiUrl(IPAddress ipAddress)
{
if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
{
var str = RemoveScopeId(ipAddress.ToString());
Span<char> span = new char[str.Length + 2];
span[0] = '[';
str.CopyTo(span.Slice(1));
span[^1] = ']';
return GetLocalApiUrl("[" + str + "]");
return GetLocalApiUrl(span);
}
return GetLocalApiUrl(ipAddress.ToString());
}
public string GetLocalApiUrl(string host)
/// <inheritdoc />
public string GetLocalApiUrl(ReadOnlySpan<char> host)
{
var url = new StringBuilder(64);
if (EnableHttps)
{
return string.Format("https://{0}:{1}",
host,
HttpsPort.ToString(CultureInfo.InvariantCulture));
url.Append("https://");
}
else
{
url.Append("http://");
}
return string.Format("http://{0}:{1}",
host,
HttpPort.ToString(CultureInfo.InvariantCulture));
url.Append(host)
.Append(':')
.Append(HttpPort);
string baseUrl = ServerConfigurationManager.Configuration.BaseUrl;
if (baseUrl.Length != 0)
{
url.Append('/').Append(baseUrl);
}
return url.ToString();
}
public Task<List<IPAddress>> GetLocalIpAddresses(CancellationToken cancellationToken)

View File

@@ -10,15 +10,10 @@ using SharpCompress.Readers.Zip;
namespace Emby.Server.Implementations.Archiving
{
/// <summary>
/// Class DotNetZipClient
/// Class DotNetZipClient.
/// </summary>
public class ZipClient : IZipClient
{
public ZipClient()
{
}
/// <summary>
/// Extracts all.
/// </summary>
@@ -144,7 +139,6 @@ namespace Emby.Server.Implementations.Archiving
}
}
/// <summary>
/// Extracts all from tar.
/// </summary>

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System.Collections.Generic;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Model.Branding;

View File

@@ -4,7 +4,7 @@ using MediaBrowser.Controller;
namespace Emby.Server.Implementations.Browser
{
/// <summary>
/// Class BrowserLauncher
/// Class BrowserLauncher.
/// </summary>
public static class BrowserLauncher
{
@@ -32,6 +32,7 @@ namespace Emby.Server.Implementations.Browser
/// <summary>
/// Opens the URL.
/// </summary>
/// <param name="appHost">The application host instance.</param>
/// <param name="url">The URL.</param>
private static void OpenUrl(IServerApplicationHost appHost, string url)
{

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Threading;
@@ -13,11 +15,16 @@ namespace Emby.Server.Implementations.Channels
{
private readonly ChannelManager _channelManager;
/// <summary>
/// Initializes a new instance of the <see cref="ChannelDynamicMediaSourceProvider"/> class.
/// </summary>
/// <param name="channelManager">The channel manager.</param>
public ChannelDynamicMediaSourceProvider(IChannelManager channelManager)
{
_channelManager = (ChannelManager)channelManager;
}
/// <inheritdoc />
public Task<IEnumerable<MediaSourceInfo>> GetMediaSources(BaseItem item, CancellationToken cancellationToken)
{
if (item.SourceType == SourceType.Channel)
@@ -28,6 +35,7 @@ namespace Emby.Server.Implementations.Channels
return Task.FromResult<IEnumerable<MediaSourceInfo>>(new List<MediaSourceInfo>());
}
/// <inheritdoc />
public Task<ILiveStream> OpenMediaSource(string openToken, List<ILiveStream> currentLiveStreams, CancellationToken cancellationToken)
{
throw new NotImplementedException();

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System.Collections.Generic;
using System.Linq;
using System.Threading;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -510,7 +512,7 @@ namespace Emby.Server.Implementations.Channels
return _libraryManager.GetItemIds(new InternalItemsQuery
{
IncludeItemTypes = new[] { typeof(Channel).Name },
OrderBy = new ValueTuple<string, SortOrder>[] { new ValueTuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending) }
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) }
}).Select(i => GetChannelFeatures(i.ToString("N", CultureInfo.InvariantCulture))).ToArray();
}
@@ -618,16 +620,16 @@ namespace Emby.Server.Implementations.Channels
{
query.OrderBy = new[]
{
new ValueTuple<string, SortOrder>(ItemSortBy.PremiereDate, SortOrder.Descending),
new ValueTuple<string, SortOrder>(ItemSortBy.ProductionYear, SortOrder.Descending),
new ValueTuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending)
(ItemSortBy.PremiereDate, SortOrder.Descending),
(ItemSortBy.ProductionYear, SortOrder.Descending),
(ItemSortBy.DateCreated, SortOrder.Descending)
};
}
else
{
query.OrderBy = new[]
{
new ValueTuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending)
(ItemSortBy.DateCreated, SortOrder.Descending)
};
}

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Linq;
using System.Threading;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Threading;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Linq;
@@ -76,7 +78,6 @@ namespace Emby.Server.Implementations.Collections
.Where(i => i != null)
.GroupBy(x => x.Id)
.Select(x => x.First())
.OrderBy(i => Guid.NewGuid())
.ToList();
}

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -29,11 +31,7 @@ namespace Emby.Server.Implementations.Collections
private readonly ILogger _logger;
private readonly IProviderManager _providerManager;
private readonly ILocalizationManager _localizationManager;
private IApplicationPaths _appPaths;
public event EventHandler<CollectionCreatedEventArgs> CollectionCreated;
public event EventHandler<CollectionModifiedEventArgs> ItemsAddedToCollection;
public event EventHandler<CollectionModifiedEventArgs> ItemsRemovedFromCollection;
private readonly IApplicationPaths _appPaths;
public CollectionManager(
ILibraryManager libraryManager,
@@ -53,6 +51,10 @@ namespace Emby.Server.Implementations.Collections
_appPaths = appPaths;
}
public event EventHandler<CollectionCreatedEventArgs> CollectionCreated;
public event EventHandler<CollectionModifiedEventArgs> ItemsAddedToCollection;
public event EventHandler<CollectionModifiedEventArgs> ItemsRemovedFromCollection;
private IEnumerable<Folder> FindFolders(string path)
{
return _libraryManager
@@ -339,11 +341,11 @@ namespace Emby.Server.Implementations.Collections
}
}
public class CollectionManagerEntryPoint : IServerEntryPoint
public sealed class CollectionManagerEntryPoint : IServerEntryPoint
{
private readonly CollectionManager _collectionManager;
private readonly IServerConfigurationManager _config;
private ILogger _logger;
private readonly ILogger _logger;
public CollectionManagerEntryPoint(ICollectionManager collectionManager, IServerConfigurationManager config, ILogger logger)
{
@@ -352,6 +354,7 @@ namespace Emby.Server.Implementations.Collections
_logger = logger;
}
/// <inheritdoc />
public async Task RunAsync()
{
if (!_config.Configuration.CollectionsUpgraded && _config.Configuration.IsStartupWizardCompleted)
@@ -375,39 +378,10 @@ namespace Emby.Server.Implementations.Collections
}
}
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
// TODO: dispose managed state (managed objects).
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
disposedValue = true;
}
}
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
// ~CollectionManagerEntryPoint() {
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
// Dispose(false);
// }
// This code added to correctly implement the disposable pattern.
/// <inheritdoc />
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
// TODO: uncomment the following line if the finalizer is overridden above.
// GC.SuppressFinalize(this);
// Nothing to dispose
}
#endregion
}
}

View File

@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using Emby.Server.Implementations.AppBase;
using MediaBrowser.Common.Configuration;
@@ -17,7 +19,6 @@ namespace Emby.Server.Implementations.Configuration
/// </summary>
public class ServerConfigurationManager : BaseConfigurationManager, IServerConfigurationManager
{
/// <summary>
/// Initializes a new instance of the <see cref="ServerConfigurationManager" /> class.
/// </summary>
@@ -31,6 +32,9 @@ namespace Emby.Server.Implementations.Configuration
UpdateMetadataPath();
}
/// <summary>
/// Configuration updating event.
/// </summary>
public event EventHandler<GenericEventArgs<ServerConfiguration>> ConfigurationUpdating;
/// <summary>
@@ -97,7 +101,7 @@ namespace Emby.Server.Implementations.Configuration
/// Validates the SSL certificate.
/// </summary>
/// <param name="newConfig">The new configuration.</param>
/// <exception cref="DirectoryNotFoundException"></exception>
/// <exception cref="FileNotFoundException">The certificate path doesn't exist.</exception>
private void ValidateSslCertificate(BaseApplicationConfiguration newConfig)
{
var serverConfig = (ServerConfiguration)newConfig;
@@ -105,12 +109,16 @@ namespace Emby.Server.Implementations.Configuration
var newPath = serverConfig.CertificatePath;
if (!string.IsNullOrWhiteSpace(newPath)
&& !string.Equals(Configuration.CertificatePath ?? string.Empty, newPath))
&& !string.Equals(Configuration.CertificatePath, newPath, StringComparison.Ordinal))
{
// Validate
if (!File.Exists(newPath))
{
throw new FileNotFoundException(string.Format("Certificate file '{0}' does not exist.", newPath));
throw new FileNotFoundException(
string.Format(
CultureInfo.InvariantCulture,
"Certificate file '{0}' does not exist.",
newPath));
}
}
}
@@ -119,24 +127,32 @@ namespace Emby.Server.Implementations.Configuration
/// Validates the metadata path.
/// </summary>
/// <param name="newConfig">The new configuration.</param>
/// <exception cref="DirectoryNotFoundException"></exception>
/// <exception cref="DirectoryNotFoundException">The new config path doesn't exist.</exception>
private void ValidateMetadataPath(ServerConfiguration newConfig)
{
var newPath = newConfig.MetadataPath;
if (!string.IsNullOrWhiteSpace(newPath)
&& !string.Equals(Configuration.MetadataPath ?? string.Empty, newPath))
&& !string.Equals(Configuration.MetadataPath, newPath, StringComparison.Ordinal))
{
// Validate
if (!Directory.Exists(newPath))
{
throw new FileNotFoundException(string.Format("{0} does not exist.", newPath));
throw new DirectoryNotFoundException(
string.Format(
CultureInfo.InvariantCulture,
"{0} does not exist.",
newPath));
}
EnsureWriteAccess(newPath);
}
}
/// <summary>
/// Sets all configuration values to their optimal values.
/// </summary>
/// <returns>If the configuration changed.</returns>
public bool SetOptimalValues()
{
var config = Configuration;

View File

@@ -1,13 +1,16 @@
using System.Collections.Generic;
using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
namespace Emby.Server.Implementations
{
public static class ConfigurationOptions
{
public static readonly Dictionary<string, string> Configuration = new Dictionary<string, string>
public static Dictionary<string, string> Configuration => new Dictionary<string, string>
{
{ "HttpListenerHost:DefaultRedirectPath", "web/index.html" },
{ "MusicBrainz:BaseUrl", "https://www.musicbrainz.org" }
{ "MusicBrainz:BaseUrl", "https://www.musicbrainz.org" },
{ FfmpegProbeSizeKey, "1G" },
{ FfmpegAnalyzeDurationKey, "200M" }
};
}
}

View File

@@ -6,6 +6,9 @@ using static MediaBrowser.Common.Cryptography.Constants;
namespace Emby.Server.Implementations.Cryptography
{
/// <summary>
/// Class providing abstractions over cryptographic functions.
/// </summary>
public class CryptographyProvider : ICryptoProvider, IDisposable
{
private static readonly HashSet<string> _supportedHashMethods = new HashSet<string>()
@@ -42,8 +45,10 @@ namespace Emby.Server.Implementations.Cryptography
_randomNumberGenerator = RandomNumberGenerator.Create();
}
/// <inheritdoc />
public string DefaultHashMethod => "PBKDF2";
/// <inheritdoc />
public IEnumerable<string> GetSupportedHashMethods()
=> _supportedHashMethods;
@@ -62,6 +67,7 @@ namespace Emby.Server.Implementations.Cryptography
throw new CryptographicException($"Cannot currently use PBKDF2 with requested hash method: {method}");
}
/// <inheritdoc />
public byte[] ComputeHash(string hashMethod, byte[] bytes, byte[] salt)
{
if (hashMethod == DefaultHashMethod)
@@ -89,12 +95,15 @@ namespace Emby.Server.Implementations.Cryptography
throw new CryptographicException($"Requested hash method is not supported: {hashMethod}");
}
/// <inheritdoc />
public byte[] ComputeHashWithDefaultMethod(byte[] bytes, byte[] salt)
=> PBKDF2(DefaultHashMethod, bytes, salt, DefaultIterations);
/// <inheritdoc />
public byte[] GenerateSalt()
=> GenerateSalt(DefaultSaltLength);
/// <inheritdoc />
public byte[] GenerateSalt(int length)
{
byte[] salt = new byte[length];
@@ -109,6 +118,10 @@ namespace Emby.Server.Implementations.Cryptography
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="dispose"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Linq;
@@ -11,6 +13,10 @@ namespace Emby.Server.Implementations.Data
{
private bool _disposed = false;
/// <summary>
/// Initializes a new instance of the <see cref="BaseSqliteRepository"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
protected BaseSqliteRepository(ILogger logger)
{
Logger = logger;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Threading;
using System.Threading.Tasks;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Threading;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;

View File

@@ -7,6 +7,7 @@ using System.Text;
using System.Text.Json;
using System.Threading;
using Emby.Server.Implementations.Playlists;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.Json;
using MediaBrowser.Controller;
using MediaBrowser.Controller.Channels;
@@ -48,6 +49,21 @@ namespace Emby.Server.Implementations.Data
private readonly TypeMapper _typeMapper;
private readonly JsonSerializerOptions _jsonOptions;
static SqliteItemRepository()
{
var queryPrefixText = new StringBuilder();
queryPrefixText.Append("insert into mediaattachments (");
foreach (var column in _mediaAttachmentSaveColumns)
{
queryPrefixText.Append(column)
.Append(',');
}
queryPrefixText.Length -= 1;
queryPrefixText.Append(") values ");
_mediaAttachmentInsertPrefix = queryPrefixText.ToString();
}
/// <summary>
/// Initializes a new instance of the <see cref="SqliteItemRepository"/> class.
/// </summary>
@@ -91,6 +107,8 @@ namespace Emby.Server.Implementations.Data
{
const string CreateMediaStreamsTableCommand
= "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, CodecTag TEXT NULL, Comment TEXT NULL, NalLengthSize TEXT NULL, IsAvc BIT NULL, Title TEXT NULL, TimeBase TEXT NULL, CodecTimeBase TEXT NULL, ColorPrimaries TEXT NULL, ColorSpace TEXT NULL, ColorTransfer TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))";
const string CreateMediaAttachmentsTableCommand
= "create table if not exists mediaattachments (ItemId GUID, AttachmentIndex INT, Codec TEXT, CodecTag TEXT NULL, Comment TEXT NULL, Filename TEXT NULL, MIMEType TEXT NULL, PRIMARY KEY (ItemId, AttachmentIndex))";
string[] queries =
{
@@ -113,6 +131,7 @@ namespace Emby.Server.Implementations.Data
"create table if not exists " + ChaptersTableName + " (ItemId GUID, ChapterIndex INT NOT NULL, StartPositionTicks BIGINT NOT NULL, Name TEXT, ImagePath TEXT, PRIMARY KEY (ItemId, ChapterIndex))",
CreateMediaStreamsTableCommand,
CreateMediaAttachmentsTableCommand,
"pragma shrink_memory"
};
@@ -420,6 +439,19 @@ namespace Emby.Server.Implementations.Data
"ColorTransfer"
};
private static readonly string[] _mediaAttachmentSaveColumns =
{
"ItemId",
"AttachmentIndex",
"Codec",
"CodecTag",
"Comment",
"Filename",
"MIMEType"
};
private static readonly string _mediaAttachmentInsertPrefix;
private static string GetSaveItemCommandText()
{
var saveColumns = new []
@@ -2831,8 +2863,8 @@ namespace Emby.Server.Implementations.Data
BindSimilarParams(query, statement);
BindSearchParams(query, statement);
// Running this again will bind the params
GetWhereClauses(query, statement);
// Running this again will bind the params
GetWhereClauses(query, statement);
var hasEpisodeAttributes = HasEpisodeAttributes(query);
var hasServiceName = HasServiceName(query);
@@ -2881,14 +2913,14 @@ namespace Emby.Server.Implementations.Data
private string GetOrderByText(InternalItemsQuery query)
{
var orderBy = query.OrderBy;
if (string.IsNullOrEmpty(query.SearchTerm))
{
int oldLen = query.OrderBy.Length;
if (query.SimilarTo != null && oldLen == 0)
int oldLen = orderBy.Count;
if (oldLen == 0 && query.SimilarTo != null)
{
var arr = new (string, SortOrder)[oldLen + 2];
query.OrderBy.CopyTo(arr, 0);
orderBy.CopyTo(arr, 0);
arr[oldLen] = ("SimilarityScore", SortOrder.Descending);
arr[oldLen + 1] = (ItemSortBy.Random, SortOrder.Ascending);
query.OrderBy = arr;
@@ -2896,16 +2928,15 @@ namespace Emby.Server.Implementations.Data
}
else
{
query.OrderBy = new []
query.OrderBy = new[]
{
("SearchScore", SortOrder.Descending),
(ItemSortBy.SortName, SortOrder.Ascending)
};
}
var orderBy = query.OrderBy;
if (orderBy.Length == 0)
if (orderBy.Count == 0)
{
return string.Empty;
}
@@ -2913,14 +2944,8 @@ namespace Emby.Server.Implementations.Data
return " ORDER BY " + string.Join(",", orderBy.Select(i =>
{
var columnMap = MapOrderByField(i.Item1, query);
var columnAscending = i.Item2 == SortOrder.Ascending;
const bool enableOrderInversion = false;
if (columnMap.Item2 && enableOrderInversion)
{
columnAscending = !columnAscending;
}
var sortOrder = columnAscending ? "ASC" : "DESC";
var sortOrder = i.Item2 == SortOrder.Ascending ? "ASC" : "DESC";
return columnMap.Item1 + " " + sortOrder;
}));
@@ -4599,10 +4624,20 @@ namespace Emby.Server.Implementations.Data
if (query.ExcludeInheritedTags.Length > 0)
{
var tagValues = query.ExcludeInheritedTags.Select(i => "'" + GetCleanValue(i) + "'");
var tagValuesList = string.Join(",", tagValues);
whereClauses.Add("((select CleanValue from itemvalues where ItemId=Guid and Type=6 and cleanvalue in (" + tagValuesList + ")) is null)");
var paramName = "@ExcludeInheritedTags";
if (statement == null)
{
int index = 0;
string excludedTags = string.Join(",", query.ExcludeInheritedTags.Select(t => paramName + index++));
whereClauses.Add("((select CleanValue from itemvalues where ItemId=Guid and Type=6 and cleanvalue in (" + excludedTags + ")) is null)");
}
else
{
for (int index = 0; index < query.ExcludeInheritedTags.Length; index++)
{
statement.TryBind(paramName + index, GetCleanValue(query.ExcludeInheritedTags[index]));
}
}
}
if (query.SeriesStatuses.Length > 0)
@@ -6132,5 +6167,175 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
return item;
}
public List<MediaAttachment> GetMediaAttachments(MediaAttachmentQuery query)
{
CheckDisposed();
if (query == null)
{
throw new ArgumentNullException(nameof(query));
}
var cmdText = "select "
+ string.Join(",", _mediaAttachmentSaveColumns)
+ " from mediaattachments where"
+ " ItemId=@ItemId";
if (query.Index.HasValue)
{
cmdText += " AND AttachmentIndex=@AttachmentIndex";
}
cmdText += " order by AttachmentIndex ASC";
var list = new List<MediaAttachment>();
using (var connection = GetConnection(true))
using (var statement = PrepareStatement(connection, cmdText))
{
statement.TryBind("@ItemId", query.ItemId.ToByteArray());
if (query.Index.HasValue)
{
statement.TryBind("@AttachmentIndex", query.Index.Value);
}
foreach (var row in statement.ExecuteQuery())
{
list.Add(GetMediaAttachment(row));
}
}
return list;
}
public void SaveMediaAttachments(
Guid id,
IReadOnlyList<MediaAttachment> attachments,
CancellationToken cancellationToken)
{
CheckDisposed();
if (id == Guid.Empty)
{
throw new ArgumentException(nameof(id));
}
if (attachments == null)
{
throw new ArgumentNullException(nameof(attachments));
}
cancellationToken.ThrowIfCancellationRequested();
using (var connection = GetConnection())
{
connection.RunInTransaction(db =>
{
var itemIdBlob = id.ToByteArray();
db.Execute("delete from mediaattachments where ItemId=@ItemId", itemIdBlob);
InsertMediaAttachments(itemIdBlob, attachments, db, cancellationToken);
}, TransactionMode);
}
}
private void InsertMediaAttachments(
byte[] idBlob,
IReadOnlyList<MediaAttachment> attachments,
IDatabaseConnection db,
CancellationToken cancellationToken)
{
const int InsertAtOnce = 10;
for (var startIndex = 0; startIndex < attachments.Count; startIndex += InsertAtOnce)
{
var insertText = new StringBuilder(_mediaAttachmentInsertPrefix);
var endIndex = Math.Min(attachments.Count, startIndex + InsertAtOnce);
for (var i = startIndex; i < endIndex; i++)
{
var index = i.ToString(CultureInfo.InvariantCulture);
insertText.Append("(@ItemId, ");
foreach (var column in _mediaAttachmentSaveColumns.Skip(1))
{
insertText.Append("@" + column + index + ",");
}
insertText.Length -= 1;
insertText.Append("),");
}
insertText.Length--;
cancellationToken.ThrowIfCancellationRequested();
using (var statement = PrepareStatement(db, insertText.ToString()))
{
statement.TryBind("@ItemId", idBlob);
for (var i = startIndex; i < endIndex; i++)
{
var index = i.ToString(CultureInfo.InvariantCulture);
var attachment = attachments[i];
statement.TryBind("@AttachmentIndex" + index, attachment.Index);
statement.TryBind("@Codec" + index, attachment.Codec);
statement.TryBind("@CodecTag" + index, attachment.CodecTag);
statement.TryBind("@Comment" + index, attachment.Comment);
statement.TryBind("@FileName" + index, attachment.FileName);
statement.TryBind("@MimeType" + index, attachment.MimeType);
}
statement.Reset();
statement.MoveNext();
}
}
}
/// <summary>
/// Gets the attachment.
/// </summary>
/// <param name="reader">The reader.</param>
/// <returns>MediaAttachment</returns>
private MediaAttachment GetMediaAttachment(IReadOnlyList<IResultSetValue> reader)
{
var item = new MediaAttachment
{
Index = reader[1].ToInt()
};
if (reader[2].SQLiteType != SQLiteType.Null)
{
item.Codec = reader[2].ToString();
}
if (reader[2].SQLiteType != SQLiteType.Null)
{
item.CodecTag = reader[3].ToString();
}
if (reader[4].SQLiteType != SQLiteType.Null)
{
item.Comment = reader[4].ToString();
}
if (reader[6].SQLiteType != SQLiteType.Null)
{
item.FileName = reader[5].ToString();
}
if (reader[6].SQLiteType != SQLiteType.Null)
{
item.MimeType = reader[6].ToString();
}
return item;
}
}
}

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.IO;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.IO;

View File

@@ -5,25 +5,22 @@ using System.Linq;
namespace Emby.Server.Implementations.Data
{
/// <summary>
/// Class TypeMapper
/// Class TypeMapper.
/// </summary>
public class TypeMapper
{
/// <summary>
/// This holds all the types in the running assemblies so that we can de-serialize properly when we don't have strong types
/// This holds all the types in the running assemblies
/// so that we can de-serialize properly when we don't have strong types.
/// </summary>
private readonly ConcurrentDictionary<string, Type> _typeMap = new ConcurrentDictionary<string, Type>();
public TypeMapper()
{
}
/// <summary>
/// Gets the type.
/// </summary>
/// <param name="typeName">Name of the type.</param>
/// <returns>Type.</returns>
/// <exception cref="ArgumentNullException"></exception>
/// <exception cref="ArgumentNullException"><c>typeName</c> is null.</exception>
public Type GetType(string typeName)
{
if (string.IsNullOrEmpty(typeName))

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Globalization;
using System.IO;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Diagnostics;
using System.IO;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using MediaBrowser.Model.Diagnostics;
namespace Emby.Server.Implementations.Diagnostics

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;

View File

@@ -15,12 +15,12 @@
<ProjectReference Include="..\MediaBrowser.LocalMetadata\MediaBrowser.LocalMetadata.csproj" />
<ProjectReference Include="..\Emby.Photos\Emby.Photos.csproj" />
<ProjectReference Include="..\Emby.Drawing\Emby.Drawing.csproj" />
<ProjectReference Include="..\Emby.XmlTv\Emby.XmlTv\Emby.XmlTv.csproj" />
<ProjectReference Include="..\MediaBrowser.MediaEncoding\MediaBrowser.MediaEncoding.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="IPNetwork2" Version="2.4.0.126" />
<PackageReference Include="Jellyfin.XmlTv" Version="10.4.3" />
<PackageReference Include="Microsoft.AspNetCore.Hosting" Version="2.2.7" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Hosting.Server.Abstractions" Version="2.2.0" />
@@ -29,7 +29,6 @@
<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.Logging" Version="3.0.1" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="3.0.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="3.0.1" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="3.0.1" />
@@ -37,6 +36,7 @@
<PackageReference Include="ServiceStack.Text.Core" Version="5.7.0" />
<PackageReference Include="sharpcompress" Version="0.24.0" />
<PackageReference Include="SQLitePCL.pretty.netstandard" Version="2.0.1" />
<PackageReference Include="System.Interactive.Async" Version="4.0.0" />
</ItemGroup>
<ItemGroup>
@@ -49,7 +49,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<!-- Code analysers-->
<!-- Code Analyzers-->
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
<PackageReference Include="Microsoft.CodeAnalysis.FxCopAnalyzers" Version="2.9.7" />
<PackageReference Include="SerilogAnalyzer" Version="0.15.0" />

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Linq;
using System.Threading;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Net;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Linq;
using System.Threading;

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Library;
@@ -12,32 +11,19 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.EntryPoints
{
/// <summary>
/// Class RefreshUsersMetadata
/// Class RefreshUsersMetadata.
/// </summary>
public class RefreshUsersMetadata : IScheduledTask, IConfigurableScheduledTask
{
private readonly ILogger _logger;
/// <summary>
/// The _user manager
/// The user manager.
/// </summary>
private readonly IUserManager _userManager;
private IFileSystem _fileSystem;
public string Name => "Refresh Users";
public string Key => "RefreshUsers";
public string Description => "Refresh user infos";
public string Category => "Library";
public bool IsHidden => true;
public bool IsEnabled => true;
public bool IsLogged => true;
/// <summary>
/// Initializes a new instance of the <see cref="RefreshUsersMetadata" /> class.
/// </summary>
@@ -48,6 +34,28 @@ namespace Emby.Server.Implementations.EntryPoints
_fileSystem = fileSystem;
}
/// <inheritdoc />
public string Name => "Refresh Users";
/// <inheritdoc />
public string Key => "RefreshUsers";
/// <inheritdoc />
public string Description => "Refresh user infos";
/// <inheritdoc />
public string Category => "Library";
/// <inheritdoc />
public bool IsHidden => true;
/// <inheritdoc />
public bool IsEnabled => true;
/// <inheritdoc />
public bool IsLogged => true;
/// <inheritdoc />
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)
{
foreach (var user in _userManager.Users)
@@ -58,9 +66,10 @@ namespace Emby.Server.Implementations.EntryPoints
}
}
/// <inheritdoc />
public IEnumerable<TaskTriggerInfo> GetDefaultTriggers()
{
return new List<TaskTriggerInfo>
return new[]
{
new TaskTriggerInfo
{

View File

@@ -16,33 +16,46 @@ using MediaBrowser.Model.Tasks;
namespace Emby.Server.Implementations.EntryPoints
{
/// <summary>
/// Class WebSocketEvents
/// Class WebSocketEvents.
/// </summary>
public class ServerEventNotifier : IServerEntryPoint
{
/// <summary>
/// The _user manager
/// The user manager.
/// </summary>
private readonly IUserManager _userManager;
/// <summary>
/// The _installation manager
/// The installation manager.
/// </summary>
private readonly IInstallationManager _installationManager;
/// <summary>
/// The _kernel
/// The kernel.
/// </summary>
private readonly IServerApplicationHost _appHost;
/// <summary>
/// The _task manager
/// The task manager.
/// </summary>
private readonly ITaskManager _taskManager;
private readonly ISessionManager _sessionManager;
public ServerEventNotifier(IServerApplicationHost appHost, IUserManager userManager, IInstallationManager installationManager, ITaskManager taskManager, ISessionManager sessionManager)
/// <summary>
/// Initializes a new instance of the <see cref="ServerEventNotifier"/> class.
/// </summary>
/// <param name="appHost">The application host.</param>
/// <param name="userManager">The user manager.</param>
/// <param name="installationManager">The installation manager.</param>
/// <param name="taskManager">The task manager.</param>
/// <param name="sessionManager">The session manager.</param>
public ServerEventNotifier(
IServerApplicationHost appHost,
IUserManager userManager,
IInstallationManager installationManager,
ITaskManager taskManager,
ISessionManager sessionManager)
{
_userManager = userManager;
_installationManager = installationManager;
@@ -51,47 +64,48 @@ namespace Emby.Server.Implementations.EntryPoints
_sessionManager = sessionManager;
}
/// <inheritdoc />
public Task RunAsync()
{
_userManager.UserDeleted += userManager_UserDeleted;
_userManager.UserUpdated += userManager_UserUpdated;
_userManager.UserPolicyUpdated += _userManager_UserPolicyUpdated;
_userManager.UserConfigurationUpdated += _userManager_UserConfigurationUpdated;
_userManager.UserDeleted += OnUserDeleted;
_userManager.UserUpdated += OnUserUpdated;
_userManager.UserPolicyUpdated += OnUserPolicyUpdated;
_userManager.UserConfigurationUpdated += OnUserConfigurationUpdated;
_appHost.HasPendingRestartChanged += kernel_HasPendingRestartChanged;
_appHost.HasPendingRestartChanged += OnHasPendingRestartChanged;
_installationManager.PluginUninstalled += InstallationManager_PluginUninstalled;
_installationManager.PackageInstalling += _installationManager_PackageInstalling;
_installationManager.PackageInstallationCancelled += _installationManager_PackageInstallationCancelled;
_installationManager.PackageInstallationCompleted += _installationManager_PackageInstallationCompleted;
_installationManager.PackageInstallationFailed += _installationManager_PackageInstallationFailed;
_installationManager.PluginUninstalled += OnPluginUninstalled;
_installationManager.PackageInstalling += OnPackageInstalling;
_installationManager.PackageInstallationCancelled += OnPackageInstallationCancelled;
_installationManager.PackageInstallationCompleted += OnPackageInstallationCompleted;
_installationManager.PackageInstallationFailed += OnPackageInstallationFailed;
_taskManager.TaskCompleted += _taskManager_TaskCompleted;
_taskManager.TaskCompleted += OnTaskCompleted;
return Task.CompletedTask;
}
void _installationManager_PackageInstalling(object sender, InstallationEventArgs e)
private void OnPackageInstalling(object sender, InstallationEventArgs e)
{
SendMessageToAdminSessions("PackageInstalling", e.InstallationInfo);
}
void _installationManager_PackageInstallationCancelled(object sender, InstallationEventArgs e)
private void OnPackageInstallationCancelled(object sender, InstallationEventArgs e)
{
SendMessageToAdminSessions("PackageInstallationCancelled", e.InstallationInfo);
}
void _installationManager_PackageInstallationCompleted(object sender, InstallationEventArgs e)
private void OnPackageInstallationCompleted(object sender, InstallationEventArgs e)
{
SendMessageToAdminSessions("PackageInstallationCompleted", e.InstallationInfo);
}
void _installationManager_PackageInstallationFailed(object sender, InstallationFailedEventArgs e)
private void OnPackageInstallationFailed(object sender, InstallationFailedEventArgs e)
{
SendMessageToAdminSessions("PackageInstallationFailed", e.InstallationInfo);
}
void _taskManager_TaskCompleted(object sender, TaskCompletionEventArgs e)
private void OnTaskCompleted(object sender, TaskCompletionEventArgs e)
{
SendMessageToAdminSessions("ScheduledTaskEnded", e.Result);
}
@@ -101,7 +115,7 @@ namespace Emby.Server.Implementations.EntryPoints
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The e.</param>
void InstallationManager_PluginUninstalled(object sender, GenericEventArgs<IPlugin> e)
private void OnPluginUninstalled(object sender, GenericEventArgs<IPlugin> e)
{
SendMessageToAdminSessions("PluginUninstalled", e.Argument.GetPluginInfo());
}
@@ -111,7 +125,7 @@ namespace Emby.Server.Implementations.EntryPoints
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param>
void kernel_HasPendingRestartChanged(object sender, EventArgs e)
private void OnHasPendingRestartChanged(object sender, EventArgs e)
{
_sessionManager.SendRestartRequiredNotification(CancellationToken.None);
}
@@ -121,7 +135,7 @@ namespace Emby.Server.Implementations.EntryPoints
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The e.</param>
void userManager_UserUpdated(object sender, GenericEventArgs<User> e)
private void OnUserUpdated(object sender, GenericEventArgs<User> e)
{
var dto = _userManager.GetUserDto(e.Argument);
@@ -133,19 +147,19 @@ namespace Emby.Server.Implementations.EntryPoints
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The e.</param>
void userManager_UserDeleted(object sender, GenericEventArgs<User> e)
private void OnUserDeleted(object sender, GenericEventArgs<User> e)
{
SendMessageToUserSession(e.Argument, "UserDeleted", e.Argument.Id.ToString("N", CultureInfo.InvariantCulture));
}
void _userManager_UserPolicyUpdated(object sender, GenericEventArgs<User> e)
private void OnUserPolicyUpdated(object sender, GenericEventArgs<User> e)
{
var dto = _userManager.GetUserDto(e.Argument);
SendMessageToUserSession(e.Argument, "UserPolicyUpdated", dto);
}
void _userManager_UserConfigurationUpdated(object sender, GenericEventArgs<User> e)
private void OnUserConfigurationUpdated(object sender, GenericEventArgs<User> e)
{
var dto = _userManager.GetUserDto(e.Argument);
@@ -168,7 +182,11 @@ namespace Emby.Server.Implementations.EntryPoints
{
try
{
await _sessionManager.SendMessageToUserSessions(new List<Guid> { user.Id }, name, data, CancellationToken.None);
await _sessionManager.SendMessageToUserSessions(
new List<Guid> { user.Id },
name,
data,
CancellationToken.None).ConfigureAwait(false);
}
catch (Exception)
{
@@ -176,12 +194,11 @@ namespace Emby.Server.Implementations.EntryPoints
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
@@ -192,18 +209,20 @@ namespace Emby.Server.Implementations.EntryPoints
{
if (dispose)
{
_userManager.UserDeleted -= userManager_UserDeleted;
_userManager.UserUpdated -= userManager_UserUpdated;
_userManager.UserPolicyUpdated -= _userManager_UserPolicyUpdated;
_userManager.UserConfigurationUpdated -= _userManager_UserConfigurationUpdated;
_userManager.UserDeleted -= OnUserDeleted;
_userManager.UserUpdated -= OnUserUpdated;
_userManager.UserPolicyUpdated -= OnUserPolicyUpdated;
_userManager.UserConfigurationUpdated -= OnUserConfigurationUpdated;
_installationManager.PluginUninstalled -= InstallationManager_PluginUninstalled;
_installationManager.PackageInstalling -= _installationManager_PackageInstalling;
_installationManager.PackageInstallationCancelled -= _installationManager_PackageInstallationCancelled;
_installationManager.PackageInstallationCompleted -= _installationManager_PackageInstallationCompleted;
_installationManager.PackageInstallationFailed -= _installationManager_PackageInstallationFailed;
_installationManager.PluginUninstalled -= OnPluginUninstalled;
_installationManager.PackageInstalling -= OnPackageInstalling;
_installationManager.PackageInstallationCancelled -= OnPackageInstallationCancelled;
_installationManager.PackageInstallationCompleted -= OnPackageInstallationCompleted;
_installationManager.PackageInstallationFailed -= OnPackageInstallationFailed;
_appHost.HasPendingRestartChanged -= kernel_HasPendingRestartChanged;
_appHost.HasPendingRestartChanged -= OnHasPendingRestartChanged;
_taskManager.TaskCompleted -= OnTaskCompleted;
}
}
}

View File

@@ -8,21 +8,28 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.EntryPoints
{
/// <summary>
/// Class StartupWizard
/// Class StartupWizard.
/// </summary>
public class StartupWizard : IServerEntryPoint
{
/// <summary>
/// The _app host
/// The app host.
/// </summary>
private readonly IServerApplicationHost _appHost;
/// <summary>
/// The _user manager
/// The user manager.
/// </summary>
private readonly ILogger _logger;
private IServerConfigurationManager _config;
/// <summary>
/// Initializes a new instance of the <see cref="StartupWizard"/> class.
/// </summary>
/// <param name="appHost">The application host.</param>
/// <param name="logger">The logger.</param>
/// <param name="config">The configuration manager.</param>
public StartupWizard(IServerApplicationHost appHost, ILogger logger, IServerConfigurationManager config)
{
_appHost = appHost;
@@ -30,9 +37,7 @@ namespace Emby.Server.Implementations.EntryPoints
_config = config;
}
/// <summary>
/// Runs this instance.
/// </summary>
/// <inheritdoc />
public Task RunAsync()
{
if (!_appHost.CanLaunchWebBrowser)
@@ -57,9 +62,7 @@ namespace Emby.Server.Implementations.EntryPoints
return Task.CompletedTask;
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <inheritdoc />
public void Dispose()
{
}

View File

@@ -10,30 +10,36 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.EntryPoints
{
/// <summary>
/// Class UdpServerEntryPoint
/// Class UdpServerEntryPoint.
/// </summary>
public class UdpServerEntryPoint : IServerEntryPoint
{
/// <summary>
/// Gets or sets the UDP server.
/// The port of the UDP server.
/// </summary>
/// <value>The UDP server.</value>
private UdpServer UdpServer { get; set; }
public const int PortNumber = 7359;
/// <summary>
/// The _logger
/// The logger.
/// </summary>
private readonly ILogger _logger;
private readonly ISocketFactory _socketFactory;
private readonly IServerApplicationHost _appHost;
private readonly IJsonSerializer _json;
public const int PortNumber = 7359;
/// <summary>
/// The UDP server.
/// </summary>
private UdpServer _udpServer;
/// <summary>
/// Initializes a new instance of the <see cref="UdpServerEntryPoint" /> class.
/// </summary>
public UdpServerEntryPoint(ILogger logger, IServerApplicationHost appHost, IJsonSerializer json, ISocketFactory socketFactory)
public UdpServerEntryPoint(
ILogger logger,
IServerApplicationHost appHost,
IJsonSerializer json,
ISocketFactory socketFactory)
{
_logger = logger;
_appHost = appHost;
@@ -41,9 +47,7 @@ namespace Emby.Server.Implementations.EntryPoints
_socketFactory = socketFactory;
}
/// <summary>
/// Runs this instance.
/// </summary>
/// <inheritdoc />
public Task RunAsync()
{
var udpServer = new UdpServer(_logger, _appHost, _json, _socketFactory);
@@ -52,7 +56,7 @@ namespace Emby.Server.Implementations.EntryPoints
{
udpServer.Start(PortNumber);
UdpServer = udpServer;
_udpServer = udpServer;
}
catch (Exception ex)
{
@@ -62,12 +66,11 @@ namespace Emby.Server.Implementations.EntryPoints
return Task.CompletedTask;
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
@@ -78,9 +81,9 @@ namespace Emby.Server.Implementations.EntryPoints
{
if (dispose)
{
if (UdpServer != null)
if (_udpServer != null)
{
UdpServer.Dispose();
_udpServer.Dispose();
}
}
}

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;

View File

@@ -282,6 +282,7 @@ namespace Emby.Server.Implementations.HttpClientManager
};
}
/// <inheritdoc />
public Task<HttpResponseInfo> Post(HttpRequestOptions options)
=> SendAsync(options, HttpMethod.Post);

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Diagnostics;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -5,12 +7,10 @@ using System.IO;
using System.IO.Compression;
using System.Net;
using System.Runtime.Serialization;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using Emby.Server.Implementations.Services;
using MediaBrowser.Common.Extensions;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
@@ -24,12 +24,12 @@ using MimeTypes = MediaBrowser.Model.Net.MimeTypes;
namespace Emby.Server.Implementations.HttpServer
{
/// <summary>
/// Class HttpResultFactory
/// Class HttpResultFactory.
/// </summary>
public class HttpResultFactory : IHttpResultFactory
{
/// <summary>
/// The _logger
/// The logger.
/// </summary>
private readonly ILogger _logger;
private readonly IFileSystem _fileSystem;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Threading;
using System.Threading.Tasks;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;

View File

@@ -8,11 +8,17 @@ using Microsoft.Net.Http.Headers;
namespace Emby.Server.Implementations.HttpServer
{
/// <summary>
/// Class ResponseFilter.
/// </summary>
public class ResponseFilter
{
private static readonly CultureInfo _usCulture = CultureInfo.ReadOnly(new CultureInfo("en-US"));
private readonly ILogger _logger;
/// <summary>
/// Initializes a new instance of the <see cref="ResponseFilter"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
public ResponseFilter(ILogger logger)
{
_logger = logger;
@@ -37,7 +43,7 @@ namespace Emby.Server.Implementations.HttpServer
if (!string.IsNullOrEmpty(exception.Message))
{
var error = exception.Message.Replace(Environment.NewLine, " ");
var error = exception.Message.Replace(Environment.NewLine, " ", StringComparison.Ordinal);
error = RemoveControlCharacters(error);
res.Headers.Add("X-Application-Error-Code", error);
@@ -55,7 +61,7 @@ namespace Emby.Server.Implementations.HttpServer
if (hasHeaders.Headers.TryGetValue(HeaderNames.ContentLength, out string contentLength)
&& !string.IsNullOrEmpty(contentLength))
{
var length = long.Parse(contentLength, _usCulture);
var length = long.Parse(contentLength, CultureInfo.InvariantCulture);
if (length > 0)
{

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Linq;
using Emby.Server.Implementations.SocketSharp;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Linq;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;

View File

@@ -10,37 +10,20 @@ using Microsoft.Net.Http.Headers;
namespace Emby.Server.Implementations.HttpServer
{
/// <summary>
/// Class StreamWriter
/// Class StreamWriter.
/// </summary>
public class StreamWriter : IAsyncStreamWriter, IHasHeaders
{
/// <summary>
/// Gets or sets the source stream.
/// </summary>
/// <value>The source stream.</value>
private Stream SourceStream { get; set; }
private byte[] SourceBytes { get; set; }
/// <summary>
/// The _options
/// The options.
/// </summary>
private readonly IDictionary<string, string> _options = new Dictionary<string, string>();
/// <summary>
/// Gets the options.
/// </summary>
/// <value>The options.</value>
public IDictionary<string, string> Headers => _options;
public Action OnComplete { get; set; }
public Action OnError { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="StreamWriter" /> class.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="contentType">Type of the content.</param>
/// <param name="logger">The logger.</param>
public StreamWriter(Stream source, string contentType)
{
if (string.IsNullOrEmpty(contentType))
@@ -65,6 +48,7 @@ namespace Emby.Server.Implementations.HttpServer
/// </summary>
/// <param name="source">The source.</param>
/// <param name="contentType">Type of the content.</param>
/// <param name="contentLength">The content length.</param>
public StreamWriter(byte[] source, string contentType, int contentLength)
{
if (string.IsNullOrEmpty(contentType))
@@ -78,6 +62,31 @@ namespace Emby.Server.Implementations.HttpServer
Headers[HeaderNames.ContentType] = contentType;
}
/// <summary>
/// Gets or sets the source stream.
/// </summary>
/// <value>The source stream.</value>
private Stream SourceStream { get; set; }
private byte[] SourceBytes { get; set; }
/// <summary>
/// Gets the options.
/// </summary>
/// <value>The options.</value>
public IDictionary<string, string> Headers => _options;
/// <summary>
/// Fires when complete.
/// </summary>
public Action OnComplete { get; set; }
/// <summary>
/// Fires when an error occours.
/// </summary>
public Action OnError { get; set; }
/// <inheritdoc />
public async Task WriteToAsync(Stream responseStream, CancellationToken cancellationToken)
{
try
@@ -98,19 +107,13 @@ namespace Emby.Server.Implementations.HttpServer
}
catch
{
if (OnError != null)
{
OnError();
}
OnError?.Invoke();
throw;
}
finally
{
if (OnComplete != null)
{
OnComplete();
}
OnComplete?.Invoke();
}
}
}

View File

@@ -7,7 +7,6 @@ using Emby.Server.Implementations.Net;
using MediaBrowser.Controller.Net;
using MediaBrowser.Model.Net;
using MediaBrowser.Model.Serialization;
using MediaBrowser.Model.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using UtfUnknown;
@@ -15,32 +14,74 @@ using UtfUnknown;
namespace Emby.Server.Implementations.HttpServer
{
/// <summary>
/// Class WebSocketConnection
/// Class WebSocketConnection.
/// </summary>
public class WebSocketConnection : IWebSocketConnection
{
public event EventHandler<EventArgs> Closed;
/// <summary>
/// The _socket
/// </summary>
private readonly IWebSocket _socket;
/// <summary>
/// The _remote end point
/// </summary>
public string RemoteEndPoint { get; private set; }
/// <summary>
/// The logger
/// The logger.
/// </summary>
private readonly ILogger _logger;
/// <summary>
/// The _json serializer
/// The json serializer.
/// </summary>
private readonly IJsonSerializer _jsonSerializer;
/// <summary>
/// The socket.
/// </summary>
private readonly IWebSocket _socket;
/// <summary>
/// Initializes a new instance of the <see cref="WebSocketConnection" /> class.
/// </summary>
/// <param name="socket">The socket.</param>
/// <param name="remoteEndPoint">The remote end point.</param>
/// <param name="jsonSerializer">The json serializer.</param>
/// <param name="logger">The logger.</param>
/// <exception cref="ArgumentNullException">socket</exception>
public WebSocketConnection(IWebSocket socket, string remoteEndPoint, IJsonSerializer jsonSerializer, ILogger logger)
{
if (socket == null)
{
throw new ArgumentNullException(nameof(socket));
}
if (string.IsNullOrEmpty(remoteEndPoint))
{
throw new ArgumentNullException(nameof(remoteEndPoint));
}
if (jsonSerializer == null)
{
throw new ArgumentNullException(nameof(jsonSerializer));
}
if (logger == null)
{
throw new ArgumentNullException(nameof(logger));
}
Id = Guid.NewGuid();
_jsonSerializer = jsonSerializer;
_socket = socket;
_socket.OnReceiveBytes = OnReceiveInternal;
RemoteEndPoint = remoteEndPoint;
_logger = logger;
socket.Closed += OnSocketClosed;
}
/// <inheritdoc />
public event EventHandler<EventArgs> Closed;
/// <summary>
/// Gets or sets the remote end point.
/// </summary>
public string RemoteEndPoint { get; private set; }
/// <summary>
/// Gets or sets the receive action.
/// </summary>
@@ -64,6 +105,7 @@ namespace Emby.Server.Implementations.HttpServer
/// </summary>
/// <value>The URL.</value>
public string Url { get; set; }
/// <summary>
/// Gets or sets the query string.
/// </summary>
@@ -71,44 +113,12 @@ namespace Emby.Server.Implementations.HttpServer
public IQueryCollection QueryString { get; set; }
/// <summary>
/// Initializes a new instance of the <see cref="WebSocketConnection" /> class.
/// Gets the state.
/// </summary>
/// <param name="socket">The socket.</param>
/// <param name="remoteEndPoint">The remote end point.</param>
/// <param name="jsonSerializer">The json serializer.</param>
/// <param name="logger">The logger.</param>
/// <exception cref="ArgumentNullException">socket</exception>
public WebSocketConnection(IWebSocket socket, string remoteEndPoint, IJsonSerializer jsonSerializer, ILogger logger)
{
if (socket == null)
{
throw new ArgumentNullException(nameof(socket));
}
if (string.IsNullOrEmpty(remoteEndPoint))
{
throw new ArgumentNullException(nameof(remoteEndPoint));
}
if (jsonSerializer == null)
{
throw new ArgumentNullException(nameof(jsonSerializer));
}
if (logger == null)
{
throw new ArgumentNullException(nameof(logger));
}
/// <value>The state.</value>
public WebSocketState State => _socket.State;
Id = Guid.NewGuid();
_jsonSerializer = jsonSerializer;
_socket = socket;
_socket.OnReceiveBytes = OnReceiveInternal;
RemoteEndPoint = remoteEndPoint;
_logger = logger;
socket.Closed += socket_Closed;
}
void socket_Closed(object sender, EventArgs e)
void OnSocketClosed(object sender, EventArgs e)
{
Closed?.Invoke(this, EventArgs.Empty);
}
@@ -210,6 +220,7 @@ namespace Emby.Server.Implementations.HttpServer
return _socket.SendAsync(buffer, true, cancellationToken);
}
/// <inheritdoc />
public Task SendAsync(string text, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(text))
@@ -222,18 +233,11 @@ namespace Emby.Server.Implementations.HttpServer
return _socket.SendAsync(text, true, cancellationToken);
}
/// <summary>
/// Gets the state.
/// </summary>
/// <value>The state.</value>
public WebSocketState State => _socket.State;
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
namespace Emby.Server.Implementations.IO
{
public class ExtendedFileSystemInfo

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.IO;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -16,22 +18,22 @@ namespace Emby.Server.Implementations.IO
public class LibraryMonitor : ILibraryMonitor
{
/// <summary>
/// The file system watchers
/// The file system watchers.
/// </summary>
private readonly ConcurrentDictionary<string, FileSystemWatcher> _fileSystemWatchers = new ConcurrentDictionary<string, FileSystemWatcher>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// The affected paths
/// The affected paths.
/// </summary>
private readonly List<FileRefresher> _activeRefreshers = new List<FileRefresher>();
/// <summary>
/// A dynamic list of paths that should be ignored. Added to during our own file sytem modifications.
/// A dynamic list of paths that should be ignored. Added to during our own file system modifications.
/// </summary>
private readonly ConcurrentDictionary<string, string> _tempIgnoredPaths = new ConcurrentDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Any file name ending in any of these will be ignored by the watchers
/// Any file name ending in any of these will be ignored by the watchers.
/// </summary>
private static readonly HashSet<string> _alwaysIgnoreFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -107,7 +109,7 @@ namespace Emby.Server.Implementations.IO
}
try
{
return Path.Combine(Path.GetFullPath(folderPath), filePath);
return Path.GetFullPath(Path.Combine(folderPath, filePath));
}
catch (ArgumentException)
{

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.IO;
using MediaBrowser.Model.IO;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Buffers;
using System.IO;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;

View File

@@ -42,6 +42,10 @@ namespace Emby.Server.Implementations.Library
".grab",
};
/// <summary>
/// Initializes a new instance of the <see cref="CoreResolutionIgnoreRule"/> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
public CoreResolutionIgnoreRule(ILibraryManager libraryManager)
{
_libraryManager = libraryManager;

View File

@@ -10,10 +10,17 @@ using MediaBrowser.Model.Cryptography;
namespace Emby.Server.Implementations.Library
{
/// <summary>
/// The default authentication provider.
/// </summary>
public class DefaultAuthenticationProvider : IAuthenticationProvider, IRequiresResolvedUser
{
private readonly ICryptoProvider _cryptographyProvider;
/// <summary>
/// Initializes a new instance of the <see cref="DefaultAuthenticationProvider"/> class.
/// </summary>
/// <param name="cryptographyProvider">The cryptography provider.</param>
public DefaultAuthenticationProvider(ICryptoProvider cryptographyProvider)
{
_cryptographyProvider = cryptographyProvider;
@@ -38,12 +45,13 @@ namespace Emby.Server.Implementations.Library
// This is the version that we need to use for local users. Because reasons.
public Task<ProviderAuthenticationResult> Authenticate(string username, string password, User resolvedUser)
{
bool success = false;
if (resolvedUser == null)
{
throw new ArgumentNullException(nameof(resolvedUser));
}
bool success = false;
// As long as jellyfin supports passwordless users, we need this little block here to accommodate
if (!HasPassword(resolvedUser) && string.IsNullOrEmpty(password))
{

View File

@@ -12,6 +12,9 @@ using MediaBrowser.Model.Users;
namespace Emby.Server.Implementations.Library
{
/// <summary>
/// The default password reset provider.
/// </summary>
public class DefaultPasswordResetProvider : IPasswordResetProvider
{
private const string BaseResetFileName = "passwordreset";
@@ -22,6 +25,12 @@ namespace Emby.Server.Implementations.Library
private readonly string _passwordResetFileBase;
private readonly string _passwordResetFileBaseDir;
/// <summary>
/// Initializes a new instance of the <see cref="DefaultPasswordResetProvider"/> class.
/// </summary>
/// <param name="configurationManager">The configuration manager.</param>
/// <param name="jsonSerializer">The JSON serializer.</param>
/// <param name="userManager">The user manager.</param>
public DefaultPasswordResetProvider(
IServerConfigurationManager configurationManager,
IJsonSerializer jsonSerializer,
@@ -56,8 +65,8 @@ namespace Emby.Server.Implementations.Library
File.Delete(resetfile);
}
else if (string.Equals(
spr.Pin.Replace("-", string.Empty),
pin.Replace("-", string.Empty),
spr.Pin.Replace("-", string.Empty, StringComparison.Ordinal),
pin.Replace("-", string.Empty, StringComparison.Ordinal),
StringComparison.InvariantCultureIgnoreCase))
{
var resetUser = _userManager.GetUserByName(spr.UserName);

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Globalization;
using System.Threading;

View File

@@ -4,37 +4,48 @@ using MediaBrowser.Controller.Entities;
namespace Emby.Server.Implementations.Library
{
/// <summary>
/// An invalid authentication provider.
/// </summary>
public class InvalidAuthProvider : IAuthenticationProvider
{
/// <inheritdoc />
public string Name => "InvalidOrMissingAuthenticationProvider";
/// <inheritdoc />
public bool IsEnabled => true;
/// <inheritdoc />
public Task<ProviderAuthenticationResult> Authenticate(string username, string password)
{
throw new AuthenticationException("User Account cannot login with this provider. The Normal provider for this user cannot be found");
}
/// <inheritdoc />
public bool HasPassword(User user)
{
return true;
}
/// <inheritdoc />
public Task ChangePassword(User user, string newPassword)
{
return Task.CompletedTask;
}
/// <inheritdoc />
public void ChangeEasyPassword(User user, string newPassword, string newPasswordHash)
{
// Nothing here
}
/// <inheritdoc />
public string GetPasswordHash(User user)
{
return string.Empty;
}
/// <inheritdoc />
public string GetEasyPasswordHash(User user)
{
return string.Empty;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -390,9 +392,9 @@ namespace Emby.Server.Implementations.Library
// Add this flag to GetDeletePaths if required in the future
var isRequiredForDelete = true;
foreach (var fileSystemInfo in item.GetDeletePaths().ToList())
foreach (var fileSystemInfo in item.GetDeletePaths())
{
if (File.Exists(fileSystemInfo.FullName))
if (Directory.Exists(fileSystemInfo.FullName) || File.Exists(fileSystemInfo.FullName))
{
try
{
@@ -829,7 +831,7 @@ namespace Emby.Server.Implementations.Library
{
Path = path,
IsFolder = isFolder,
OrderBy = new[] { ItemSortBy.DateCreated }.Select(i => new ValueTuple<string, SortOrder>(i, SortOrder.Descending)).ToArray(),
OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending) },
Limit = 1,
DtoOptions = new DtoOptions(true)
};
@@ -1257,7 +1259,7 @@ namespace Emby.Server.Implementations.Library
public List<BaseItem> GetItemList(InternalItemsQuery query, bool allowExternalContent)
{
if (query.Recursive && !query.ParentId.Equals(Guid.Empty))
if (query.Recursive && query.ParentId != Guid.Empty)
{
var parent = GetItemById(query.ParentId);
if (parent != null)

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -128,6 +130,21 @@ namespace Emby.Server.Implementations.Library
return streams;
}
/// <inheritdoc />
public List<MediaAttachment> GetMediaAttachments(MediaAttachmentQuery query)
{
return _itemRepo.GetMediaAttachments(query);
}
/// <inheritdoc />
public List<MediaAttachment> GetMediaAttachments(Guid itemId)
{
return GetMediaAttachments(new MediaAttachmentQuery
{
ItemId = itemId
});
}
public async Task<List<MediaSourceInfo>> GetPlaybackMediaSources(BaseItem item, User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken)
{
var mediaSources = GetStaticMediaSources(item, enablePathSubstitution, user);

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Linq;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Linq;
@@ -89,10 +91,9 @@ namespace Emby.Server.Implementations.Library
Limit = 200,
OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.Random, SortOrder.Ascending) },
OrderBy = new[] { (ItemSortBy.Random, SortOrder.Ascending) },
DtoOptions = dtoOptions
});
}

View File

@@ -3,6 +3,9 @@ using System.Text.RegularExpressions;
namespace Emby.Server.Implementations.Library
{
/// <summary>
/// Class providing extension methods for working with paths.
/// </summary>
public static class PathExtensions
{
/// <summary>
@@ -32,6 +35,7 @@ namespace Emby.Server.Implementations.Library
int end = str.IndexOf(']', start);
return str.Substring(start, end - start);
}
// for imdbid we also accept pattern matching
if (string.Equals(attrib, "imdbid", StringComparison.OrdinalIgnoreCase))
{

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.IO;
@@ -13,7 +15,7 @@ using MediaBrowser.Model.IO;
namespace Emby.Server.Implementations.Library.Resolvers.Audio
{
/// <summary>
/// Class AudioResolver
/// Class AudioResolver.
/// </summary>
public class AudioResolver : ItemResolver<MediaBrowser.Controller.Entities.Audio.Audio>, IMultiItemResolver
{

View File

@@ -13,7 +13,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Resolvers.Audio
{
/// <summary>
/// Class MusicAlbumResolver
/// Class MusicAlbumResolver.
/// </summary>
public class MusicAlbumResolver : ItemResolver<MusicAlbum>
{
@@ -21,6 +21,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
private readonly IFileSystem _fileSystem;
private readonly ILibraryManager _libraryManager;
/// <summary>
/// Initializes a new instance of the <see cref="MusicAlbumResolver"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="fileSystem">The file system.</param>
/// <param name="libraryManager">The library manager.</param>
public MusicAlbumResolver(ILogger logger, IFileSystem fileSystem, ILibraryManager libraryManager)
{
_logger = logger;
@@ -50,16 +56,25 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
return null;
}
if (!args.IsDirectory) return null;
if (!args.IsDirectory)
{
return null;
}
// Avoid mis-identifying top folders
if (args.HasParent<MusicAlbum>()) return null;
if (args.Parent.IsRoot) return null;
if (args.HasParent<MusicAlbum>())
{
return null;
}
if (args.Parent.IsRoot)
{
return null;
}
return IsMusicAlbum(args) ? new MusicAlbum() : null;
}
/// <summary>
/// Determine if the supplied file data points to a music album
/// </summary>
@@ -78,8 +93,11 @@ 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 (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService, _logger, _fileSystem, args.GetLibraryOptions(), _libraryManager)) return true;
// if (args.Parent is MusicArtist) return true; //saves us from testing children twice
if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService, _logger, _fileSystem, args.GetLibraryOptions(), _libraryManager))
{
return true;
}
}
return false;
@@ -88,7 +106,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
/// <summary>
/// Determine if the supplied list contains what we should consider music
/// </summary>
private bool ContainsMusic(IEnumerable<FileSystemMetadata> list,
private bool ContainsMusic(
IEnumerable<FileSystemMetadata> list,
bool allowSubfolders,
IDirectoryService directoryService,
ILogger logger,

View File

@@ -11,7 +11,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Resolvers.Audio
{
/// <summary>
/// Class MusicArtistResolver
/// Class MusicArtistResolver.
/// </summary>
public class MusicArtistResolver : ItemResolver<MusicArtist>
{
@@ -20,6 +20,13 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
private readonly ILibraryManager _libraryManager;
private readonly IServerConfigurationManager _config;
/// <summary>
/// Initializes a new instance of the <see cref="MusicArtistResolver"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
/// <param name="fileSystem">The file system.</param>
/// <param name="libraryManager">The library manager.</param>
/// <param name="config">The configuration manager.</param>
public MusicArtistResolver(ILogger logger, IFileSystem fileSystem, ILibraryManager libraryManager, IServerConfigurationManager config)
{
_logger = logger;
@@ -41,7 +48,10 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
/// <returns>MusicArtist.</returns>
protected override MusicArtist Resolve(ItemResolveArgs args)
{
if (!args.IsDirectory) return null;
if (!args.IsDirectory)
{
return null;
}
// Don't allow nested artists
if (args.HasParent<MusicArtist>() || args.HasParent<MusicAlbum>())
@@ -79,6 +89,5 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
// If we contain an album assume we are an artist folder
return args.FileSystemChildren.Where(i => i.IsDirectory).Any(i => albumResolver.IsMusicAlbum(i.FullName, directoryService, args.GetLibraryOptions())) ? new MusicArtist() : null;
}
}
}

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.IO;
using System.Linq;
@@ -10,7 +12,7 @@ using MediaBrowser.Model.Entities;
namespace Emby.Server.Implementations.Library.Resolvers
{
/// <summary>
/// Resolves a Path into a Video or Video subclass
/// Resolves a Path into a Video or Video subclass.
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class BaseVideoResolver<T> : MediaBrowser.Controller.Resolvers.ItemResolver<T>

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.IO;
using System.Linq;
@@ -7,18 +9,10 @@ using MediaBrowser.Model.Entities;
namespace Emby.Server.Implementations.Library.Resolvers.Books
{
/// <summary>
///
/// </summary>
public class BookResolver : MediaBrowser.Controller.Resolvers.ItemResolver<Book>
{
private readonly string[] _validExtensions = { ".pdf", ".epub", ".mobi", ".cbr", ".cbz", ".azw3" };
/// <summary>
///
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
protected override Book Resolve(ItemResolveArgs args)
{
var collectionType = args.GetCollectionType();
@@ -47,11 +41,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books
return null;
}
/// <summary>
///
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
private Book GetBook(ItemResolveArgs args)
{
var bookFiles = args.FileSystemChildren.Where(f =>

View File

@@ -5,7 +5,7 @@ using MediaBrowser.Controller.Resolvers;
namespace Emby.Server.Implementations.Library.Resolvers
{
/// <summary>
/// Class FolderResolver
/// Class FolderResolver.
/// </summary>
public class FolderResolver : FolderResolver<Folder>
{
@@ -32,7 +32,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
}
/// <summary>
/// Class FolderResolver
/// Class FolderResolver.
/// </summary>
/// <typeparam name="TItemType">The type of the T item type.</typeparam>
public abstract class FolderResolver<TItemType> : ItemResolver<TItemType>

View File

@@ -5,7 +5,7 @@ using MediaBrowser.Controller.Resolvers;
namespace Emby.Server.Implementations.Library.Resolvers
{
/// <summary>
/// Class ItemResolver
/// Class ItemResolver.
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class ItemResolver<T> : IItemResolver

View File

@@ -4,12 +4,11 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Movies;
using MediaBrowser.Controller.Library;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Library.Resolvers.Movies
{
/// <summary>
/// Class BoxSetResolver
/// Class BoxSetResolver.
/// </summary>
public class BoxSetResolver : FolderResolver<BoxSet>
{
@@ -63,7 +62,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
/// <param name="item">The item.</param>
private static void SetProviderIdFromPath(BaseItem item)
{
//we need to only look at the name of this actual item (not parents)
// we need to only look at the name of this actual item (not parents)
var justName = Path.GetFileName(item.Path);
var id = justName.GetAttributeValue("tmdbid");

View File

@@ -17,7 +17,7 @@ using MediaBrowser.Model.IO;
namespace Emby.Server.Implementations.Library.Resolvers.Movies
{
/// <summary>
/// Class MovieResolver
/// Class MovieResolver.
/// </summary>
public class MovieResolver : BaseVideoResolver<Video>, IMultiItemResolver
{
@@ -27,6 +27,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
/// <value>The priority.</value>
public override ResolverPriority Priority => ResolverPriority.Third;
/// <inheritdoc />
public MultiItemResolverResult ResolveMultiple(
Folder parent,
List<FileSystemMetadata> files,
@@ -522,7 +523,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
CollectionType.MusicVideos,
CollectionType.Movies,
CollectionType.Photos
};
};
private bool IsInvalid(Folder parent, string collectionType)
{
@@ -544,6 +545,11 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
private IImageProcessor _imageProcessor;
/// <summary>
/// Initializes a new instance of the <see cref="MovieResolver"/> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="imageProcessor">The image processor.</param>
public MovieResolver(ILibraryManager libraryManager, IImageProcessor imageProcessor)
: base(libraryManager)
{

View File

@@ -7,11 +7,19 @@ using MediaBrowser.Model.Entities;
namespace Emby.Server.Implementations.Library.Resolvers
{
/// <summary>
/// Class PhotoAlbumResolver.
/// </summary>
public class PhotoAlbumResolver : FolderResolver<PhotoAlbum>
{
private readonly IImageProcessor _imageProcessor;
private ILibraryManager _libraryManager;
/// <summary>
/// Initializes a new instance of the <see cref="PhotoAlbumResolver"/> class.
/// </summary>
/// <param name="imageProcessor">The image processor.</param>
/// <param name="libraryManager">The library manager.</param>
public PhotoAlbumResolver(IImageProcessor imageProcessor, ILibraryManager libraryManager)
{
_imageProcessor = imageProcessor;
@@ -74,9 +82,11 @@ namespace Emby.Server.Implementations.Library.Resolvers
}
}
}
return false;
}
/// <inheritdoc />
public override ResolverPriority Priority => ResolverPriority.Second;
}
}

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.IO;

View File

@@ -1,10 +1,11 @@
#pragma warning disable CS1591
using System;
using System.IO;
using System.Linq;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Playlists;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Extensions;
namespace Emby.Server.Implementations.Library.Resolvers
{

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.IO;
using System.Linq;

View File

@@ -7,7 +7,7 @@ using MediaBrowser.Model.Entities;
namespace Emby.Server.Implementations.Library.Resolvers.TV
{
/// <summary>
/// Class EpisodeResolver
/// Class EpisodeResolver.
/// </summary>
public class EpisodeResolver : BaseVideoResolver<Episode>
{
@@ -26,6 +26,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
}
var season = parent as Season;
// Just in case the user decided to nest episodes.
// Not officially supported but in some cases we can handle it.
if (season == null)
@@ -73,6 +74,10 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
return null;
}
/// <summary>
/// Initializes a new instance of the <see cref="EpisodeResolver"/> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
public EpisodeResolver(ILibraryManager libraryManager)
: base(libraryManager)
{

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.IO;
@@ -14,7 +16,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Resolvers.TV
{
/// <summary>
/// Class SeriesResolver
/// Class SeriesResolver.
/// </summary>
public class SeriesResolver : FolderResolver<Series>
{
@@ -22,6 +24,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
private readonly ILogger _logger;
private readonly ILibraryManager _libraryManager;
/// <summary>
/// Initializes a new instance of the <see cref="SeriesResolver"/> class.
/// </summary>
/// <param name="fileSystem">The file system.</param>
/// <param name="logger">The logger.</param>
/// <param name="libraryManager">The library manager.</param>
public SeriesResolver(IFileSystem fileSystem, ILogger logger, ILibraryManager libraryManager)
{
_fileSystem = fileSystem;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Linq;
@@ -13,8 +15,6 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library
{
/// <summary>
/// </summary>
public class SearchEngine : ISearchEngine
{
private readonly ILibraryManager _libraryManager;
@@ -162,7 +162,7 @@ namespace Emby.Server.Implementations.Library
Limit = query.Limit,
IncludeItemsByName = string.IsNullOrEmpty(query.ParentId),
ParentId = string.IsNullOrEmpty(query.ParentId) ? Guid.Empty : new Guid(query.ParentId),
OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending) },
OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
Recursive = true,
IsKids = query.IsKids,

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -15,7 +17,7 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library
{
/// <summary>
/// Class UserDataManager
/// Class UserDataManager.
/// </summary>
public class UserDataManager : IUserDataManager
{
@@ -55,6 +57,7 @@ namespace Emby.Server.Implementations.Library
{
throw new ArgumentNullException(nameof(userData));
}
if (item == null)
{
throw new ArgumentNullException(nameof(item));
@@ -160,11 +163,6 @@ namespace Emby.Server.Implementations.Library
return GetUserData(user, item.Id, item.GetUserDataKeys());
}
public UserItemData GetUserData(string userId, BaseItem item)
{
return GetUserData(new Guid(userId), item);
}
public UserItemData GetUserData(Guid userId, BaseItem item)
{
return GetUserData(userId, item.Id, item.GetUserDataKeys());
@@ -228,24 +226,21 @@ namespace Emby.Server.Implementations.Library
{
var pctIn = decimal.Divide(positionTicks, runtimeTicks) * 100;
// Don't track in very beginning
if (pctIn < _config.Configuration.MinResumePct)
{
// ignore progress during the beginning
positionTicks = 0;
}
// If we're at the end, assume completed
else if (pctIn > _config.Configuration.MaxResumePct || positionTicks >= runtimeTicks)
{
// mark as completed close to the end
positionTicks = 0;
data.Played = playedToCompletion = true;
}
else
{
// Enforce MinResumeDuration
var durationSeconds = TimeSpan.FromTicks(runtimeTicks).TotalSeconds;
if (durationSeconds < _config.Configuration.MinResumeDurationSeconds)
{
positionTicks = 0;
@@ -265,6 +260,7 @@ namespace Emby.Server.Implementations.Library
positionTicks = 0;
data.Played = false;
}
if (!item.SupportsPositionTicksResume)
{
positionTicks = 0;

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -36,19 +38,19 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library
{
/// <summary>
/// Class UserManager
/// Class UserManager.
/// </summary>
public class UserManager : IUserManager
{
private readonly object _policySyncLock = new object();
private readonly object _configSyncLock = new object();
/// <summary>
/// The _logger
/// The logger.
/// </summary>
private readonly ILogger _logger;
private readonly object _policySyncLock = new object();
/// <summary>
/// Gets the active user repository
/// Gets the active user repository.
/// </summary>
/// <value>The user repository.</value>
private readonly IUserRepository _userRepository;
@@ -194,10 +196,6 @@ namespace Emby.Server.Implementations.Library
return user;
}
/// <inheritdoc />
public User GetUserById(string id)
=> GetUserById(new Guid(id));
public User GetUserByName(string name)
{
if (string.IsNullOrWhiteSpace(name))
@@ -257,7 +255,12 @@ namespace Emby.Server.Implementations.Library
return builder.ToString();
}
public async Task<User> AuthenticateUser(string username, string password, string hashedPassword, string remoteEndPoint, bool isUserSession)
public async Task<User> AuthenticateUser(
string username,
string password,
string hashedPassword,
string remoteEndPoint,
bool isUserSession)
{
if (string.IsNullOrWhiteSpace(username))
{
@@ -358,6 +361,8 @@ namespace Emby.Server.Implementations.Library
return success ? user : null;
}
#nullable enable
private static string GetAuthenticationProviderId(IAuthenticationProvider provider)
{
return provider.GetType().FullName;
@@ -378,7 +383,7 @@ namespace Emby.Server.Implementations.Library
return GetPasswordResetProviders(user)[0];
}
private IAuthenticationProvider[] GetAuthenticationProviders(User user)
private IAuthenticationProvider[] GetAuthenticationProviders(User? user)
{
var authenticationProviderId = user?.Policy.AuthenticationProviderId;
@@ -392,14 +397,14 @@ namespace Emby.Server.Implementations.Library
if (providers.Length == 0)
{
// Assign the user to the InvalidAuthProvider since no configured auth provider was valid/found
_logger.LogWarning("User {UserName} was found with invalid/missing Authentication Provider {AuthenticationProviderId}. Assigning user to InvalidAuthProvider until this is corrected", user.Name, user.Policy.AuthenticationProviderId);
_logger.LogWarning("User {UserName} was found with invalid/missing Authentication Provider {AuthenticationProviderId}. Assigning user to InvalidAuthProvider until this is corrected", user?.Name, user?.Policy.AuthenticationProviderId);
providers = new IAuthenticationProvider[] { _invalidAuthProvider };
}
return providers;
}
private IPasswordResetProvider[] GetPasswordResetProviders(User user)
private IPasswordResetProvider[] GetPasswordResetProviders(User? user)
{
var passwordResetProviderId = user?.Policy.PasswordResetProviderId;
@@ -418,7 +423,11 @@ namespace Emby.Server.Implementations.Library
return providers;
}
private async Task<(string username, bool success)> AuthenticateWithProvider(IAuthenticationProvider provider, string username, string password, User resolvedUser)
private async Task<(string username, bool success)> AuthenticateWithProvider(
IAuthenticationProvider provider,
string username,
string password,
User? resolvedUser)
{
try
{
@@ -442,15 +451,15 @@ namespace Emby.Server.Implementations.Library
}
}
private async Task<(IAuthenticationProvider authenticationProvider, string username, bool success)> AuthenticateLocalUser(
private async Task<(IAuthenticationProvider? authenticationProvider, string username, bool success)> AuthenticateLocalUser(
string username,
string password,
string hashedPassword,
User user,
User? user,
string remoteEndPoint)
{
bool success = false;
IAuthenticationProvider authenticationProvider = null;
IAuthenticationProvider? authenticationProvider = null;
foreach (var provider in GetAuthenticationProviders(user))
{
@@ -468,7 +477,7 @@ namespace Emby.Server.Implementations.Library
if (!success
&& _networkManager.IsInLocalNetwork(remoteEndPoint)
&& user.Configuration.EnableLocalPassword
&& user?.Configuration.EnableLocalPassword == true
&& !string.IsNullOrEmpty(user.EasyPassword))
{
// Check easy password
@@ -547,6 +556,8 @@ namespace Emby.Server.Implementations.Library
_users[user.Id] = user;
}
#nullable restore
public UserDto GetUserDto(User user, string remoteEndPoint = null)
{
if (user == null)
@@ -748,13 +759,10 @@ namespace Emby.Server.Implementations.Library
return user;
}
/// <summary>
/// Deletes the user.
/// </summary>
/// <param name="user">The user.</param>
/// <returns>Task.</returns>
/// <exception cref="ArgumentNullException">user</exception>
/// <exception cref="ArgumentException"></exception>
/// <inheritdoc />
/// <exception cref="ArgumentNullException">The <c>user</c> is <c>null</c>.</exception>
/// <exception cref="ArgumentException">The <c>user</c> doesn't exist, or is the last administrator.</exception>
/// <exception cref="InvalidOperationException">The <c>user</c> can't be deleted; there are no other users.</exception>
public void DeleteUser(User user)
{
if (user == null)
@@ -773,7 +781,7 @@ namespace Emby.Server.Implementations.Library
if (_users.Count == 1)
{
throw new ArgumentException(string.Format(
throw new InvalidOperationException(string.Format(
CultureInfo.InvariantCulture,
"The user '{0}' cannot be deleted because there must be at least one user in the system.",
user.Name));
@@ -794,16 +802,19 @@ namespace Emby.Server.Implementations.Library
_userRepository.DeleteUser(user);
try
// Delete user config dir
lock (_configSyncLock)
lock (_policySyncLock)
{
_fileSystem.DeleteFile(configPath);
try
{
Directory.Delete(user.ConfigurationDirectoryPath, true);
}
catch (IOException ex)
{
_logger.LogError(ex, "Error deleting user config dir: {Path}", user.ConfigurationDirectoryPath);
}
}
catch (IOException ex)
{
_logger.LogError(ex, "Error deleting file {path}", configPath);
}
DeleteUserPolicy(user);
_users.TryRemove(user.Id, out _);
@@ -912,10 +923,9 @@ namespace Emby.Server.Implementations.Library
public UserPolicy GetUserPolicy(User user)
{
var path = GetPolicyFilePath(user);
if (!File.Exists(path))
{
return GetDefaultPolicy(user);
return GetDefaultPolicy();
}
try
@@ -925,19 +935,15 @@ namespace Emby.Server.Implementations.Library
return (UserPolicy)_xmlSerializer.DeserializeFromFile(typeof(UserPolicy), path);
}
}
catch (IOException)
{
return GetDefaultPolicy(user);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error reading policy file: {path}", path);
_logger.LogError(ex, "Error reading policy file: {Path}", path);
return GetDefaultPolicy(user);
return GetDefaultPolicy();
}
}
private static UserPolicy GetDefaultPolicy(User user)
private static UserPolicy GetDefaultPolicy()
{
return new UserPolicy
{
@@ -977,27 +983,6 @@ namespace Emby.Server.Implementations.Library
}
}
private void DeleteUserPolicy(User user)
{
var path = GetPolicyFilePath(user);
try
{
lock (_policySyncLock)
{
_fileSystem.DeleteFile(path);
}
}
catch (IOException)
{
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting policy file");
}
}
private static string GetPolicyFilePath(User user)
{
return Path.Combine(user.ConfigurationDirectoryPath, "policy.xml");
@@ -1024,19 +1009,14 @@ namespace Emby.Server.Implementations.Library
return (UserConfiguration)_xmlSerializer.DeserializeFromFile(typeof(UserConfiguration), path);
}
}
catch (IOException)
{
return new UserConfiguration();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error reading policy file: {path}", path);
_logger.LogError(ex, "Error reading policy file: {Path}", path);
return new UserConfiguration();
}
}
private readonly object _configSyncLock = new object();
public void UpdateConfiguration(Guid userId, UserConfiguration config)
{
var user = GetUserById(userId);

View File

@@ -1,3 +1,5 @@
#pragma warning disable CS1591
using System;
using System.Collections.Generic;
using System.Globalization;
@@ -340,7 +342,7 @@ namespace Emby.Server.Implementations.Library
var query = new InternalItemsQuery(user)
{
IncludeItemTypes = includeItemTypes,
OrderBy = new[] { new ValueTuple<string, SortOrder>(ItemSortBy.DateCreated, SortOrder.Descending) },
OrderBy = new[] { (ItemSortBy.DateCreated, SortOrder.Descending) },
IsFolder = includeItemTypes.Length == 0 ? false : (bool?)null,
ExcludeItemTypes = excludeItemTypes,
IsVirtualItem = false,

View File

@@ -8,12 +8,12 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
{
/// <summary>
/// Class ArtistsPostScanTask
/// Class ArtistsPostScanTask.
/// </summary>
public class ArtistsPostScanTask : ILibraryPostScanTask
{
/// <summary>
/// The _library manager
/// The _library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
private readonly ILogger _logger;
@@ -23,6 +23,8 @@ namespace Emby.Server.Implementations.Library.Validators
/// Initializes a new instance of the <see cref="ArtistsPostScanTask" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public ArtistsPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
{
_libraryManager = libraryManager;

View File

@@ -12,17 +12,17 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
{
/// <summary>
/// Class ArtistsValidator
/// Class ArtistsValidator.
/// </summary>
public class ArtistsValidator
{
/// <summary>
/// The _library manager
/// The library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
/// <summary>
/// The _logger
/// The logger.
/// </summary>
private readonly ILogger _logger;
private readonly IItemRepository _itemRepo;

View File

@@ -7,6 +7,9 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
{
/// <summary>
/// Class GenresPostScanTask.
/// </summary>
public class GenresPostScanTask : ILibraryPostScanTask
{
/// <summary>

View File

@@ -7,19 +7,28 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
{
class GenresValidator
/// <summary>
/// Class GenresValidator.
/// </summary>
public class GenresValidator
{
/// <summary>
/// The _library manager
/// The library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
private readonly IItemRepository _itemRepo;
/// <summary>
/// The _logger
/// The logger.
/// </summary>
private readonly ILogger _logger;
/// <summary>
/// Initializes a new instance of the <see cref="GenresValidator"/> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public GenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
{
_libraryManager = libraryManager;

View File

@@ -8,12 +8,12 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
{
/// <summary>
/// Class MusicGenresPostScanTask
/// Class MusicGenresPostScanTask.
/// </summary>
public class MusicGenresPostScanTask : ILibraryPostScanTask
{
/// <summary>
/// The _library manager
/// The library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
private readonly ILogger _logger;

View File

@@ -7,19 +7,28 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
{
class MusicGenresValidator
/// <summary>
/// Class MusicGenresValidator.
/// </summary>
public class MusicGenresValidator
{
/// <summary>
/// The _library manager
/// The library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
/// <summary>
/// The _logger
/// The logger.
/// </summary>
private readonly ILogger _logger;
private readonly IItemRepository _itemRepo;
/// <summary>
/// Initializes a new instance of the <see cref="MusicGenresValidator" /> class.
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">The item repository.</param>
public MusicGenresValidator(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
{
_libraryManager = libraryManager;

View File

@@ -32,6 +32,7 @@ namespace Emby.Server.Implementations.Library.Validators
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="fileSystem">The file system.</param>
public PeopleValidator(ILibraryManager libraryManager, ILogger logger, IFileSystem fileSystem)
{
_libraryManager = libraryManager;

View File

@@ -8,12 +8,12 @@ using Microsoft.Extensions.Logging;
namespace Emby.Server.Implementations.Library.Validators
{
/// <summary>
/// Class MusicGenresPostScanTask
/// Class MusicGenresPostScanTask.
/// </summary>
public class StudiosPostScanTask : ILibraryPostScanTask
{
/// <summary>
/// The _library manager
/// The _library manager.
/// </summary>
private readonly ILibraryManager _libraryManager;
@@ -25,7 +25,7 @@ namespace Emby.Server.Implementations.Library.Validators
/// </summary>
/// <param name="libraryManager">The library manager.</param>
/// <param name="logger">The logger.</param>
/// <param name="itemRepo">Th item repository.</param>
/// <param name="itemRepo">The item repository.</param>
public StudiosPostScanTask(ILibraryManager libraryManager, ILogger logger, IItemRepository itemRepo)
{
_libraryManager = libraryManager;

Some files were not shown because too many files have changed in this diff Show More