Merge branch 'namingtests' of https://github.com/Bond-009/jellyfin into namingtests
This commit is contained in:
commit
a1ca50fd5a
|
@ -30,6 +30,7 @@
|
|||
- [Khinenw](https://github.com/HelloWorld017)
|
||||
- [fhriley](https://github.com/fhriley)
|
||||
- [nevado](https://github.com/nevado)
|
||||
- [mark-monteiro](https://github.com/mark-monteiro)
|
||||
|
||||
# Emby Contributors
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Emby.Dlna.Main;
|
||||
|
@ -195,7 +193,7 @@ namespace Emby.Dlna.Api
|
|||
|
||||
private ControlResponse PostAsync(Stream requestStream, IUpnpService service)
|
||||
{
|
||||
var id = GetPathValue(2);
|
||||
var id = GetPathValue(2).ToString();
|
||||
|
||||
return service.ProcessControlRequest(new ControlRequest
|
||||
{
|
||||
|
@ -206,51 +204,99 @@ namespace Emby.Dlna.Api
|
|||
});
|
||||
}
|
||||
|
||||
protected string GetPathValue(int index)
|
||||
// Copied from MediaBrowser.Api/BaseApiService.cs
|
||||
// TODO: Remove code duplication
|
||||
/// <summary>
|
||||
/// Gets the path segment at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index of the path segment.</param>
|
||||
/// <returns>The path segment at the specified index.</returns>
|
||||
/// <exception cref="IndexOutOfRangeException" >Path doesn't contain enough segments.</exception>
|
||||
/// <exception cref="InvalidDataException" >Path doesn't start with the base url.</exception>
|
||||
protected internal ReadOnlySpan<char> GetPathValue(int index)
|
||||
{
|
||||
var pathInfo = Parse(Request.PathInfo);
|
||||
var first = pathInfo[0];
|
||||
static void ThrowIndexOutOfRangeException()
|
||||
=> throw new IndexOutOfRangeException("Path doesn't contain enough segments.");
|
||||
|
||||
static void ThrowInvalidDataException()
|
||||
=> throw new InvalidDataException("Path doesn't start with the base url.");
|
||||
|
||||
ReadOnlySpan<char> path = Request.PathInfo;
|
||||
|
||||
// Remove the protocol part from the url
|
||||
int pos = path.LastIndexOf("://");
|
||||
if (pos != -1)
|
||||
{
|
||||
path = path.Slice(pos + 3);
|
||||
}
|
||||
|
||||
// Remove the query string
|
||||
pos = path.LastIndexOf('?');
|
||||
if (pos != -1)
|
||||
{
|
||||
path = path.Slice(0, pos);
|
||||
}
|
||||
|
||||
// Remove the domain
|
||||
pos = path.IndexOf('/');
|
||||
if (pos != -1)
|
||||
{
|
||||
path = path.Slice(pos);
|
||||
}
|
||||
|
||||
// Remove base url
|
||||
string baseUrl = _configurationManager.Configuration.BaseUrl;
|
||||
|
||||
// backwards compatibility
|
||||
if (baseUrl.Length == 0)
|
||||
int baseUrlLen = baseUrl.Length;
|
||||
if (baseUrlLen != 0)
|
||||
{
|
||||
if (string.Equals(first, "mediabrowser", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(first, "emby", StringComparison.OrdinalIgnoreCase))
|
||||
if (path.StartsWith(baseUrl, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
index++;
|
||||
path = path.Slice(baseUrlLen);
|
||||
}
|
||||
}
|
||||
else if (string.Equals(first, baseUrl.Remove(0, 1)))
|
||||
{
|
||||
index++;
|
||||
var second = pathInfo[1];
|
||||
if (string.Equals(second, "mediabrowser", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(second, "emby", StringComparison.OrdinalIgnoreCase))
|
||||
else
|
||||
{
|
||||
index++;
|
||||
// The path doesn't start with the base url,
|
||||
// how did we get here?
|
||||
ThrowInvalidDataException();
|
||||
}
|
||||
}
|
||||
|
||||
return pathInfo[index];
|
||||
}
|
||||
// Remove leading /
|
||||
path = path.Slice(1);
|
||||
|
||||
private static string[] Parse(string pathUri)
|
||||
{
|
||||
var actionParts = pathUri.Split(new[] { "://" }, StringSplitOptions.None);
|
||||
|
||||
var pathInfo = actionParts[actionParts.Length - 1];
|
||||
|
||||
var optionsPos = pathInfo.LastIndexOf('?');
|
||||
if (optionsPos != -1)
|
||||
// Backwards compatibility
|
||||
const string Emby = "emby/";
|
||||
if (path.StartsWith(Emby, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
pathInfo = pathInfo.Substring(0, optionsPos);
|
||||
path = path.Slice(Emby.Length);
|
||||
}
|
||||
|
||||
var args = pathInfo.Split('/');
|
||||
const string MediaBrowser = "mediabrowser/";
|
||||
if (path.StartsWith(MediaBrowser, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
path = path.Slice(MediaBrowser.Length);
|
||||
}
|
||||
|
||||
return args.Skip(1).ToArray();
|
||||
// Skip segments until we are at the right index
|
||||
for (int i = 0; i < index; i++)
|
||||
{
|
||||
pos = path.IndexOf('/');
|
||||
if (pos == -1)
|
||||
{
|
||||
ThrowIndexOutOfRangeException();
|
||||
}
|
||||
|
||||
path = path.Slice(pos + 1);
|
||||
}
|
||||
|
||||
// Remove the rest
|
||||
pos = path.IndexOf('/');
|
||||
if (pos != -1)
|
||||
{
|
||||
path = path.Slice(0, pos);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public object Get(GetIcon request)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Emby.Dlna.Service;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Controller.Configuration;
|
||||
|
@ -104,7 +103,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
{
|
||||
if (!string.IsNullOrEmpty(profile.UserId))
|
||||
{
|
||||
var user = _userManager.GetUserById(profile.UserId);
|
||||
var user = _userManager.GetUserById(Guid.Parse(profile.UserId));
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
|
@ -116,7 +115,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
|
||||
if (!string.IsNullOrEmpty(userId))
|
||||
{
|
||||
var user = _userManager.GetUserById(userId);
|
||||
var user = _userManager.GetUserById(Guid.Parse(userId));
|
||||
|
||||
if (user != null)
|
||||
{
|
||||
|
|
|
@ -425,10 +425,10 @@ namespace Emby.Dlna.ContentDirectory
|
|||
{
|
||||
var folder = (Folder)item;
|
||||
|
||||
var sortOrders = new List<string>();
|
||||
var sortOrders = new List<(string, SortOrder)>();
|
||||
if (!folder.IsPreSorted)
|
||||
{
|
||||
sortOrders.Add(ItemSortBy.SortName);
|
||||
sortOrders.Add((ItemSortBy.SortName, sort.SortOrder));
|
||||
}
|
||||
|
||||
var mediaTypes = new List<string>();
|
||||
|
@ -464,7 +464,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
{
|
||||
Limit = limit,
|
||||
StartIndex = startIndex,
|
||||
OrderBy = sortOrders.Select(i => new ValueTuple<string, SortOrder>(i, sort.SortOrder)).ToArray(),
|
||||
OrderBy = sortOrders,
|
||||
User = user,
|
||||
Recursive = true,
|
||||
IsMissing = false,
|
||||
|
@ -872,10 +872,10 @@ namespace Emby.Dlna.ContentDirectory
|
|||
query.Parent = parent;
|
||||
query.SetUser(user);
|
||||
|
||||
query.OrderBy = new ValueTuple<string, SortOrder>[]
|
||||
query.OrderBy = new[]
|
||||
{
|
||||
new ValueTuple<string, SortOrder> (ItemSortBy.DatePlayed, SortOrder.Descending),
|
||||
new ValueTuple<string, SortOrder> (ItemSortBy.SortName, SortOrder.Ascending)
|
||||
(ItemSortBy.DatePlayed, SortOrder.Descending),
|
||||
(ItemSortBy.SortName, SortOrder.Ascending)
|
||||
};
|
||||
|
||||
query.IsResumable = true;
|
||||
|
@ -1121,7 +1121,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
|
||||
private QueryResult<ServerItem> GetMusicLatest(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.OrderBy = new ValueTuple<string, SortOrder>[] { };
|
||||
query.OrderBy = Array.Empty<(string, SortOrder)>();
|
||||
|
||||
var items = _userViewManager.GetLatestItems(new LatestItemsQuery
|
||||
{
|
||||
|
@ -1138,7 +1138,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
|
||||
private QueryResult<ServerItem> GetNextUp(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.OrderBy = new ValueTuple<string, SortOrder>[] { };
|
||||
query.OrderBy = Array.Empty<(string, SortOrder)>();
|
||||
|
||||
var result = _tvSeriesManager.GetNextUp(new NextUpQuery
|
||||
{
|
||||
|
@ -1153,7 +1153,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
|
||||
private QueryResult<ServerItem> GetTvLatest(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.OrderBy = new ValueTuple<string, SortOrder>[] { };
|
||||
query.OrderBy = Array.Empty<(string, SortOrder)>();
|
||||
|
||||
var items = _userViewManager.GetLatestItems(new LatestItemsQuery
|
||||
{
|
||||
|
@ -1170,7 +1170,7 @@ namespace Emby.Dlna.ContentDirectory
|
|||
|
||||
private QueryResult<ServerItem> GetMovieLatest(BaseItem parent, User user, InternalItemsQuery query)
|
||||
{
|
||||
query.OrderBy = new ValueTuple<string, SortOrder>[] { };
|
||||
query.OrderBy = Array.Empty<(string, SortOrder)>();
|
||||
|
||||
var items = _userViewManager.GetLatestItems(new LatestItemsQuery
|
||||
{
|
||||
|
@ -1274,13 +1274,14 @@ namespace Emby.Dlna.ContentDirectory
|
|||
|
||||
private void SetSorting(InternalItemsQuery query, SortCriteria sort, bool isPreSorted)
|
||||
{
|
||||
var sortOrders = new List<string>();
|
||||
if (!isPreSorted)
|
||||
if (isPreSorted)
|
||||
{
|
||||
sortOrders.Add(ItemSortBy.SortName);
|
||||
query.OrderBy = Array.Empty<(string, SortOrder)>();
|
||||
}
|
||||
else
|
||||
{
|
||||
query.OrderBy = new[] { (ItemSortBy.SortName, sort.SortOrder) };
|
||||
}
|
||||
|
||||
query.OrderBy = sortOrders.Select(i => new ValueTuple<string, SortOrder>(i, sort.SortOrder)).ToArray();
|
||||
}
|
||||
|
||||
private QueryResult<ServerItem> ApplyPaging(QueryResult<ServerItem> result, int? startIndex, int? limit)
|
||||
|
|
|
@ -315,7 +315,7 @@ namespace Emby.Naming.Common
|
|||
// This isn't a Kodi naming rule, but the expression below causes false positives,
|
||||
// so we make sure this one gets tested first.
|
||||
// "Foo Bar 889"
|
||||
new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?<seriesname>(\w+\s*?)*)\s(?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*[^\\\/]*$")
|
||||
new EpisodeExpression(@".*[\\\/](?![Ee]pisode)(?<seriesname>[\w\s]+?)\s(?<epnumber>\d{1,3})(-(?<endingepnumber>\d{2,3}))*[^\\\/]*$")
|
||||
{
|
||||
IsNamed = true
|
||||
},
|
||||
|
@ -337,8 +337,8 @@ namespace Emby.Naming.Common
|
|||
|
||||
// *** End Kodi Standard Naming
|
||||
|
||||
// [bar] Foo - 1 [baz]
|
||||
new EpisodeExpression(@".*?(\[.*?\])+.*?(?<seriesname>(\w+\s*?)+?)[-\s_]+(?<epnumber>\d+).*$")
|
||||
// [bar] Foo - 1 [baz]
|
||||
new EpisodeExpression(@".*?(\[.*?\])+.*?(?<seriesname>[\w\s]+?)[-\s_]+(?<epnumber>\d+).*$")
|
||||
{
|
||||
IsNamed = true
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
|
|
@ -133,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();
|
||||
|
@ -247,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());
|
||||
|
@ -259,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 =>
|
||||
|
@ -305,6 +314,7 @@ namespace Emby.Server.Implementations.AppBase
|
|||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SaveConfiguration(string key, object configuration)
|
||||
{
|
||||
var configurationStore = GetConfigurationStore(key);
|
||||
|
@ -341,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
|
||||
|
@ -350,6 +365,7 @@ namespace Emby.Server.Implementations.AppBase
|
|||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Type GetConfigurationType(string key)
|
||||
{
|
||||
return GetConfigurationStore(key)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System.Collections.Generic;
|
||||
using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Model.Branding;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
|
|
@ -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;
|
||||
|
@ -2831,8 +2832,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 +2882,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 +2897,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 +2913,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;
|
||||
}));
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using MediaBrowser.Model.Diagnostics;
|
||||
|
||||
namespace Emby.Server.Implementations.Diagnostics
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
|
|
@ -282,6 +282,7 @@ namespace Emby.Server.Implementations.HttpClientManager
|
|||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<HttpResponseInfo> Post(HttpRequestOptions options)
|
||||
=> SendAsync(options, HttpMethod.Post);
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Emby.Server.Implementations.SocketSharp;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
namespace Emby.Server.Implementations.IO
|
||||
{
|
||||
public class ExtendedFileSystemInfo
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using MediaBrowser.Model.IO;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
@ -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)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
|
|
@ -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
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 =>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
#pragma warning disable CS1591
|
||||
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
/// <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))
|
||||
|
@ -358,6 +356,8 @@ namespace Emby.Server.Implementations.Library
|
|||
return success ? user : null;
|
||||
}
|
||||
|
||||
#nullable enable
|
||||
|
||||
private static string GetAuthenticationProviderId(IAuthenticationProvider provider)
|
||||
{
|
||||
return provider.GetType().FullName;
|
||||
|
@ -378,7 +378,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;
|
||||
|
||||
|
@ -399,7 +399,7 @@ namespace Emby.Server.Implementations.Library
|
|||
return providers;
|
||||
}
|
||||
|
||||
private IPasswordResetProvider[] GetPasswordResetProviders(User user)
|
||||
private IPasswordResetProvider[] GetPasswordResetProviders(User? user)
|
||||
{
|
||||
var passwordResetProviderId = user?.Policy.PasswordResetProviderId;
|
||||
|
||||
|
@ -418,7 +418,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 +446,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))
|
||||
{
|
||||
|
@ -547,6 +551,8 @@ namespace Emby.Server.Implementations.Library
|
|||
_users[user.Id] = user;
|
||||
}
|
||||
|
||||
#nullable restore
|
||||
|
||||
public UserDto GetUserDto(User user, string remoteEndPoint = null)
|
||||
{
|
||||
if (user == null)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -7,6 +7,9 @@ using Microsoft.Extensions.Logging;
|
|||
|
||||
namespace Emby.Server.Implementations.Library.Validators
|
||||
{
|
||||
/// <summary>
|
||||
/// Class GenresPostScanTask.
|
||||
/// </summary>
|
||||
public class GenresPostScanTask : ILibraryPostScanTask
|
||||
{
|
||||
/// <summary>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user