mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-05-23 00:57:02 +01:00
Merge pull request #16828 from Shadowghost/episode-multiple-versions
Implement multiple versions for episodes.
This commit is contained in:
@@ -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>();
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -787,6 +788,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 +2344,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 +2551,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user