mirror of https://github.com/jellyfin/jellyfin.git
Compare commits
12 Commits
4f1bf3f839
...
f758431f47
Author | SHA1 | Date |
---|---|---|
SenorSmartyPants | f758431f47 | |
renovate[bot] | 5612cb8178 | |
renovate[bot] | ccd06bc547 | |
Bond-009 | d29b85a134 | |
SenorSmartyPants | a726629d94 | |
SenorSmartyPants | d53a61cc48 | |
SenorSmartyPants | 180e720d17 | |
SenorSmartyPants | 881f1b7b40 | |
SenorSmartyPants | aa4b7c6547 | |
SenorSmartyPants | bc93f34ffa | |
SenorSmartyPants | bf9c528593 | |
SenorSmartyPants | 0569017b79 |
|
@ -20,7 +20,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.0
|
||||
with:
|
||||
|
|
|
@ -14,7 +14,7 @@ jobs:
|
|||
permissions: read-all
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
|
@ -39,7 +39,7 @@ jobs:
|
|||
permissions: read-all
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
|
@ -78,12 +78,12 @@ jobs:
|
|||
- openapi-base
|
||||
steps:
|
||||
- name: Download openapi-head
|
||||
uses: actions/download-artifact@9c19ed7fe5d278cd354c7dfd5d3b88589c7e2395 # v4.1.6
|
||||
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
|
||||
with:
|
||||
name: openapi-head
|
||||
path: openapi-head
|
||||
- name: Download openapi-base
|
||||
uses: actions/download-artifact@9c19ed7fe5d278cd354c7dfd5d3b88589c7e2395 # v4.1.6
|
||||
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
|
||||
with:
|
||||
name: openapi-base
|
||||
path: openapi-base
|
||||
|
@ -152,7 +152,7 @@ jobs:
|
|||
run: |-
|
||||
echo "JELLYFIN_VERSION=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV
|
||||
- name: Download openapi-head
|
||||
uses: actions/download-artifact@9c19ed7fe5d278cd354c7dfd5d3b88589c7e2395 # v4.1.6
|
||||
uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7
|
||||
with:
|
||||
name: openapi-head
|
||||
path: openapi-head
|
||||
|
|
|
@ -19,7 +19,7 @@ jobs:
|
|||
|
||||
runs-on: "${{ matrix.os }}"
|
||||
steps:
|
||||
- uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
|
||||
- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
|
||||
- uses: actions/setup-dotnet@4d6c8fcf3c8f7a60068d26b594648e99df24cee3 # v4.0.0
|
||||
with:
|
||||
|
|
|
@ -24,7 +24,7 @@ jobs:
|
|||
reactions: '+1'
|
||||
|
||||
- name: Checkout the latest code
|
||||
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
with:
|
||||
token: ${{ secrets.JF_BOT_TOKEN }}
|
||||
fetch-depth: 0
|
||||
|
@ -51,7 +51,7 @@ jobs:
|
|||
reactions: eyes
|
||||
|
||||
- name: Checkout the latest code
|
||||
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
with:
|
||||
token: ${{ secrets.JF_BOT_TOKEN }}
|
||||
fetch-depth: 0
|
||||
|
@ -128,7 +128,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: pull in script
|
||||
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
with:
|
||||
repository: jellyfin/jellyfin-triage-script
|
||||
- name: install python
|
||||
|
|
|
@ -10,7 +10,7 @@ jobs:
|
|||
issues: write
|
||||
steps:
|
||||
- name: pull in script
|
||||
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
with:
|
||||
repository: jellyfin/jellyfin-triage-script
|
||||
- name: install python
|
||||
|
|
|
@ -33,7 +33,7 @@ jobs:
|
|||
yq-version: v4.9.8
|
||||
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
with:
|
||||
ref: ${{ env.TAG_BRANCH }}
|
||||
|
||||
|
@ -66,7 +66,7 @@ jobs:
|
|||
NEXT_VERSION: ${{ github.event.inputs.NEXT_VERSION }}
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@1d96c772d19495a3b5c517cd2bc0cb401ea0529f # v4.1.3
|
||||
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||
with:
|
||||
ref: ${{ env.TAG_BRANCH }}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<PackageVersion Include="BlurHashSharp" Version="1.3.2" />
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
|
||||
<PackageVersion Include="Diacritics" Version="3.3.27" />
|
||||
<PackageVersion Include="Diacritics" Version="3.3.29" />
|
||||
<PackageVersion Include="DiscUtils.Udf" Version="0.16.13" />
|
||||
<PackageVersion Include="DotNet.Glob" Version="3.1.3" />
|
||||
<PackageVersion Include="EFCoreSecondLevelCacheInterceptor" Version="4.4.3" />
|
||||
|
|
|
@ -44,11 +44,12 @@ using MediaBrowser.Model.Library;
|
|||
using MediaBrowser.Model.Querying;
|
||||
using MediaBrowser.Model.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using TMDbLib.Objects.Authentication;
|
||||
using Episode = MediaBrowser.Controller.Entities.TV.Episode;
|
||||
using EpisodeInfo = Emby.Naming.TV.EpisodeInfo;
|
||||
using Genre = MediaBrowser.Controller.Entities.Genre;
|
||||
using Person = MediaBrowser.Controller.Entities.Person;
|
||||
using Season = MediaBrowser.Controller.Entities.TV.Season;
|
||||
using Series = MediaBrowser.Controller.Entities.TV.Series;
|
||||
using VideoResolver = Emby.Naming.Video.VideoResolver;
|
||||
|
||||
namespace Emby.Server.Implementations.Library
|
||||
|
@ -1612,14 +1613,18 @@ namespace Emby.Server.Implementations.Library
|
|||
/// <returns>IEnumerable{System.String}.</returns>
|
||||
public async Task<IEnumerable<Video>> GetIntros(BaseItem item, User user)
|
||||
{
|
||||
if (IntroProviders.Length == 0)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
var tasks = IntroProviders
|
||||
.Take(1)
|
||||
.Select(i => GetIntros(i, item, user));
|
||||
|
||||
var items = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
return items
|
||||
.SelectMany(i => i.ToArray())
|
||||
.SelectMany(i => i)
|
||||
.Select(ResolveIntro)
|
||||
.Where(i => i is not null)!; // null values got filtered out
|
||||
}
|
||||
|
@ -2651,11 +2656,12 @@ namespace Emby.Server.Implementations.Library
|
|||
yield break;
|
||||
}
|
||||
|
||||
var resolver = new EpisodeResolver(_namingOptions);
|
||||
var count = fileSystemChildren.Count;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var current = fileSystemChildren[i];
|
||||
if (current.IsDirectory && _namingOptions.AllExtrasTypesFolderNames.ContainsKey(current.Name))
|
||||
if (!owner.IsInMixedFolder && current.IsDirectory && _namingOptions.AllExtrasTypesFolderNames.ContainsKey(current.Name))
|
||||
{
|
||||
var filesInSubFolder = _fileSystem.GetFiles(current.FullName, null, false, false);
|
||||
foreach (var file in filesInSubFolder)
|
||||
|
@ -2674,10 +2680,61 @@ namespace Emby.Server.Implementations.Library
|
|||
}
|
||||
else if (!current.IsDirectory && _extraResolver.TryGetExtraTypeForOwner(current.FullName, ownerVideoInfo, out var extraType))
|
||||
{
|
||||
var extra = GetExtra(current, extraType.Value);
|
||||
if (extra is not null)
|
||||
// if owner is dir, don't own episode extras
|
||||
// test if extra filename is formatted like an episode
|
||||
int? dashIndex = current.Name?.LastIndexOf('-');
|
||||
string prefix = null;
|
||||
if (dashIndex is int dashIndexValue)
|
||||
{
|
||||
yield return extra;
|
||||
if (dashIndexValue >= 0)
|
||||
{
|
||||
prefix = current.Name.Substring(0, dashIndexValue); // possible episode name
|
||||
prefix = ParseName(prefix).Name; // clean name - remove all things in brackets etc
|
||||
string path = current.FullName;
|
||||
path = string.Concat(path.AsSpan(0, path.LastIndexOf('-')), current.Extension);
|
||||
var episodeInfo = resolver.Resolve(path, false);
|
||||
|
||||
string seriesName = null;
|
||||
if (owner is Series series)
|
||||
{
|
||||
seriesName = series.Name;
|
||||
}
|
||||
|
||||
if (owner is Season season)
|
||||
{
|
||||
seriesName = season.SeriesName;
|
||||
}
|
||||
|
||||
if (seriesName is not null && episodeInfo?.SeriesName is not null)
|
||||
{
|
||||
// trim series names like episodepathparser does
|
||||
seriesName = seriesName
|
||||
.Trim()
|
||||
.Trim('_', '.', '-')
|
||||
.Trim();
|
||||
|
||||
var episodeInfoSeriesName = episodeInfo.SeriesName
|
||||
.Trim()
|
||||
.Trim('_', '.', '-')
|
||||
.Trim();
|
||||
|
||||
if (seriesName.Equals(episodeInfoSeriesName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// don't attach episode extras to series or season
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if owner is Episode, only suffix type matches will be allowed, episode file cleaned name must match
|
||||
if (owner is not Episode || (prefix is not null && prefix.Equals(ownerVideoInfo.Name, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
var extra = GetExtra(current, extraType.Value);
|
||||
if (extra is not null)
|
||||
{
|
||||
yield return extra;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -274,7 +274,7 @@ namespace Emby.Server.Implementations.Library
|
|||
var tasks = _providers.Select(i => GetDynamicMediaSources(item, i, cancellationToken));
|
||||
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
return results.SelectMany(i => i.ToList());
|
||||
return results.SelectMany(i => i);
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<MediaSourceInfo>> GetDynamicMediaSources(BaseItem item, IMediaSourceProvider provider, CancellationToken cancellationToken)
|
||||
|
|
|
@ -281,8 +281,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
|||
ExtraFiles = leftOver
|
||||
};
|
||||
|
||||
var isInMixedFolder = resolverResult.Count > 1 || parent?.IsTopParent == true;
|
||||
|
||||
foreach (var video in resolverResult)
|
||||
{
|
||||
var firstVideo = video.Files[0];
|
||||
|
@ -298,7 +296,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
|||
var videoItem = new T
|
||||
{
|
||||
Path = path,
|
||||
IsInMixedFolder = isInMixedFolder,
|
||||
ProductionYear = video.Year,
|
||||
Name = parseName ? video.Name : firstVideo.Name,
|
||||
AdditionalParts = additionalParts,
|
||||
|
@ -313,6 +310,13 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
|
|||
|
||||
result.ExtraFiles.AddRange(files.Where(i => !ContainsFile(resolverResult, i)));
|
||||
|
||||
// calculate if in mixed folder after extra files have been removed from count
|
||||
var isInMixedFolder = result.Items.Count > 1 || parent?.IsTopParent == true;
|
||||
foreach (var item in result.Items)
|
||||
{
|
||||
item.IsInMixedFolder = isInMixedFolder;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ using MediaBrowser.Controller.Channels;
|
|||
using MediaBrowser.Controller.Configuration;
|
||||
using MediaBrowser.Controller.Dto;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Entities.TV;
|
||||
using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Controller.Persistence;
|
||||
using MediaBrowser.Controller.Providers;
|
||||
|
@ -1338,7 +1339,7 @@ namespace MediaBrowser.Controller.Entities
|
|||
/// <returns><c>true</c> if any items have changed, else <c>false</c>.</returns>
|
||||
protected virtual async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, IReadOnlyList<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!IsFileProtocol || !SupportsOwnedItems || IsInMixedFolder || this is ICollectionFolder or UserRootFolder or AggregateFolder || this.GetType() == typeof(Folder))
|
||||
if (!IsFileProtocol || !SupportsOwnedItems || (IsInMixedFolder && this is not Episode) || this is ICollectionFolder or UserRootFolder or AggregateFolder || this.GetType() == typeof(Folder))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
|||
public int? IndexNumberEnd { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
protected override bool SupportsOwnedItems => IsStacked || MediaSourceCount > 1;
|
||||
protected override bool SupportsOwnedItems => true;
|
||||
|
||||
[JsonIgnore]
|
||||
public override bool SupportsInheritedParentImages => true;
|
||||
|
|
|
@ -286,7 +286,7 @@ namespace MediaBrowser.Providers.Manager
|
|||
|
||||
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
|
||||
|
||||
return results.SelectMany(i => i.ToList());
|
||||
return results.SelectMany(i => i);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -331,4 +331,216 @@ public class FindExtrasTests
|
|||
Assert.Equal("/series/Dexter/trailer.mkv", extras[0].Path);
|
||||
Assert.Equal("/series/Dexter/trailers/trailer2.mkv", extras[1].Path);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindExtras_SeriesWithExtras_FindsCorrectExtras()
|
||||
{
|
||||
var owner = new Series { Name = "Dexter", Path = "/series/Dexter" };
|
||||
var paths = new List<string>
|
||||
{
|
||||
"/series/Dexter/Season 1/Dexter - S01E01.mkv",
|
||||
"/series/Dexter/Season 1/Dexter - S01E01-deleted.mkv",
|
||||
"/series/Dexter/Season 1/Dexter - S01E01 [WEBDL-1080p AVC][AAC 2.0][YouTube]-deleted.mkv",
|
||||
"/series/Dexter/Season 1/Dexter - S01E02 - Second Epi.mkv",
|
||||
"/series/Dexter/Season 1/Dexter - S01E02 - Second Epi-interview.mkv",
|
||||
"/series/Dexter/Season 1/Dexter - S01E02 - Second Epi-scene.mkv",
|
||||
"/series/Dexter/Season 1/It's a begining-behindthescenes.mkv",
|
||||
"/series/Dexter/Season 1/interviews/The Cast.mkv",
|
||||
"/series/Dexter/Funny-behindthescenes.mkv",
|
||||
"/series/Dexter/interviews/The Director.mkv",
|
||||
"/series/Dexter/Dexter - S02E05.mkv",
|
||||
"/series/Dexter/Dexter - S02E05-clip.mkv",
|
||||
"/series/Dexter/Dexter - S03E05/Dexter - S03E05 - Fifth.mkv",
|
||||
"/series/Dexter/Dexter - S03E05/Dexter - S03E05 - Fifth-featurette.mkv",
|
||||
};
|
||||
|
||||
var files = paths.Select(p => new FileSystemMetadata
|
||||
{
|
||||
FullName = p,
|
||||
Name = Path.GetFileName(p),
|
||||
Extension = Path.GetExtension(p),
|
||||
IsDirectory = string.IsNullOrEmpty(Path.GetExtension(p))
|
||||
}).ToList();
|
||||
|
||||
var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList();
|
||||
|
||||
Assert.Equal(2, extras.Count);
|
||||
Assert.Equal(ExtraType.BehindTheScenes, extras[0].ExtraType);
|
||||
Assert.Equal(typeof(Video), extras[0].GetType());
|
||||
Assert.Equal("Funny-behindthescenes", extras[0].FileNameWithoutExtension);
|
||||
Assert.Equal("/series/Dexter/Funny-behindthescenes.mkv", extras[0].Path);
|
||||
Assert.Equal("/series/Dexter/interviews/The Director.mkv", extras[1].Path);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindExtras_SeasonWithExtras_FindsCorrectExtras()
|
||||
{
|
||||
var owner = new Season { Name = "Season 1", SeriesName = "Dexter", Path = "/series/Dexter/Season 1" };
|
||||
var paths = new List<string>
|
||||
{
|
||||
"/series/Dexter/Season 1/Dexter 1x01 [Bluray-1080p x264][AC3 5.1][-reward] - Northwest Passage.mkv",
|
||||
"/series/Dexter/Season 1/Dexter 1x01-deleted.mkv",
|
||||
"/series/Dexter/Season 1/Dexter 1x01 [WEBDL-1080p AVC][AAC 2.0][YouTube]-deleted.mkv",
|
||||
"/series/Dexter/Season 1/Dexter 1x01 [WEBDL-1080p AVC][AAC 2.0][YouTube][-MrC] - Log Lady Introduction 1-extra.mkv",
|
||||
"/series/Dexter/Season 1/Dexter - S01E02 - Second Epi.mkv",
|
||||
"/series/Dexter/Season 1/Dexter - S01E02 - Second Epi-interview.mkv",
|
||||
"/series/Dexter/Season 1/Dexter - S01E02 - Second Epi-scene.mkv",
|
||||
"/series/Dexter/Season 1/It's a begining-behindthescenes.mkv",
|
||||
"/series/Dexter/Season 1/interviews/The Cast.mkv",
|
||||
"/series/Dexter/Funny-behindthescenes.mkv",
|
||||
"/series/Dexter/interviews/The Director.mkv",
|
||||
"/series/Dexter/Dexter - S02E05.mkv",
|
||||
"/series/Dexter/Dexter - S02E05-clip.mkv",
|
||||
"/series/Dexter/Dexter - S03E05/Dexter - S03E05 - Fifth.mkv",
|
||||
"/series/Dexter/Dexter - S03E05/Dexter - S03E05 - Fifth-featurette.mkv",
|
||||
};
|
||||
|
||||
var files = paths.Select(p => new FileSystemMetadata
|
||||
{
|
||||
FullName = p,
|
||||
Name = Path.GetFileName(p),
|
||||
Extension = Path.GetExtension(p),
|
||||
IsDirectory = string.IsNullOrEmpty(Path.GetExtension(p))
|
||||
}).ToList();
|
||||
|
||||
var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList();
|
||||
|
||||
Assert.Equal(2, extras.Count);
|
||||
Assert.Equal(ExtraType.BehindTheScenes, extras[0].ExtraType);
|
||||
Assert.Equal(typeof(Video), extras[0].GetType());
|
||||
Assert.Equal("It's a begining-behindthescenes", extras[0].FileNameWithoutExtension);
|
||||
Assert.Equal("/series/Dexter/Season 1/It's a begining-behindthescenes.mkv", extras[0].Path);
|
||||
Assert.Equal("/series/Dexter/Season 1/interviews/The Cast.mkv", extras[1].Path);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindExtras_SeasonWithExtras_FindsCorrectExtras2()
|
||||
{
|
||||
// Series name directory has special characters stripped that episodes do not
|
||||
var owner = new Season { Name = "Season 1", SeriesName = "The Venture Bros.", Path = "/series/The Venture Bros/Season 1" };
|
||||
var paths = new List<string>
|
||||
{
|
||||
"/series/The Venture Bros/Season 1/The Venture Bros. S01E01.mkv",
|
||||
"/series/The Venture Bros/Season 1/The Venture Bros. S01E01-deleted.mkv",
|
||||
"/series/The Venture Bros/Season 1/The Venture Bros. - S01E02 - Second Epi.mkv",
|
||||
"/series/The Venture Bros/Season 1/The Venture Bros. - S01E02 - Second Epi-interview.mkv",
|
||||
"/series/The Venture Bros/Season 1/The Venture Bros. - S01E02 - Second Epi-scene.mkv",
|
||||
"/series/The Venture Bros/Season 1/It's a begining-behindthescenes.mkv",
|
||||
"/series/The Venture Bros/Season 1/interviews/The Cast.mkv",
|
||||
};
|
||||
|
||||
var files = paths.Select(p => new FileSystemMetadata
|
||||
{
|
||||
FullName = p,
|
||||
Name = Path.GetFileName(p),
|
||||
Extension = Path.GetExtension(p),
|
||||
IsDirectory = string.IsNullOrEmpty(Path.GetExtension(p))
|
||||
}).ToList();
|
||||
|
||||
var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList();
|
||||
|
||||
Assert.Equal(2, extras.Count);
|
||||
Assert.Equal(ExtraType.BehindTheScenes, extras[0].ExtraType);
|
||||
Assert.Equal(typeof(Video), extras[0].GetType());
|
||||
Assert.Equal("It's a begining-behindthescenes", extras[0].FileNameWithoutExtension);
|
||||
Assert.Equal("/series/The Venture Bros/Season 1/It's a begining-behindthescenes.mkv", extras[0].Path);
|
||||
Assert.Equal("/series/The Venture Bros/Season 1/interviews/The Cast.mkv", extras[1].Path);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindExtras_EpisodeWithExtras_FindsCorrectExtras()
|
||||
{
|
||||
var paths = new List<string>
|
||||
{
|
||||
"/series/Dexter/Season 1/Dexter - S01E01.mkv",
|
||||
"/series/Dexter/Season 1/Dexter - S01E01-deleted.mkv",
|
||||
"/series/Dexter/Season 1/Dexter - S01E02 - Second Epi.mkv",
|
||||
"/series/Dexter/Season 1/Dexter - S01E02 - Second Epi-interview.mkv",
|
||||
"/series/Dexter/Season 1/Dexter - S01E02 - Second Epi-scene.mkv",
|
||||
"/series/Dexter/Season 1/It's a begining-behindthescenes.mkv",
|
||||
"/series/Dexter/Season 1/interviews/The Cast.mkv",
|
||||
"/series/Dexter/Funny-behindthescenes.mkv",
|
||||
"/series/Dexter/interviews/The Director.mkv",
|
||||
"/series/Dexter/Dexter - S02E05.mkv",
|
||||
"/series/Dexter/Dexter - S02E05-clip.mkv",
|
||||
"/series/Dexter/Dexter - S03E05/Dexter - S03E05 - Fifth.mkv",
|
||||
"/series/Dexter/Dexter - S03E05/Dexter - S03E05 - Fifth-featurette.mkv",
|
||||
"/series/Dexter/Dexter - S03E05/Dexter - S03E05 - Fifth-featurette2.mkv",
|
||||
"/series/Dexter/Dexter - S03E05/Deleted Scenes/Meet Friends.mkv",
|
||||
};
|
||||
|
||||
var files = paths.Select(p => new FileSystemMetadata
|
||||
{
|
||||
FullName = p,
|
||||
Name = Path.GetFileName(p),
|
||||
Extension = Path.GetExtension(p),
|
||||
IsDirectory = string.IsNullOrEmpty(Path.GetExtension(p))
|
||||
}).ToList();
|
||||
|
||||
var owner = new Episode { Name = "Dexter - S01E01", Path = "/series/Dexter/Season 1/Dexter - S01E01.mkv", IsInMixedFolder = true };
|
||||
var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList();
|
||||
|
||||
Assert.Single(extras);
|
||||
Assert.Equal(ExtraType.DeletedScene, extras[0].ExtraType);
|
||||
Assert.Equal(typeof(Video), extras[0].GetType());
|
||||
Assert.Equal("/series/Dexter/Season 1/Dexter - S01E01-deleted.mkv", extras[0].Path);
|
||||
|
||||
owner = new Episode { Name = "Dexter - S01E02 - Second Epi", Path = "/series/Dexter/Season 1/Dexter - S01E02 - Second Epi.mkv", IsInMixedFolder = true };
|
||||
extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList();
|
||||
|
||||
Assert.Equal(2, extras.Count);
|
||||
Assert.Equal(ExtraType.Interview, extras[0].ExtraType);
|
||||
Assert.Equal(ExtraType.Scene, extras[1].ExtraType);
|
||||
Assert.Equal(typeof(Video), extras[0].GetType());
|
||||
Assert.Equal("/series/Dexter/Season 1/Dexter - S01E02 - Second Epi-interview.mkv", extras[0].Path);
|
||||
Assert.Equal("/series/Dexter/Season 1/Dexter - S01E02 - Second Epi-scene.mkv", extras[1].Path);
|
||||
|
||||
owner = new Episode { Name = "Dexter - S02E05", Path = "/series/Dexter/Dexter - S02E05.mkv", IsInMixedFolder = true };
|
||||
extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList();
|
||||
|
||||
Assert.Single(extras);
|
||||
Assert.Equal(ExtraType.Clip, extras[0].ExtraType);
|
||||
Assert.Equal(typeof(Video), extras[0].GetType());
|
||||
Assert.Equal("/series/Dexter/Dexter - S02E05-clip.mkv", extras[0].Path);
|
||||
|
||||
// episode folder with special feature subfolders are not supported yet, but it should be considered as not mixed, but current is marked as mixed
|
||||
Folder folderOwner = new Folder { Name = "Dexter - S03E05", Path = "/series/Dexter/Dexter - S03E05", IsInMixedFolder = false };
|
||||
extras = _libraryManager.FindExtras(folderOwner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList();
|
||||
|
||||
Assert.Equal(3, extras.Count);
|
||||
// directory type extras are found before suffix type
|
||||
Assert.Equal(ExtraType.DeletedScene, extras[0].ExtraType);
|
||||
Assert.Equal("/series/Dexter/Dexter - S03E05/Deleted Scenes/Meet Friends.mkv", extras[0].Path);
|
||||
Assert.Equal(ExtraType.Featurette, extras[1].ExtraType);
|
||||
Assert.Equal(typeof(Video), extras[1].GetType());
|
||||
Assert.Equal("/series/Dexter/Dexter - S03E05/Dexter - S03E05 - Fifth-featurette.mkv", extras[1].Path);
|
||||
Assert.Equal("/series/Dexter/Dexter - S03E05/Dexter - S03E05 - Fifth-featurette2.mkv", extras[2].Path);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindExtras_EpisodeWithExtras_CleanNameTest()
|
||||
{
|
||||
var paths = new List<string>
|
||||
{
|
||||
"/series/Dexter/Season 1/Dexter - S01E01[Bluray-1080p x264][AC3 5.1].mkv",
|
||||
"/series/Dexter/Season 1/Dexter - S01E01 [WEBDL-1080p AVC][AAC 2.0][YouTube]-deleted.mkv",
|
||||
"/series/Dexter/Season 1/Dexter - S01E01[Bluray-1080p x264][AC3 5.1] - Some crazy deleted scene -deleted.mkv"
|
||||
};
|
||||
|
||||
var files = paths.Select(p => new FileSystemMetadata
|
||||
{
|
||||
FullName = p,
|
||||
Name = Path.GetFileName(p),
|
||||
Extension = Path.GetExtension(p),
|
||||
IsDirectory = string.IsNullOrEmpty(Path.GetExtension(p))
|
||||
}).ToList();
|
||||
|
||||
var owner = new Episode { Name = "Dexter - S01E01", Path = "/series/Dexter/Season 1/Dexter - S01E01[Bluray-1080p x264][AC3 5.1].mkv", IsInMixedFolder = true };
|
||||
var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList();
|
||||
|
||||
Assert.Equal(2, extras.Count);
|
||||
Assert.Equal(ExtraType.DeletedScene, extras[0].ExtraType);
|
||||
Assert.Equal(typeof(Video), extras[0].GetType());
|
||||
Assert.Equal("/series/Dexter/Season 1/Dexter - S01E01 [WEBDL-1080p AVC][AAC 2.0][YouTube]-deleted.mkv", extras[0].Path);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue