mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-07-01 11:52:52 +01:00
Merge branch 'master' into network-rewrite
This commit is contained in:
@@ -80,11 +80,13 @@ using MediaBrowser.Controller.Subtitles;
|
||||
using MediaBrowser.Controller.SyncPlay;
|
||||
using MediaBrowser.Controller.TV;
|
||||
using MediaBrowser.LocalMetadata.Savers;
|
||||
using MediaBrowser.MediaEncoding.BdInfo;
|
||||
using MediaBrowser.MediaEncoding.Subtitles;
|
||||
using MediaBrowser.Model.Cryptography;
|
||||
using MediaBrowser.Model.Dlna;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using MediaBrowser.Model.IO;
|
||||
using MediaBrowser.Model.MediaInfo;
|
||||
using MediaBrowser.Model.Net;
|
||||
using MediaBrowser.Model.Serialization;
|
||||
using MediaBrowser.Model.System;
|
||||
@@ -529,6 +531,8 @@ namespace Emby.Server.Implementations
|
||||
|
||||
serviceCollection.AddSingleton<ILocalizationManager, LocalizationManager>();
|
||||
|
||||
serviceCollection.AddSingleton<IBlurayExaminer, BdInfoExaminer>();
|
||||
|
||||
serviceCollection.AddSingleton<IUserDataRepository, SqliteUserDataRepository>();
|
||||
serviceCollection.AddSingleton<IUserDataManager, UserDataManager>();
|
||||
|
||||
|
||||
@@ -157,16 +157,16 @@ namespace Emby.Server.Implementations.Channels
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public QueryResult<Channel> GetChannelsInternal(ChannelQuery query)
|
||||
public async Task<QueryResult<Channel>> GetChannelsInternalAsync(ChannelQuery query)
|
||||
{
|
||||
var user = query.UserId.Equals(default)
|
||||
? null
|
||||
: _userManager.GetUserById(query.UserId);
|
||||
|
||||
var channels = GetAllChannels()
|
||||
.Select(GetChannelEntity)
|
||||
var channels = await GetAllChannelEntitiesAsync()
|
||||
.OrderBy(i => i.SortName)
|
||||
.ToList();
|
||||
.ToListAsync()
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (query.IsRecordingsFolder.HasValue)
|
||||
{
|
||||
@@ -226,6 +226,7 @@ namespace Emby.Server.Implementations.Channels
|
||||
|
||||
if (user is not null)
|
||||
{
|
||||
var userId = user.Id.ToString("N", CultureInfo.InvariantCulture);
|
||||
channels = channels.Where(i =>
|
||||
{
|
||||
if (!i.IsVisible(user))
|
||||
@@ -235,7 +236,7 @@ namespace Emby.Server.Implementations.Channels
|
||||
|
||||
try
|
||||
{
|
||||
return GetChannelProvider(i).IsEnabledFor(user.Id.ToString("N", CultureInfo.InvariantCulture));
|
||||
return GetChannelProvider(i).IsEnabledFor(userId);
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -258,7 +259,7 @@ namespace Emby.Server.Implementations.Channels
|
||||
{
|
||||
foreach (var item in all)
|
||||
{
|
||||
RefreshLatestChannelItems(GetChannelProvider(item), CancellationToken.None).GetAwaiter().GetResult();
|
||||
await RefreshLatestChannelItems(GetChannelProvider(item), CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,13 +270,13 @@ namespace Emby.Server.Implementations.Channels
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public QueryResult<BaseItemDto> GetChannels(ChannelQuery query)
|
||||
public async Task<QueryResult<BaseItemDto>> GetChannelsAsync(ChannelQuery query)
|
||||
{
|
||||
var user = query.UserId.Equals(default)
|
||||
? null
|
||||
: _userManager.GetUserById(query.UserId);
|
||||
|
||||
var internalResult = GetChannelsInternal(query);
|
||||
var internalResult = await GetChannelsInternalAsync(query).ConfigureAwait(false);
|
||||
|
||||
var dtoOptions = new DtoOptions();
|
||||
|
||||
@@ -327,9 +328,12 @@ namespace Emby.Server.Implementations.Channels
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
private Channel GetChannelEntity(IChannel channel)
|
||||
private async IAsyncEnumerable<Channel> GetAllChannelEntitiesAsync()
|
||||
{
|
||||
return GetChannel(GetInternalChannelId(channel.Name)) ?? GetChannel(channel, CancellationToken.None).GetAwaiter().GetResult();
|
||||
foreach (IChannel channel in GetAllChannels())
|
||||
{
|
||||
yield return GetChannel(GetInternalChannelId(channel.Name)) ?? await GetChannel(channel, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private MediaSourceInfo[] GetSavedMediaSources(BaseItem item)
|
||||
|
||||
@@ -276,25 +276,31 @@ namespace Emby.Server.Implementations.EntryPoints
|
||||
/// Libraries the update timer callback.
|
||||
/// </summary>
|
||||
/// <param name="state">The state.</param>
|
||||
private void LibraryUpdateTimerCallback(object state)
|
||||
private async void LibraryUpdateTimerCallback(object state)
|
||||
{
|
||||
List<Folder> foldersAddedTo;
|
||||
List<Folder> foldersRemovedFrom;
|
||||
List<BaseItem> itemsUpdated;
|
||||
List<BaseItem> itemsAdded;
|
||||
List<BaseItem> itemsRemoved;
|
||||
lock (_libraryChangedSyncLock)
|
||||
{
|
||||
// Remove dupes in case some were saved multiple times
|
||||
var foldersAddedTo = _foldersAddedTo
|
||||
foldersAddedTo = _foldersAddedTo
|
||||
.DistinctBy(x => x.Id)
|
||||
.ToList();
|
||||
|
||||
var foldersRemovedFrom = _foldersRemovedFrom
|
||||
foldersRemovedFrom = _foldersRemovedFrom
|
||||
.DistinctBy(x => x.Id)
|
||||
.ToList();
|
||||
|
||||
var itemsUpdated = _itemsUpdated
|
||||
itemsUpdated = _itemsUpdated
|
||||
.Where(i => !_itemsAdded.Contains(i))
|
||||
.DistinctBy(x => x.Id)
|
||||
.ToList();
|
||||
|
||||
SendChangeNotifications(_itemsAdded.ToList(), itemsUpdated, _itemsRemoved.ToList(), foldersAddedTo, foldersRemovedFrom, CancellationToken.None).GetAwaiter().GetResult();
|
||||
itemsAdded = _itemsAdded.ToList();
|
||||
itemsRemoved = _itemsRemoved.ToList();
|
||||
|
||||
if (LibraryUpdateTimer is not null)
|
||||
{
|
||||
@@ -308,6 +314,8 @@ namespace Emby.Server.Implementations.EntryPoints
|
||||
_foldersAddedTo.Clear();
|
||||
_foldersRemovedFrom.Clear();
|
||||
}
|
||||
|
||||
await SendChangeNotifications(itemsAdded, itemsUpdated, itemsRemoved, foldersAddedTo, foldersRemovedFrom, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -87,29 +87,30 @@ namespace Emby.Server.Implementations.EntryPoints
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTimerCallback(object? state)
|
||||
private async void UpdateTimerCallback(object? state)
|
||||
{
|
||||
List<KeyValuePair<Guid, List<BaseItem>>> changes;
|
||||
lock (_syncLock)
|
||||
{
|
||||
// Remove dupes in case some were saved multiple times
|
||||
var changes = _changedItems.ToList();
|
||||
changes = _changedItems.ToList();
|
||||
_changedItems.Clear();
|
||||
|
||||
SendNotifications(changes, CancellationToken.None).GetAwaiter().GetResult();
|
||||
|
||||
if (_updateTimer is not null)
|
||||
{
|
||||
_updateTimer.Dispose();
|
||||
_updateTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
await SendNotifications(changes, CancellationToken.None).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task SendNotifications(List<KeyValuePair<Guid, List<BaseItem>>> changes, CancellationToken cancellationToken)
|
||||
{
|
||||
foreach (var pair in changes)
|
||||
foreach ((var key, var value) in changes)
|
||||
{
|
||||
await SendNotifications(pair.Key, pair.Value, cancellationToken).ConfigureAwait(false);
|
||||
await SendNotifications(key, value, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,6 +113,7 @@ namespace Emby.Server.Implementations.Library
|
||||
/// <param name="imageProcessor">The image processor.</param>
|
||||
/// <param name="memoryCache">The memory cache.</param>
|
||||
/// <param name="namingOptions">The naming options.</param>
|
||||
/// <param name="directoryService">The directory service.</param>
|
||||
public LibraryManager(
|
||||
IServerApplicationHost appHost,
|
||||
ILoggerFactory loggerFactory,
|
||||
@@ -128,7 +129,8 @@ namespace Emby.Server.Implementations.Library
|
||||
IItemRepository itemRepository,
|
||||
IImageProcessor imageProcessor,
|
||||
IMemoryCache memoryCache,
|
||||
NamingOptions namingOptions)
|
||||
NamingOptions namingOptions,
|
||||
IDirectoryService directoryService)
|
||||
{
|
||||
_appHost = appHost;
|
||||
_logger = loggerFactory.CreateLogger<LibraryManager>();
|
||||
@@ -146,7 +148,7 @@ namespace Emby.Server.Implementations.Library
|
||||
_memoryCache = memoryCache;
|
||||
_namingOptions = namingOptions;
|
||||
|
||||
_extraResolver = new ExtraResolver(loggerFactory.CreateLogger<ExtraResolver>(), namingOptions);
|
||||
_extraResolver = new ExtraResolver(loggerFactory.CreateLogger<ExtraResolver>(), namingOptions, directoryService);
|
||||
|
||||
_configurationManager.ConfigurationUpdated += ConfigurationUpdated;
|
||||
|
||||
@@ -537,7 +539,7 @@ namespace Emby.Server.Implementations.Library
|
||||
collectionType = GetContentTypeOverride(fullPath, true);
|
||||
}
|
||||
|
||||
var args = new ItemResolveArgs(_configurationManager.ApplicationPaths, directoryService)
|
||||
var args = new ItemResolveArgs(_configurationManager.ApplicationPaths, this)
|
||||
{
|
||||
Parent = parent,
|
||||
FileInfo = fileInfo,
|
||||
|
||||
@@ -192,7 +192,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||
continue;
|
||||
}
|
||||
|
||||
if (resolvedItem.Files.Count == 0)
|
||||
// Until multi-part books are handled letting files stack hides them from browsing in the client
|
||||
if (resolvedItem.Files.Count == 0 || resolvedItem.Extras.Count > 0 || resolvedItem.AlternateVersions.Count > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -25,16 +25,19 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||
{
|
||||
private readonly ILogger<MusicAlbumResolver> _logger;
|
||||
private readonly NamingOptions _namingOptions;
|
||||
private readonly IDirectoryService _directoryService;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MusicAlbumResolver"/> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="namingOptions">The naming options.</param>
|
||||
public MusicAlbumResolver(ILogger<MusicAlbumResolver> logger, NamingOptions namingOptions)
|
||||
/// <param name="directoryService">The directory service.</param>
|
||||
public MusicAlbumResolver(ILogger<MusicAlbumResolver> logger, NamingOptions namingOptions, IDirectoryService directoryService)
|
||||
{
|
||||
_logger = logger;
|
||||
_namingOptions = namingOptions;
|
||||
_directoryService = directoryService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -109,7 +112,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||
}
|
||||
|
||||
// If args contains music it's a music album
|
||||
if (ContainsMusic(args.FileSystemChildren, true, args.DirectoryService))
|
||||
if (ContainsMusic(args.FileSystemChildren, true, _directoryService))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
using Emby.Naming.Common;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -18,19 +19,23 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||
public class MusicArtistResolver : ItemResolver<MusicArtist>
|
||||
{
|
||||
private readonly ILogger<MusicAlbumResolver> _logger;
|
||||
private NamingOptions _namingOptions;
|
||||
private readonly NamingOptions _namingOptions;
|
||||
private readonly IDirectoryService _directoryService;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MusicArtistResolver"/> class.
|
||||
/// </summary>
|
||||
/// <param name="logger">Instance of the <see cref="MusicAlbumResolver"/> interface.</param>
|
||||
/// <param name="namingOptions">The <see cref="NamingOptions"/>.</param>
|
||||
/// <param name="directoryService">The directory service.</param>
|
||||
public MusicArtistResolver(
|
||||
ILogger<MusicAlbumResolver> logger,
|
||||
NamingOptions namingOptions)
|
||||
NamingOptions namingOptions,
|
||||
IDirectoryService directoryService)
|
||||
{
|
||||
_logger = logger;
|
||||
_namingOptions = namingOptions;
|
||||
_directoryService = directoryService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -78,9 +83,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||
return null;
|
||||
}
|
||||
|
||||
var directoryService = args.DirectoryService;
|
||||
|
||||
var albumResolver = new MusicAlbumResolver(_logger, _namingOptions);
|
||||
var albumResolver = new MusicAlbumResolver(_logger, _namingOptions, _directoryService);
|
||||
|
||||
var directories = args.FileSystemChildren.Where(i => i.IsDirectory);
|
||||
|
||||
@@ -97,7 +100,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio
|
||||
}
|
||||
|
||||
// If we contain a music album assume we are an artist folder
|
||||
if (albumResolver.IsMusicAlbum(fileSystemInfo.FullName, directoryService))
|
||||
if (albumResolver.IsMusicAlbum(fileSystemInfo.FullName, _directoryService))
|
||||
{
|
||||
// Stop once we see a music album
|
||||
state.Stop();
|
||||
|
||||
@@ -25,14 +25,17 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
|
||||
protected BaseVideoResolver(ILogger logger, NamingOptions namingOptions)
|
||||
protected BaseVideoResolver(ILogger logger, NamingOptions namingOptions, IDirectoryService directoryService)
|
||||
{
|
||||
_logger = logger;
|
||||
NamingOptions = namingOptions;
|
||||
DirectoryService = directoryService;
|
||||
}
|
||||
|
||||
protected NamingOptions NamingOptions { get; }
|
||||
|
||||
protected IDirectoryService DirectoryService { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Resolves the specified args.
|
||||
/// </summary>
|
||||
@@ -65,13 +68,25 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
||||
var filename = child.Name;
|
||||
if (child.IsDirectory)
|
||||
{
|
||||
if (IsDvdDirectory(child.FullName, filename, args.DirectoryService))
|
||||
if (IsDvdDirectory(child.FullName, filename, DirectoryService))
|
||||
{
|
||||
videoType = VideoType.Dvd;
|
||||
var videoTmp = new TVideoType
|
||||
{
|
||||
Path = args.Path,
|
||||
VideoType = VideoType.Dvd
|
||||
};
|
||||
Set3DFormat(videoTmp);
|
||||
return videoTmp;
|
||||
}
|
||||
else if (IsBluRayDirectory(filename))
|
||||
{
|
||||
videoType = VideoType.BluRay;
|
||||
var videoTmp = new TVideoType
|
||||
{
|
||||
Path = args.Path,
|
||||
VideoType = VideoType.BluRay
|
||||
};
|
||||
Set3DFormat(videoTmp);
|
||||
return videoTmp;
|
||||
}
|
||||
}
|
||||
else if (IsDvdFile(filename))
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.IO;
|
||||
using Emby.Naming.Common;
|
||||
using Emby.Naming.Video;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -25,11 +26,12 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="namingOptions">An instance of <see cref="NamingOptions"/>.</param>
|
||||
public ExtraResolver(ILogger<ExtraResolver> logger, NamingOptions namingOptions)
|
||||
/// <param name="directoryService">The directory service.</param>
|
||||
public ExtraResolver(ILogger<ExtraResolver> logger, NamingOptions namingOptions, IDirectoryService directoryService)
|
||||
{
|
||||
_namingOptions = namingOptions;
|
||||
_trailerResolvers = new IItemResolver[] { new GenericVideoResolver<Trailer>(logger, namingOptions) };
|
||||
_videoResolvers = new IItemResolver[] { new GenericVideoResolver<Video>(logger, namingOptions) };
|
||||
_trailerResolvers = new IItemResolver[] { new GenericVideoResolver<Trailer>(logger, namingOptions, directoryService) };
|
||||
_videoResolvers = new IItemResolver[] { new GenericVideoResolver<Video>(logger, namingOptions, directoryService) };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using Emby.Naming.Common;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Emby.Server.Implementations.Library.Resolvers
|
||||
@@ -18,8 +19,9 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="namingOptions">The naming options.</param>
|
||||
public GenericVideoResolver(ILogger logger, NamingOptions namingOptions)
|
||||
: base(logger, namingOptions)
|
||||
/// <param name="directoryService">The directory service.</param>
|
||||
public GenericVideoResolver(ILogger logger, NamingOptions namingOptions, IDirectoryService directoryService)
|
||||
: base(logger, namingOptions, directoryService)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
||||
/// <param name="imageProcessor">The image processor.</param>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="namingOptions">The naming options.</param>
|
||||
public MovieResolver(IImageProcessor imageProcessor, ILogger<MovieResolver> logger, NamingOptions namingOptions)
|
||||
: base(logger, namingOptions)
|
||||
/// <param name="directoryService">The directory service.</param>
|
||||
public MovieResolver(IImageProcessor imageProcessor, ILogger<MovieResolver> logger, NamingOptions namingOptions, IDirectoryService directoryService)
|
||||
: base(logger, namingOptions, directoryService)
|
||||
{
|
||||
_imageProcessor = imageProcessor;
|
||||
}
|
||||
@@ -97,12 +98,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
||||
|
||||
if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
movie = FindMovie<MusicVideo>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
|
||||
movie = FindMovie<MusicVideo>(args, args.Path, args.Parent, files, DirectoryService, collectionType, false);
|
||||
}
|
||||
|
||||
if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
movie = FindMovie<Video>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
|
||||
movie = FindMovie<Video>(args, args.Path, args.Parent, files, DirectoryService, collectionType, false);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(collectionType))
|
||||
@@ -118,12 +119,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
||||
return null;
|
||||
}
|
||||
|
||||
movie = FindMovie<Movie>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
|
||||
movie = FindMovie<Movie>(args, args.Path, args.Parent, files, DirectoryService, collectionType, true);
|
||||
}
|
||||
|
||||
if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
movie = FindMovie<Movie>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
|
||||
movie = FindMovie<Movie>(args, args.Path, args.Parent, files, DirectoryService, collectionType, true);
|
||||
}
|
||||
|
||||
// ignore extras
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
#nullable disable
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@@ -12,15 +10,20 @@ using Jellyfin.Extensions;
|
||||
using MediaBrowser.Controller.Drawing;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Controller.Resolvers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace Emby.Server.Implementations.Library.Resolvers
|
||||
{
|
||||
/// <summary>
|
||||
/// Class PhotoResolver.
|
||||
/// </summary>
|
||||
public class PhotoResolver : ItemResolver<Photo>
|
||||
{
|
||||
private readonly IImageProcessor _imageProcessor;
|
||||
private readonly NamingOptions _namingOptions;
|
||||
private readonly IDirectoryService _directoryService;
|
||||
|
||||
private static readonly HashSet<string> _ignoreFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
@@ -35,10 +38,17 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
||||
"default"
|
||||
};
|
||||
|
||||
public PhotoResolver(IImageProcessor imageProcessor, NamingOptions namingOptions)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PhotoResolver"/> class.
|
||||
/// </summary>
|
||||
/// <param name="imageProcessor">The image processor.</param>
|
||||
/// <param name="namingOptions">The naming options.</param>
|
||||
/// <param name="directoryService">The directory service.</param>
|
||||
public PhotoResolver(IImageProcessor imageProcessor, NamingOptions namingOptions, IDirectoryService directoryService)
|
||||
{
|
||||
_imageProcessor = imageProcessor;
|
||||
_namingOptions = namingOptions;
|
||||
_directoryService = directoryService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -61,7 +71,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
|
||||
var filename = Path.GetFileNameWithoutExtension(args.Path);
|
||||
|
||||
// Make sure the image doesn't belong to a video file
|
||||
var files = args.DirectoryService.GetFiles(Path.GetDirectoryName(args.Path));
|
||||
var files = _directoryService.GetFiles(Path.GetDirectoryName(args.Path));
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using Emby.Naming.Common;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
using MediaBrowser.Model.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
@@ -20,8 +21,9 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
|
||||
/// </summary>
|
||||
/// <param name="logger">The logger.</param>
|
||||
/// <param name="namingOptions">The naming options.</param>
|
||||
public EpisodeResolver(ILogger<EpisodeResolver> logger, NamingOptions namingOptions)
|
||||
: base(logger, namingOptions)
|
||||
/// <param name="directoryService">The directory service.</param>
|
||||
public EpisodeResolver(ILogger<EpisodeResolver> logger, NamingOptions namingOptions, IDirectoryService directoryService)
|
||||
: base(logger, namingOptions, directoryService)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -111,10 +111,10 @@ namespace Emby.Server.Implementations.Library
|
||||
|
||||
if (query.IncludeExternalContent)
|
||||
{
|
||||
var channelResult = _channelManager.GetChannelsInternal(new ChannelQuery
|
||||
var channelResult = _channelManager.GetChannelsInternalAsync(new ChannelQuery
|
||||
{
|
||||
UserId = query.UserId
|
||||
});
|
||||
}).GetAwaiter().GetResult();
|
||||
|
||||
var channels = channelResult.Items;
|
||||
|
||||
|
||||
@@ -1312,20 +1312,19 @@ namespace Emby.Server.Implementations.LiveTv
|
||||
return 7;
|
||||
}
|
||||
|
||||
private QueryResult<BaseItem> GetEmbyRecordings(RecordingQuery query, DtoOptions dtoOptions, User user)
|
||||
private async Task<QueryResult<BaseItem>> GetEmbyRecordingsAsync(RecordingQuery query, DtoOptions dtoOptions, User user)
|
||||
{
|
||||
if (user is null)
|
||||
{
|
||||
return new QueryResult<BaseItem>();
|
||||
}
|
||||
|
||||
var folderIds = GetRecordingFolders(user, true)
|
||||
.Select(i => i.Id)
|
||||
.ToList();
|
||||
var folders = await GetRecordingFoldersAsync(user, true).ConfigureAwait(false);
|
||||
var folderIds = Array.ConvertAll(folders, x => x.Id);
|
||||
|
||||
var excludeItemTypes = new List<BaseItemKind>();
|
||||
|
||||
if (folderIds.Count == 0)
|
||||
if (folderIds.Length == 0)
|
||||
{
|
||||
return new QueryResult<BaseItem>();
|
||||
}
|
||||
@@ -1392,7 +1391,7 @@ namespace Emby.Server.Implementations.LiveTv
|
||||
{
|
||||
MediaTypes = new[] { MediaType.Video },
|
||||
Recursive = true,
|
||||
AncestorIds = folderIds.ToArray(),
|
||||
AncestorIds = folderIds,
|
||||
IsFolder = false,
|
||||
IsVirtualItem = false,
|
||||
Limit = limit,
|
||||
@@ -1528,7 +1527,7 @@ namespace Emby.Server.Implementations.LiveTv
|
||||
}
|
||||
}
|
||||
|
||||
public QueryResult<BaseItemDto> GetRecordings(RecordingQuery query, DtoOptions options)
|
||||
public async Task<QueryResult<BaseItemDto>> GetRecordingsAsync(RecordingQuery query, DtoOptions options)
|
||||
{
|
||||
var user = query.UserId.Equals(default)
|
||||
? null
|
||||
@@ -1536,7 +1535,7 @@ namespace Emby.Server.Implementations.LiveTv
|
||||
|
||||
RemoveFields(options);
|
||||
|
||||
var internalResult = GetEmbyRecordings(query, options, user);
|
||||
var internalResult = await GetEmbyRecordingsAsync(query, options, user).ConfigureAwait(false);
|
||||
|
||||
var returnArray = _dtoService.GetBaseItemDtos(internalResult.Items, options, user);
|
||||
|
||||
@@ -2379,12 +2378,11 @@ namespace Emby.Server.Implementations.LiveTv
|
||||
return _tvDtoService.GetInternalProgramId(externalId);
|
||||
}
|
||||
|
||||
public List<BaseItem> GetRecordingFolders(User user)
|
||||
{
|
||||
return GetRecordingFolders(user, false);
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public Task<BaseItem[]> GetRecordingFoldersAsync(User user)
|
||||
=> GetRecordingFoldersAsync(user, false);
|
||||
|
||||
private List<BaseItem> GetRecordingFolders(User user, bool refreshChannels)
|
||||
private async Task<BaseItem[]> GetRecordingFoldersAsync(User user, bool refreshChannels)
|
||||
{
|
||||
var folders = EmbyTV.EmbyTV.Current.GetRecordingFolders()
|
||||
.SelectMany(i => i.Locations)
|
||||
@@ -2396,14 +2394,16 @@ namespace Emby.Server.Implementations.LiveTv
|
||||
.OrderBy(i => i.SortName)
|
||||
.ToList();
|
||||
|
||||
folders.AddRange(_channelManager.GetChannelsInternal(new MediaBrowser.Model.Channels.ChannelQuery
|
||||
var channels = await _channelManager.GetChannelsInternalAsync(new MediaBrowser.Model.Channels.ChannelQuery
|
||||
{
|
||||
UserId = user.Id,
|
||||
IsRecordingsFolder = true,
|
||||
RefreshLatestChannelItems = refreshChannels
|
||||
}).Items);
|
||||
}).ConfigureAwait(false);
|
||||
|
||||
return folders.Cast<BaseItem>().ToList();
|
||||
folders.AddRange(channels.Items);
|
||||
|
||||
return folders.Cast<BaseItem>().ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,9 +122,13 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts
|
||||
var attributes = ParseExtInf(extInf, out string remaining);
|
||||
extInf = remaining;
|
||||
|
||||
if (attributes.TryGetValue("tvg-logo", out string value))
|
||||
if (attributes.TryGetValue("tvg-logo", out string tvgLogo))
|
||||
{
|
||||
channel.ImageUrl = value;
|
||||
channel.ImageUrl = tvgLogo;
|
||||
}
|
||||
else if (attributes.TryGetValue("logo", out string logo))
|
||||
{
|
||||
channel.ImageUrl = logo;
|
||||
}
|
||||
|
||||
if (attributes.TryGetValue("group-title", out string groupTitle))
|
||||
|
||||
@@ -107,5 +107,14 @@
|
||||
"TasksApplicationCategory": "Forrit",
|
||||
"TasksLibraryCategory": "Miðlasafn",
|
||||
"TasksMaintenanceCategory": "Viðhald",
|
||||
"Default": "Sjálfgefið"
|
||||
"Default": "Sjálfgefið",
|
||||
"TaskCleanActivityLog": "Hreinsa athafnaskrá",
|
||||
"TaskRefreshPeople": "Endurnýja fólk",
|
||||
"TaskDownloadMissingSubtitles": "Sækja texta sem vantar",
|
||||
"TaskOptimizeDatabase": "Fínstilla gagnagrunn",
|
||||
"Undefined": "Óskilgreint",
|
||||
"TaskCleanLogsDescription": "Eyðir færslu skrám sem eru meira en {0} gömul.",
|
||||
"TaskCleanLogs": "Hreinsa færslu skrá",
|
||||
"TaskDownloadMissingSubtitlesDescription": "Leitar á netinu að texta sem vantar miðað við uppsetningu lýsigagna.",
|
||||
"HearingImpaired": "Heyrnarskertur"
|
||||
}
|
||||
|
||||
@@ -184,10 +184,19 @@ namespace Emby.Server.Implementations.Localization
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<ParentalRating> GetParentalRatings()
|
||||
{
|
||||
var ratings = GetParentalRatingsDictionary().Values.ToList();
|
||||
// Use server default language for ratings
|
||||
// Fall back to empty list if there are no parental ratings for that language
|
||||
var ratings = GetParentalRatingsDictionary()?.Values.ToList()
|
||||
?? new List<ParentalRating>();
|
||||
|
||||
// Add common ratings to ensure them being available for selection.
|
||||
// Add common ratings to ensure them being available for selection
|
||||
// Based on the US rating system due to it being the main source of rating in the metadata providers
|
||||
// Unrated
|
||||
if (!ratings.Any(x => x.Value is null))
|
||||
{
|
||||
ratings.Add(new ParentalRating("Unrated", null));
|
||||
}
|
||||
|
||||
// Minimum rating possible
|
||||
if (!ratings.Any(x => x.Value == 0))
|
||||
{
|
||||
@@ -237,36 +246,26 @@ namespace Emby.Server.Implementations.Localization
|
||||
/// <summary>
|
||||
/// Gets the parental ratings dictionary.
|
||||
/// </summary>
|
||||
/// <param name="countryCode">The optional two letter ISO language string.</param>
|
||||
/// <returns><see cref="Dictionary{String, ParentalRating}" />.</returns>
|
||||
private Dictionary<string, ParentalRating> GetParentalRatingsDictionary()
|
||||
private Dictionary<string, ParentalRating>? GetParentalRatingsDictionary(string? countryCode = null)
|
||||
{
|
||||
var countryCode = _configurationManager.Configuration.MetadataCountryCode;
|
||||
|
||||
// Fall back to US ratings if no country code is specified or country code does not exist.
|
||||
// Fallback to server default if no country code is specified.
|
||||
if (string.IsNullOrEmpty(countryCode))
|
||||
{
|
||||
countryCode = "us";
|
||||
countryCode = _configurationManager.Configuration.MetadataCountryCode;
|
||||
}
|
||||
|
||||
return GetRatings(countryCode)
|
||||
?? GetRatings("us")
|
||||
?? throw new InvalidOperationException($"Invalid resource path: '{CountriesPath}'");
|
||||
}
|
||||
if (_allParentalRatings.TryGetValue(countryCode, out var countryValue))
|
||||
{
|
||||
return countryValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ratings for a country.
|
||||
/// </summary>
|
||||
/// <param name="countryCode">The country code.</param>
|
||||
/// <returns>The ratings.</returns>
|
||||
private Dictionary<string, ParentalRating>? GetRatings(string countryCode)
|
||||
{
|
||||
_allParentalRatings.TryGetValue(countryCode, out var countryValue);
|
||||
|
||||
return countryValue;
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int? GetRatingLevel(string rating)
|
||||
public int? GetRatingLevel(string rating, string? countryCode = null)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrEmpty(rating);
|
||||
|
||||
@@ -280,32 +279,51 @@ namespace Emby.Server.Implementations.Localization
|
||||
rating = rating.Replace("Rated :", string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
rating = rating.Replace("Rated ", string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
var ratingsDictionary = GetParentalRatingsDictionary();
|
||||
|
||||
if (ratingsDictionary.TryGetValue(rating, out ParentalRating? value))
|
||||
// Use rating system matching the language
|
||||
if (!string.IsNullOrEmpty(countryCode))
|
||||
{
|
||||
return value.Value;
|
||||
var ratingsDictionary = GetParentalRatingsDictionary(countryCode);
|
||||
if (ratingsDictionary is not null && ratingsDictionary.TryGetValue(rating, out ParentalRating? value))
|
||||
{
|
||||
return value.Value;
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't find anything check all ratings systems
|
||||
foreach (var dictionary in _allParentalRatings.Values)
|
||||
else
|
||||
{
|
||||
if (dictionary.TryGetValue(rating, out value))
|
||||
// Fall back to server default language for ratings check
|
||||
// If it has no ratings, use the US ratings
|
||||
var ratingsDictionary = GetParentalRatingsDictionary() ?? GetParentalRatingsDictionary("us");
|
||||
if (ratingsDictionary is not null && ratingsDictionary.TryGetValue(rating, out ParentalRating? value))
|
||||
{
|
||||
return value.Value;
|
||||
}
|
||||
}
|
||||
|
||||
// Try splitting by : to handle "Germany: FSK 18"
|
||||
// If we don't find anything, check all ratings systems
|
||||
foreach (var dictionary in _allParentalRatings.Values)
|
||||
{
|
||||
if (dictionary.TryGetValue(rating, out var value))
|
||||
{
|
||||
return value.Value;
|
||||
}
|
||||
}
|
||||
|
||||
// Try splitting by : to handle "Germany: FSK-18"
|
||||
if (rating.Contains(':', StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return GetRatingLevel(rating.AsSpan().RightPart(':').ToString());
|
||||
}
|
||||
|
||||
// Remove prefix country code to handle "DE-18"
|
||||
// Handle prefix country code to handle "DE-18"
|
||||
if (rating.Contains('-', StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return GetRatingLevel(rating.AsSpan().RightPart('-').ToString());
|
||||
var ratingSpan = rating.AsSpan();
|
||||
|
||||
// Extract culture from country prefix
|
||||
var culture = FindLanguageInfo(ratingSpan.LeftPart('-').ToString());
|
||||
|
||||
// Check rating system of culture
|
||||
return GetRatingLevel(ratingSpan.RightPart('-').ToString(), culture?.TwoLetterISOLanguageName);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user