aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations
diff options
context:
space:
mode:
Diffstat (limited to 'Emby.Server.Implementations')
-rw-r--r--Emby.Server.Implementations/ApplicationHost.cs2
-rw-r--r--Emby.Server.Implementations/Library/LibraryManager.cs58
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs25
-rw-r--r--Emby.Server.Implementations/Localization/Core/nl.json3
4 files changed, 77 insertions, 11 deletions
diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs
index b624a6d4f9..c81829688f 100644
--- a/Emby.Server.Implementations/ApplicationHost.cs
+++ b/Emby.Server.Implementations/ApplicationHost.cs
@@ -14,6 +14,7 @@ using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Emby.Naming.Common;
+using Emby.Naming.Video;
using Emby.Photos;
using Emby.Server.Implementations.Chapters;
using Emby.Server.Implementations.Collections;
@@ -540,6 +541,7 @@ namespace Emby.Server.Implementations
serviceCollection.AddTransient(provider => new Lazy<IUserViewManager>(provider.GetRequiredService<IUserViewManager>));
serviceCollection.AddSingleton<ILibraryManager, LibraryManager>();
serviceCollection.AddSingleton<NamingOptions>();
+ serviceCollection.AddSingleton<VideoListResolver>();
serviceCollection.AddSingleton<IMusicManager, MusicManager>();
diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs
index 11f1496086..30ff1bd333 100644
--- a/Emby.Server.Implementations/Library/LibraryManager.cs
+++ b/Emby.Server.Implementations/Library/LibraryManager.cs
@@ -13,6 +13,7 @@ using System.Threading.Tasks;
using BitFaster.Caching.Lru;
using Emby.Naming.Common;
using Emby.Naming.TV;
+using Emby.Naming.Video;
using Emby.Server.Implementations.Library.Resolvers;
using Emby.Server.Implementations.Library.Validators;
using Emby.Server.Implementations.Playlists;
@@ -87,6 +88,7 @@ namespace Emby.Server.Implementations.Library
private readonly IPathManager _pathManager;
private readonly FastConcurrentLru<Guid, BaseItem> _cache;
private readonly DotIgnoreIgnoreRule _dotIgnoreIgnoreRule;
+ private readonly IMediaStreamRepository _mediaStreamRepository;
/// <summary>
/// The _root folder sync lock.
@@ -129,6 +131,7 @@ namespace Emby.Server.Implementations.Library
/// <param name="peopleRepository">The people repository.</param>
/// <param name="pathManager">The path manager.</param>
/// <param name="dotIgnoreIgnoreRule">The .ignore rule handler.</param>
+ /// <param name="mediaStreamRepository">The media stream repository.</param>
public LibraryManager(
IServerApplicationHost appHost,
ILoggerFactory loggerFactory,
@@ -151,7 +154,8 @@ namespace Emby.Server.Implementations.Library
IDirectoryService directoryService,
IPeopleRepository peopleRepository,
IPathManager pathManager,
- DotIgnoreIgnoreRule dotIgnoreIgnoreRule)
+ DotIgnoreIgnoreRule dotIgnoreIgnoreRule,
+ IMediaStreamRepository mediaStreamRepository)
{
_appHost = appHost;
_logger = loggerFactory.CreateLogger<LibraryManager>();
@@ -181,6 +185,8 @@ namespace Emby.Server.Implementations.Library
_configurationManager.ConfigurationUpdated += ConfigurationUpdated;
+ _mediaStreamRepository = mediaStreamRepository;
+
RecordConfigurationValues(_configurationManager.Configuration);
}
@@ -787,6 +793,42 @@ namespace Emby.Server.Implementations.Library
CollectionType? collectionType = null)
=> ResolvePath(fileInfo, directoryService ?? new DirectoryService(_fileSystem), null, parent, collectionType);
+ private void SetAdditionalPartsFromStack(Video altVideo, string path)
+ {
+ if (altVideo.AdditionalParts is { Length: > 0 })
+ {
+ return;
+ }
+
+ var directory = Path.GetDirectoryName(path);
+ if (string.IsNullOrEmpty(directory))
+ {
+ return;
+ }
+
+ IEnumerable<FileSystemMetadata> siblings;
+ try
+ {
+ siblings = _fileSystem.GetFiles(directory);
+ }
+ catch (Exception ex)
+ {
+ _logger.LogWarning(ex, "Failed to enumerate siblings to detect stack for {Path}", path);
+ return;
+ }
+
+ var stacks = StackResolver.Resolve(siblings, _namingOptions);
+ foreach (var stack in stacks)
+ {
+ if (stack.Files.Count > 1
+ && string.Equals(stack.Files[0], path, StringComparison.OrdinalIgnoreCase))
+ {
+ altVideo.AdditionalParts = stack.Files.Skip(1).ToArray();
+ return;
+ }
+ }
+ }
+
/// <inheritdoc />
public Video? ResolveAlternateVersion(string path, Type expectedVideoType, Folder? parent, CollectionType? collectionType)
{
@@ -2307,6 +2349,10 @@ namespace Emby.Server.Implementations.Library
{
altVideo.OwnerId = video.Id;
altVideo.SetPrimaryVersionId(video.Id);
+ // ResolveAlternateVersion only sees the alternate's primary file.
+ // If the alternate is itself a stack (e.g. 1080p part1 + part2),
+ // detect its parts from sibling files so its AdditionalParts persist.
+ SetAdditionalPartsFromStack(altVideo, path);
allItems.Add(altVideo);
}
}
@@ -2510,6 +2556,10 @@ namespace Emby.Server.Implementations.Library
{
altVideo.OwnerId = video.Id;
altVideo.SetPrimaryVersionId(video.Id);
+ // ResolveAlternateVersion only sees the alternate's primary file.
+ // If the alternate is itself a stack (e.g. 1080p part1 + part2),
+ // detect its parts from sibling files so its AdditionalParts persist.
+ SetAdditionalPartsFromStack(altVideo, path);
allItems.Add(altVideo);
}
}
@@ -3800,5 +3850,11 @@ namespace Emby.Server.Implementations.Library
SetTopParentOrAncestorIds(query);
return _itemRepository.GetQueryFiltersLegacy(query);
}
+
+ /// <inheritdoc />
+ public IReadOnlyList<string> GetMediaStreamLanguages(MediaStreamType mediaStreamType)
+ {
+ return _mediaStreamRepository.GetMediaStreamLanguages(mediaStreamType);
+ }
}
}
diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index 98e8f5350b..68b66ab7f5 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
@@ -28,15 +28,16 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
public partial class MovieResolver : BaseVideoResolver<Video>, IMultiItemResolver
{
private readonly IImageProcessor _imageProcessor;
+ private readonly VideoListResolver _videoListResolver;
- private static readonly CollectionType[] _validCollectionTypes = new[]
- {
+ private static readonly CollectionType[] _validCollectionTypes =
+ [
CollectionType.movies,
CollectionType.homevideos,
CollectionType.musicvideos,
CollectionType.tvshows,
CollectionType.photos
- };
+ ];
/// <summary>
/// Initializes a new instance of the <see cref="MovieResolver"/> class.
@@ -45,10 +46,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
/// <param name="logger">The logger.</param>
/// <param name="namingOptions">The naming options.</param>
/// <param name="directoryService">The directory service.</param>
- public MovieResolver(IImageProcessor imageProcessor, ILogger<MovieResolver> logger, NamingOptions namingOptions, IDirectoryService directoryService)
+ /// <param name="videoListResolver">The video list resolver.</param>
+ public MovieResolver(IImageProcessor imageProcessor, ILogger<MovieResolver> logger, NamingOptions namingOptions, IDirectoryService directoryService, VideoListResolver videoListResolver)
: base(logger, namingOptions, directoryService)
{
_imageProcessor = imageProcessor;
+ _videoListResolver = videoListResolver;
}
/// <summary>
@@ -228,7 +231,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
if (collectionType == CollectionType.tvshows)
{
- return ResolveVideos<Episode>(parent, files, false, collectionType, true);
+ return ResolveVideos<Episode>(parent, files, true, collectionType, true);
}
return null;
@@ -274,7 +277,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
.Where(f => f is not null)
.ToList();
- var resolverResult = VideoListResolver.Resolve(videoInfos, NamingOptions, supportMultiEditions, parseName, parent.ContainingFolderPath);
+ var resolverResult = _videoListResolver.Resolve(videoInfos, supportMultiEditions, parseName, parent.ContainingFolderPath, collectionType);
var result = new MultiItemResolverResult
{
@@ -302,7 +305,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
ProductionYear = video.Year,
Name = parseName ? video.Name : firstVideo.Name,
AdditionalParts = additionalParts,
- LocalAlternateVersions = video.AlternateVersions.Select(i => i.Path).ToArray()
+ LocalAlternateVersions = video.AlternateVersions.Select(av => av.Files[0].Path).ToArray()
};
SetVideoType(videoItem, firstVideo);
@@ -331,9 +334,13 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
for (var j = 0; j < current.AlternateVersions.Count; j++)
{
- if (ContainsFile(current.AlternateVersions[j], file))
+ var alternate = current.AlternateVersions[j];
+ for (var k = 0; k < alternate.Files.Count; k++)
{
- return true;
+ if (ContainsFile(alternate.Files[k], file))
+ {
+ return true;
+ }
}
}
}
diff --git a/Emby.Server.Implementations/Localization/Core/nl.json b/Emby.Server.Implementations/Localization/Core/nl.json
index 363ae502bd..9aea3adc22 100644
--- a/Emby.Server.Implementations/Localization/Core/nl.json
+++ b/Emby.Server.Implementations/Localization/Core/nl.json
@@ -107,5 +107,6 @@
"CleanupUserDataTaskDescription": "Wist alle gebruikersgegevens (kijkstatus, favorieten, etc.) van media die al minstens 90 dagen niet meer aanwezig zijn.",
"CleanupUserDataTask": "Opruimtaak gebruikersdata",
"Genres": "Genres",
- "Original": "Oorspronkelijk"
+ "Original": "Oorspronkelijk",
+ "LyricDownloadFailureFromForItem": "Downloaden van liedteksten voor {1} van {0} mislukt"
}