mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-05-28 03:18:27 +01:00
Support stacked multi versions
This commit is contained in:
@@ -17,8 +17,8 @@ namespace Emby.Naming.Video
|
|||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
|
|
||||||
Files = Array.Empty<VideoFileInfo>();
|
Files = [];
|
||||||
AlternateVersions = Array.Empty<VideoFileInfo>();
|
AlternateVersions = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -40,10 +40,10 @@ namespace Emby.Naming.Video
|
|||||||
public IReadOnlyList<VideoFileInfo> Files { get; set; }
|
public IReadOnlyList<VideoFileInfo> Files { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the alternate versions.
|
/// Gets or sets the alternate versions. Each alternate may itself span multiple files.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>The alternate versions.</value>
|
/// <value>The alternate versions.</value>
|
||||||
public IReadOnlyList<VideoFileInfo> AlternateVersions { get; set; }
|
public IReadOnlyList<VideoInfo> AlternateVersions { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the extra type.
|
/// Gets or sets the extra type.
|
||||||
|
|||||||
@@ -296,10 +296,13 @@ namespace Emby.Naming.Video
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var primary = primaryOverride ?? videos[0];
|
// Prefer a stacked entry (more than one part) as primary
|
||||||
|
var primary = primaryOverride
|
||||||
|
?? videos.FirstOrDefault(v => v.Files.Count > 1)
|
||||||
|
?? videos[0];
|
||||||
videos.Remove(primary);
|
videos.Remove(primary);
|
||||||
|
|
||||||
primary.AlternateVersions = [.. videos.Select(x => x.Files[0])];
|
primary.AlternateVersions = videos;
|
||||||
|
|
||||||
if (nameOverride is not null)
|
if (nameOverride is not null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
|||||||
ProductionYear = video.Year,
|
ProductionYear = video.Year,
|
||||||
Name = parseName ? video.Name : firstVideo.Name,
|
Name = parseName ? video.Name : firstVideo.Name,
|
||||||
AdditionalParts = additionalParts,
|
AdditionalParts = additionalParts,
|
||||||
LocalAlternateVersions = video.AlternateVersions.Select(i => i.Path).ToArray()
|
LocalAlternateVersions = video.AlternateVersions.Select(av => av.Files[0].Path).ToArray()
|
||||||
};
|
};
|
||||||
|
|
||||||
SetVideoType(videoItem, firstVideo);
|
SetVideoType(videoItem, firstVideo);
|
||||||
@@ -334,9 +334,13 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
|||||||
|
|
||||||
for (var j = 0; j < current.AlternateVersions.Count; j++)
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using Emby.Naming.Common;
|
using Emby.Naming.Common;
|
||||||
using Emby.Naming.Video;
|
using Emby.Naming.Video;
|
||||||
using Jellyfin.Data.Enums;
|
using Jellyfin.Data.Enums;
|
||||||
|
using MediaBrowser.Model.Entities;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Jellyfin.Naming.Tests.Video
|
namespace Jellyfin.Naming.Tests.Video
|
||||||
@@ -197,12 +198,12 @@ namespace Jellyfin.Naming.Tests.Video
|
|||||||
Assert.Single(result);
|
Assert.Single(result);
|
||||||
Assert.Equal("/movies/Iron Man/Iron Man.mkv", result[0].Files[0].Path);
|
Assert.Equal("/movies/Iron Man/Iron Man.mkv", result[0].Files[0].Path);
|
||||||
Assert.Equal(6, result[0].AlternateVersions.Count);
|
Assert.Equal(6, result[0].AlternateVersions.Count);
|
||||||
Assert.Equal("/movies/Iron Man/Iron Man-720p.mkv", result[0].AlternateVersions[0].Path);
|
Assert.Equal("/movies/Iron Man/Iron Man-720p.mkv", result[0].AlternateVersions[0].Files[0].Path);
|
||||||
Assert.Equal("/movies/Iron Man/Iron Man-3d.mkv", result[0].AlternateVersions[1].Path);
|
Assert.Equal("/movies/Iron Man/Iron Man-3d.mkv", result[0].AlternateVersions[1].Files[0].Path);
|
||||||
Assert.Equal("/movies/Iron Man/Iron Man-3d-hsbs.mkv", result[0].AlternateVersions[2].Path);
|
Assert.Equal("/movies/Iron Man/Iron Man-3d-hsbs.mkv", result[0].AlternateVersions[2].Files[0].Path);
|
||||||
Assert.Equal("/movies/Iron Man/Iron Man-bluray.mkv", result[0].AlternateVersions[3].Path);
|
Assert.Equal("/movies/Iron Man/Iron Man-bluray.mkv", result[0].AlternateVersions[3].Files[0].Path);
|
||||||
Assert.Equal("/movies/Iron Man/Iron Man-test.mkv", result[0].AlternateVersions[4].Path);
|
Assert.Equal("/movies/Iron Man/Iron Man-test.mkv", result[0].AlternateVersions[4].Files[0].Path);
|
||||||
Assert.Equal("/movies/Iron Man/Iron Man[test].mkv", result[0].AlternateVersions[5].Path);
|
Assert.Equal("/movies/Iron Man/Iron Man[test].mkv", result[0].AlternateVersions[5].Files[0].Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -225,12 +226,12 @@ namespace Jellyfin.Naming.Tests.Video
|
|||||||
Assert.Single(result);
|
Assert.Single(result);
|
||||||
Assert.Equal("/movies/Iron Man/Iron Man.mkv", result[0].Files[0].Path);
|
Assert.Equal("/movies/Iron Man/Iron Man.mkv", result[0].Files[0].Path);
|
||||||
Assert.Equal(6, result[0].AlternateVersions.Count);
|
Assert.Equal(6, result[0].AlternateVersions.Count);
|
||||||
Assert.Equal("/movies/Iron Man/Iron Man - 720p.mkv", result[0].AlternateVersions[0].Path);
|
Assert.Equal("/movies/Iron Man/Iron Man - 720p.mkv", result[0].AlternateVersions[0].Files[0].Path);
|
||||||
Assert.Equal("/movies/Iron Man/Iron Man - 3d.mkv", result[0].AlternateVersions[1].Path);
|
Assert.Equal("/movies/Iron Man/Iron Man - 3d.mkv", result[0].AlternateVersions[1].Files[0].Path);
|
||||||
Assert.Equal("/movies/Iron Man/Iron Man - 3d-hsbs.mkv", result[0].AlternateVersions[2].Path);
|
Assert.Equal("/movies/Iron Man/Iron Man - 3d-hsbs.mkv", result[0].AlternateVersions[2].Files[0].Path);
|
||||||
Assert.Equal("/movies/Iron Man/Iron Man - bluray.mkv", result[0].AlternateVersions[3].Path);
|
Assert.Equal("/movies/Iron Man/Iron Man - bluray.mkv", result[0].AlternateVersions[3].Files[0].Path);
|
||||||
Assert.Equal("/movies/Iron Man/Iron Man - test.mkv", result[0].AlternateVersions[4].Path);
|
Assert.Equal("/movies/Iron Man/Iron Man - test.mkv", result[0].AlternateVersions[4].Files[0].Path);
|
||||||
Assert.Equal("/movies/Iron Man/Iron Man [test].mkv", result[0].AlternateVersions[5].Path);
|
Assert.Equal("/movies/Iron Man/Iron Man [test].mkv", result[0].AlternateVersions[5].Files[0].Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -269,9 +270,9 @@ namespace Jellyfin.Naming.Tests.Video
|
|||||||
Assert.Equal(6, result[0].AlternateVersions.Count);
|
Assert.Equal(6, result[0].AlternateVersions.Count);
|
||||||
|
|
||||||
// Verify 3D recognition is preserved on alternate versions
|
// Verify 3D recognition is preserved on alternate versions
|
||||||
var hsbs = result[0].AlternateVersions.First(v => v.Path.Contains("3d-hsbs", StringComparison.Ordinal));
|
var hsbs = result[0].AlternateVersions.First(v => v.Files[0].Path.Contains("3d-hsbs", StringComparison.Ordinal));
|
||||||
Assert.True(hsbs.Is3D);
|
Assert.True(hsbs.Files[0].Is3D);
|
||||||
Assert.Equal("hsbs", hsbs.Format3D);
|
Assert.Equal("hsbs", hsbs.Files[0].Format3D);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -346,11 +347,11 @@ namespace Jellyfin.Naming.Tests.Video
|
|||||||
Assert.Single(result);
|
Assert.Single(result);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016).mkv", result[0].Files[0].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016).mkv", result[0].Files[0].Path);
|
||||||
Assert.Equal(5, result[0].AlternateVersions.Count);
|
Assert.Equal(5, result[0].AlternateVersions.Count);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 2160p.mkv", result[0].AlternateVersions[0].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 2160p.mkv", result[0].AlternateVersions[0].Files[0].Path);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p.mkv", result[0].AlternateVersions[1].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p.mkv", result[0].AlternateVersions[1].Files[0].Path);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 720p.mkv", result[0].AlternateVersions[2].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 720p.mkv", result[0].AlternateVersions[2].Files[0].Path);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Directors Cut.mkv", result[0].AlternateVersions[3].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Directors Cut.mkv", result[0].AlternateVersions[3].Files[0].Path);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Theatrical Release.mkv", result[0].AlternateVersions[4].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Theatrical Release.mkv", result[0].AlternateVersions[4].Files[0].Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -378,17 +379,17 @@ namespace Jellyfin.Naming.Tests.Video
|
|||||||
Assert.Single(result);
|
Assert.Single(result);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016).mkv", result[0].Files[0].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016).mkv", result[0].Files[0].Path);
|
||||||
Assert.Equal(11, result[0].AlternateVersions.Count);
|
Assert.Equal(11, result[0].AlternateVersions.Count);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 2160p.mkv", result[0].AlternateVersions[0].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 2160p.mkv", result[0].AlternateVersions[0].Files[0].Path);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 2160p Remux.mkv", result[0].AlternateVersions[1].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 2160p Remux.mkv", result[0].AlternateVersions[1].Files[0].Path);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p.mkv", result[0].AlternateVersions[2].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p.mkv", result[0].AlternateVersions[2].Files[0].Path);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p Directors Cut.mkv", result[0].AlternateVersions[3].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p Directors Cut.mkv", result[0].AlternateVersions[3].Files[0].Path);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p High Bitrate.mkv", result[0].AlternateVersions[4].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p High Bitrate.mkv", result[0].AlternateVersions[4].Files[0].Path);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p Remux.mkv", result[0].AlternateVersions[5].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p Remux.mkv", result[0].AlternateVersions[5].Files[0].Path);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p Theatrical Release.mkv", result[0].AlternateVersions[6].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 1080p Theatrical Release.mkv", result[0].AlternateVersions[6].Files[0].Path);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 720p.mkv", result[0].AlternateVersions[7].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 720p.mkv", result[0].AlternateVersions[7].Files[0].Path);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 720p Directors Cut.mkv", result[0].AlternateVersions[8].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - 720p Directors Cut.mkv", result[0].AlternateVersions[8].Files[0].Path);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Directors Cut.mkv", result[0].AlternateVersions[9].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Directors Cut.mkv", result[0].AlternateVersions[9].Files[0].Path);
|
||||||
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Theatrical Release.mkv", result[0].AlternateVersions[10].Path);
|
Assert.Equal("/movies/X-Men Apocalypse (2016)/X-Men Apocalypse (2016) - Theatrical Release.mkv", result[0].AlternateVersions[10].Files[0].Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -482,7 +483,7 @@ namespace Jellyfin.Naming.Tests.Video
|
|||||||
Assert.Single(result[0].AlternateVersions);
|
Assert.Single(result[0].AlternateVersions);
|
||||||
// 1080p should be primary (higher resolution)
|
// 1080p should be primary (higher resolution)
|
||||||
Assert.Contains("1080p", result[0].Files[0].Path, StringComparison.Ordinal);
|
Assert.Contains("1080p", result[0].Files[0].Path, StringComparison.Ordinal);
|
||||||
Assert.Contains("720p", result[0].AlternateVersions[0].Path, StringComparison.Ordinal);
|
Assert.Contains("720p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -602,8 +603,8 @@ namespace Jellyfin.Naming.Tests.Video
|
|||||||
// Primary should be 2160p (highest resolution)
|
// Primary should be 2160p (highest resolution)
|
||||||
Assert.Contains("2160p", result[0].Files[0].Path, StringComparison.Ordinal);
|
Assert.Contains("2160p", result[0].Files[0].Path, StringComparison.Ordinal);
|
||||||
// Next should be 1080p, then 720p
|
// Next should be 1080p, then 720p
|
||||||
Assert.Contains("1080p", result[0].AlternateVersions[0].Path, StringComparison.Ordinal);
|
Assert.Contains("1080p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
|
||||||
Assert.Contains("720p", result[0].AlternateVersions[1].Path, StringComparison.Ordinal);
|
Assert.Contains("720p", result[0].AlternateVersions[1].Files[0].Path, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -681,7 +682,7 @@ namespace Jellyfin.Naming.Tests.Video
|
|||||||
Assert.Single(result);
|
Assert.Single(result);
|
||||||
Assert.Single(result[0].AlternateVersions);
|
Assert.Single(result[0].AlternateVersions);
|
||||||
Assert.Contains("1080p", result[0].Files[0].Path, StringComparison.Ordinal);
|
Assert.Contains("1080p", result[0].Files[0].Path, StringComparison.Ordinal);
|
||||||
Assert.Contains("720p", result[0].AlternateVersions[0].Path, StringComparison.Ordinal);
|
Assert.Contains("720p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -733,7 +734,7 @@ namespace Jellyfin.Naming.Tests.Video
|
|||||||
Assert.Single(result);
|
Assert.Single(result);
|
||||||
Assert.Single(result[0].AlternateVersions);
|
Assert.Single(result[0].AlternateVersions);
|
||||||
Assert.Contains("1080p", result[0].Files[0].Path, StringComparison.Ordinal);
|
Assert.Contains("1080p", result[0].Files[0].Path, StringComparison.Ordinal);
|
||||||
Assert.Contains("720p", result[0].AlternateVersions[0].Path, StringComparison.Ordinal);
|
Assert.Contains("720p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -774,7 +775,7 @@ namespace Jellyfin.Naming.Tests.Video
|
|||||||
Assert.Single(result);
|
Assert.Single(result);
|
||||||
Assert.Equal(2, result[0].Files.Count);
|
Assert.Equal(2, result[0].Files.Count);
|
||||||
Assert.Single(result[0].AlternateVersions);
|
Assert.Single(result[0].AlternateVersions);
|
||||||
Assert.Contains("720p", result[0].AlternateVersions[0].Path, StringComparison.Ordinal);
|
Assert.Contains("720p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -795,7 +796,7 @@ namespace Jellyfin.Naming.Tests.Video
|
|||||||
Assert.Single(result);
|
Assert.Single(result);
|
||||||
Assert.Equal(2, result[0].Files.Count);
|
Assert.Equal(2, result[0].Files.Count);
|
||||||
Assert.Single(result[0].AlternateVersions);
|
Assert.Single(result[0].AlternateVersions);
|
||||||
Assert.Contains("720p", result[0].AlternateVersions[0].Path, StringComparison.Ordinal);
|
Assert.Contains("720p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -816,7 +817,7 @@ namespace Jellyfin.Naming.Tests.Video
|
|||||||
Assert.Single(result);
|
Assert.Single(result);
|
||||||
Assert.Equal(2, result[0].Files.Count);
|
Assert.Equal(2, result[0].Files.Count);
|
||||||
Assert.Single(result[0].AlternateVersions);
|
Assert.Single(result[0].AlternateVersions);
|
||||||
Assert.Contains("720p", result[0].AlternateVersions[0].Path, StringComparison.Ordinal);
|
Assert.Contains("720p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -838,7 +839,7 @@ namespace Jellyfin.Naming.Tests.Video
|
|||||||
// Primary should be the stacked 1080p version with 2 files
|
// Primary should be the stacked 1080p version with 2 files
|
||||||
Assert.Equal(2, result[0].Files.Count);
|
Assert.Equal(2, result[0].Files.Count);
|
||||||
Assert.Single(result[0].AlternateVersions);
|
Assert.Single(result[0].AlternateVersions);
|
||||||
Assert.Contains("720p", result[0].AlternateVersions[0].Path, StringComparison.Ordinal);
|
Assert.Contains("720p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -860,7 +861,7 @@ namespace Jellyfin.Naming.Tests.Video
|
|||||||
// Primary should be the stacked 1080p version with 2 files
|
// Primary should be the stacked 1080p version with 2 files
|
||||||
Assert.Equal(2, result[0].Files.Count);
|
Assert.Equal(2, result[0].Files.Count);
|
||||||
Assert.Single(result[0].AlternateVersions);
|
Assert.Single(result[0].AlternateVersions);
|
||||||
Assert.Contains("720p", result[0].AlternateVersions[0].Path, StringComparison.Ordinal);
|
Assert.Contains("720p", result[0].AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -893,6 +894,88 @@ namespace Jellyfin.Naming.Tests.Video
|
|||||||
Assert.Empty(e02!.AlternateVersions);
|
Assert.Empty(e02!.AlternateVersions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestMultiVersionEpisodePartStackAlongsideSingleFileResolutions()
|
||||||
|
{
|
||||||
|
// A part-stacked episode (3 parts, no resolution suffix) alongside single-file 720p and 1080p versions.
|
||||||
|
// The multi-part stack is preferred as primary.
|
||||||
|
var files = new[]
|
||||||
|
{
|
||||||
|
"/TV/Show/Season 1/S01E01 - 720p.mkv",
|
||||||
|
"/TV/Show/Season 1/S01E01 - 1080p.mkv",
|
||||||
|
"/TV/Show/Season 1/S01E01 - Part 1.mkv",
|
||||||
|
"/TV/Show/Season 1/S01E01 - Part 2.mkv",
|
||||||
|
"/TV/Show/Season 1/S01E01 - Part 3.mkv"
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = _videoListResolver.Resolve(
|
||||||
|
files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
|
||||||
|
collectionType: CollectionType.tvshows).ToList();
|
||||||
|
|
||||||
|
Assert.Single(result);
|
||||||
|
Assert.Equal(3, result[0].Files.Count);
|
||||||
|
Assert.All(result[0].Files, f => Assert.Contains("Part", f.Path, StringComparison.Ordinal));
|
||||||
|
Assert.Equal(2, result[0].AlternateVersions.Count);
|
||||||
|
Assert.Contains(result[0].AlternateVersions, f => f.Files[0].Path.Contains("1080p", StringComparison.Ordinal));
|
||||||
|
Assert.Contains(result[0].AlternateVersions, f => f.Files[0].Path.Contains("720p", StringComparison.Ordinal));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestMultiVersionEpisodeTwoPartStacks()
|
||||||
|
{
|
||||||
|
// Two part-suffixed stacks of the same episode at different resolutions.
|
||||||
|
// The 1080p stack is primary, the 720p stack is preserved as a multi-file alternate.
|
||||||
|
var files = new[]
|
||||||
|
{
|
||||||
|
"/TV/Show/Season 1/Show - S01E01 - 1080p - part1.mkv",
|
||||||
|
"/TV/Show/Season 1/Show - S01E01 - 1080p - part2.mkv",
|
||||||
|
"/TV/Show/Season 1/Show - S01E01 - 720p - part1.mkv",
|
||||||
|
"/TV/Show/Season 1/Show - S01E01 - 720p - part2.mkv"
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = _videoListResolver.Resolve(
|
||||||
|
files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
|
||||||
|
collectionType: CollectionType.tvshows).ToList();
|
||||||
|
|
||||||
|
Assert.Single(result);
|
||||||
|
Assert.Equal(2, result[0].Files.Count);
|
||||||
|
Assert.Contains("1080p", result[0].Files[0].Path, StringComparison.Ordinal);
|
||||||
|
|
||||||
|
Assert.Single(result[0].AlternateVersions);
|
||||||
|
var alt = result[0].AlternateVersions[0];
|
||||||
|
Assert.Equal(2, alt.Files.Count);
|
||||||
|
Assert.All(alt.Files, f => Assert.Contains("720p", f.Path, StringComparison.Ordinal));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestMultiVersionEpisodePartStackWithTrailer()
|
||||||
|
{
|
||||||
|
// A part-stacked multi-version episode alongside a trailer must not pull the trailer into the version group
|
||||||
|
var files = new[]
|
||||||
|
{
|
||||||
|
"/TV/Show/Season 1/Show - S01E01 - 1080p part1.mkv",
|
||||||
|
"/TV/Show/Season 1/Show - S01E01 - 1080p part2.mkv",
|
||||||
|
"/TV/Show/Season 1/Show - S01E01 - 720p.mkv",
|
||||||
|
"/TV/Show/Season 1/Show - S01E01-trailer.mp4"
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = _videoListResolver.Resolve(
|
||||||
|
files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
|
||||||
|
collectionType: CollectionType.tvshows).ToList();
|
||||||
|
|
||||||
|
Assert.Equal(2, result.Count);
|
||||||
|
|
||||||
|
var episode = result.FirstOrDefault(r => r.ExtraType is null);
|
||||||
|
Assert.NotNull(episode);
|
||||||
|
Assert.Equal(2, episode!.Files.Count);
|
||||||
|
Assert.Single(episode.AlternateVersions);
|
||||||
|
Assert.Contains("720p", episode.AlternateVersions[0].Files[0].Path, StringComparison.Ordinal);
|
||||||
|
|
||||||
|
var trailer = result.FirstOrDefault(r => r.ExtraType is not null);
|
||||||
|
Assert.NotNull(trailer);
|
||||||
|
Assert.Equal(ExtraType.Trailer, trailer!.ExtraType);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestMovieStackingWithPartNaming()
|
public void TestMovieStackingWithPartNaming()
|
||||||
{
|
{
|
||||||
@@ -981,6 +1064,31 @@ namespace Jellyfin.Naming.Tests.Video
|
|||||||
Assert.Single(result[0].AlternateVersions);
|
Assert.Single(result[0].AlternateVersions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void TestMovieMultiVersionWithStackedAlternate()
|
||||||
|
{
|
||||||
|
// Movie folder where the folder-named file is the primary (single file via primaryOverride)
|
||||||
|
// and an alternate version is itself a stack. The stacked alternate must keep all its files.
|
||||||
|
var files = new[]
|
||||||
|
{
|
||||||
|
"/movies/Inception (2010)/Inception (2010).mkv",
|
||||||
|
"/movies/Inception (2010)/Inception (2010) - 4k part1.mkv",
|
||||||
|
"/movies/Inception (2010)/Inception (2010) - 4k part2.mkv"
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = _videoListResolver.Resolve(
|
||||||
|
files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList()).ToList();
|
||||||
|
|
||||||
|
Assert.Single(result);
|
||||||
|
Assert.Single(result[0].Files);
|
||||||
|
Assert.Equal("/movies/Inception (2010)/Inception (2010).mkv", result[0].Files[0].Path);
|
||||||
|
|
||||||
|
Assert.Single(result[0].AlternateVersions);
|
||||||
|
var stackedAlternate = result[0].AlternateVersions[0];
|
||||||
|
Assert.Equal(2, stackedAlternate.Files.Count);
|
||||||
|
Assert.All(stackedAlternate.Files, f => Assert.Contains("4k part", f.Path, StringComparison.Ordinal));
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void TestEpisodeStackingWithHyphenNoSpaces()
|
public void TestEpisodeStackingWithHyphenNoSpaces()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user