From 74d36b6f6e5893ecd58d2fe12226f0160c50c8ee Mon Sep 17 00:00:00 2001 From: Mikal Stordal Date: Sun, 24 Mar 2024 01:11:45 +0100 Subject: [PATCH 1/3] Don't expect `BaseItem` to be a movie/video file. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fix is mainly so I can mass-add series _and_ movie entries using a `IMultiItemResolver` without having to resort to complicated logic using _both_ a `IItemResolver` and a `IMultiItemResolver` by splitting up what gets added where. I've also added three new interface methods to the `IDirectoryService`, one of which is used in the modified `ResolverHelper.SetInitialItemValues(…)` to get the file system entry info for the item regardless of which type the file system entry is. In my local testing so far I haven't found any issues introduced by this change. --- .../Library/ResolverHelper.cs | 2 +- .../Providers/DirectoryService.cs | 40 ++++++++++++++++--- .../Providers/IDirectoryService.cs | 6 +++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/Emby.Server.Implementations/Library/ResolverHelper.cs b/Emby.Server.Implementations/Library/ResolverHelper.cs index 7a61e2607c..3ffc80533d 100644 --- a/Emby.Server.Implementations/Library/ResolverHelper.cs +++ b/Emby.Server.Implementations/Library/ResolverHelper.cs @@ -39,7 +39,7 @@ namespace Emby.Server.Implementations.Library item.GetParents().Any(i => i.IsLocked); // Make sure DateCreated and DateModified have values - var fileInfo = directoryService.GetFile(item.Path); + var fileInfo = directoryService.GetFileSystemEntry(item.Path); if (fileInfo is null) { return false; diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs index 7fe2f64af3..305453cde7 100644 --- a/MediaBrowser.Controller/Providers/DirectoryService.cs +++ b/MediaBrowser.Controller/Providers/DirectoryService.cs @@ -28,6 +28,21 @@ namespace MediaBrowser.Controller.Providers return _cache.GetOrAdd(path, static (p, fileSystem) => fileSystem.GetFileSystemEntries(p).ToArray(), _fileSystem); } + public FileSystemMetadata? GetFileSystemEntry(string path) + { + if (!_fileCache.TryGetValue(path, out var result)) + { + var file = _fileSystem.GetFileSystemInfo(path); + if (file.Exists) + { + result = file; + _fileCache.TryAdd(path, result); + } + } + + return result; + } + public List GetFiles(string path) { var list = new List(); @@ -46,17 +61,30 @@ namespace MediaBrowser.Controller.Providers public FileSystemMetadata? GetFile(string path) { - if (!_fileCache.TryGetValue(path, out var result)) + var entry = GetFileSystemEntry(path); + return entry != null && !entry.IsDirectory ? entry : null; + } + + public List GetDirectories(string path) + { + var list = new List(); + var items = GetFileSystemEntries(path); + for (var i = 0; i < items.Length; i++) { - var file = _fileSystem.GetFileInfo(path); - if (file.Exists) + var item = items[i]; + if (item.IsDirectory) { - result = file; - _fileCache.TryAdd(path, result); + list.Add(item); } } - return result; + return list; + } + + public FileSystemMetadata? GetDirectory(string path) + { + var entry = GetFileSystemEntry(path); + return entry != null && entry.IsDirectory ? entry : null; } public IReadOnlyList GetFilePaths(string path) diff --git a/MediaBrowser.Controller/Providers/IDirectoryService.cs b/MediaBrowser.Controller/Providers/IDirectoryService.cs index 6d7550ab53..5cd6772b8e 100644 --- a/MediaBrowser.Controller/Providers/IDirectoryService.cs +++ b/MediaBrowser.Controller/Providers/IDirectoryService.cs @@ -9,10 +9,16 @@ namespace MediaBrowser.Controller.Providers { FileSystemMetadata[] GetFileSystemEntries(string path); + FileSystemMetadata? GetFileSystemEntry(string path); + List GetFiles(string path); FileSystemMetadata? GetFile(string path); + List GetDirectories(string path); + + FileSystemMetadata? GetDirectory(string path); + IReadOnlyList GetFilePaths(string path); IReadOnlyList GetFilePaths(string path, bool clearCache, bool sort = false); From afc7699e4eabb86a6987f3389d1e56dc4511cbbf Mon Sep 17 00:00:00 2001 From: Mikal Stordal Date: Sun, 24 Mar 2024 04:41:15 +0000 Subject: [PATCH 2/3] fix: add null check --- MediaBrowser.Controller/Providers/DirectoryService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Controller/Providers/DirectoryService.cs b/MediaBrowser.Controller/Providers/DirectoryService.cs index 305453cde7..42d795ae5a 100644 --- a/MediaBrowser.Controller/Providers/DirectoryService.cs +++ b/MediaBrowser.Controller/Providers/DirectoryService.cs @@ -33,7 +33,7 @@ namespace MediaBrowser.Controller.Providers if (!_fileCache.TryGetValue(path, out var result)) { var file = _fileSystem.GetFileSystemInfo(path); - if (file.Exists) + if (file?.Exists ?? false) { result = file; _fileCache.TryAdd(path, result); From 8fcb0cbfbf2b0f4df54aec112c4380d6f01e216a Mon Sep 17 00:00:00 2001 From: Mikal Stordal Date: Sun, 24 Mar 2024 05:06:32 +0000 Subject: [PATCH 3/3] fix: update tests --- .../DirectoryServiceTests.cs | 68 ++++++++++++++++--- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/tests/Jellyfin.Controller.Tests/DirectoryServiceTests.cs b/tests/Jellyfin.Controller.Tests/DirectoryServiceTests.cs index 46439aecbe..83a0233845 100644 --- a/tests/Jellyfin.Controller.Tests/DirectoryServiceTests.cs +++ b/tests/Jellyfin.Controller.Tests/DirectoryServiceTests.cs @@ -79,6 +79,21 @@ namespace Jellyfin.Controller.Tests Assert.Equal(_lowerCaseFileSystemMetadata.Where(f => !f.IsDirectory), lowerCaseResult); } + [Fact] + public void GetDirectories_GivenPathsWithDifferentCasing_ReturnsCorrectDirectories() + { + var fileSystemMock = new Mock(); + fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == UpperCasePath), false)).Returns(_upperCaseFileSystemMetadata); + fileSystemMock.Setup(f => f.GetFileSystemEntries(It.Is(x => x == LowerCasePath), false)).Returns(_lowerCaseFileSystemMetadata); + var directoryService = new DirectoryService(fileSystemMock.Object); + + var upperCaseResult = directoryService.GetDirectories(UpperCasePath); + var lowerCaseResult = directoryService.GetDirectories(LowerCasePath); + + Assert.Equal(_upperCaseFileSystemMetadata.Where(f => f.IsDirectory), upperCaseResult); + Assert.Equal(_lowerCaseFileSystemMetadata.Where(f => f.IsDirectory), lowerCaseResult); + } + [Fact] public void GetFile_GivenFilePathsWithDifferentCasing_ReturnsCorrectFile() { @@ -95,15 +110,52 @@ namespace Jellyfin.Controller.Tests Exists = false }; var fileSystemMock = new Mock(); - fileSystemMock.Setup(f => f.GetFileInfo(It.Is(x => x == upperCasePath))).Returns(upperCaseFileSystemMetadata); - fileSystemMock.Setup(f => f.GetFileInfo(It.Is(x => x == lowerCasePath))).Returns(lowerCaseFileSystemMetadata); + fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == upperCasePath))).Returns(upperCaseFileSystemMetadata); + fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == lowerCasePath))).Returns(lowerCaseFileSystemMetadata); + var directoryService = new DirectoryService(fileSystemMock.Object); + + var lowerCaseDirResult = directoryService.GetDirectory(lowerCasePath); + var lowerCaseFileResult = directoryService.GetFile(lowerCasePath); + var upperCaseDirResult = directoryService.GetDirectory(upperCasePath); + var upperCaseFileResult = directoryService.GetFile(upperCasePath); + + Assert.Null(lowerCaseDirResult); + Assert.Equal(lowerCaseFileSystemMetadata, lowerCaseFileResult); + Assert.Null(upperCaseDirResult); + Assert.Null(upperCaseFileResult); + } + + [Fact] + public void GetDirectory_GivenFilePathsWithDifferentCasing_ReturnsCorrectDirectory() + { + const string lowerCasePath = "/music/someartist/Lyrics"; + var lowerCaseFileSystemMetadata = new FileSystemMetadata + { + FullName = lowerCasePath, + IsDirectory = true, + Exists = true + }; + const string upperCasePath = "/music/SOMEARTIST/LYRICS"; + var upperCaseFileSystemMetadata = new FileSystemMetadata + { + FullName = upperCasePath, + IsDirectory = true, + Exists = false + }; + var fileSystemMock = new Mock(); + fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == upperCasePath))).Returns(upperCaseFileSystemMetadata); + fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == lowerCasePath))).Returns(lowerCaseFileSystemMetadata); var directoryService = new DirectoryService(fileSystemMock.Object); - var lowerCaseResult = directoryService.GetFile(lowerCasePath); - var upperCaseResult = directoryService.GetFile(upperCasePath); + var lowerCaseDirResult = directoryService.GetDirectory(lowerCasePath); + var lowerCaseFileResult = directoryService.GetFile(lowerCasePath); + var upperCaseDirResult = directoryService.GetDirectory(upperCasePath); + var upperCaseFileResult = directoryService.GetFile(upperCasePath); - Assert.Equal(lowerCaseFileSystemMetadata, lowerCaseResult); - Assert.Null(upperCaseResult); + Assert.Equal(lowerCaseFileSystemMetadata, lowerCaseDirResult); + Assert.Null(lowerCaseFileResult); + Assert.Null(upperCaseDirResult); + Assert.Null(upperCaseFileResult); } [Fact] @@ -122,11 +174,11 @@ namespace Jellyfin.Controller.Tests }; var fileSystemMock = new Mock(); - fileSystemMock.Setup(f => f.GetFileInfo(It.Is(x => x == path))).Returns(cachedFileSystemMetadata); + fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == path))).Returns(cachedFileSystemMetadata); var directoryService = new DirectoryService(fileSystemMock.Object); var result = directoryService.GetFile(path); - fileSystemMock.Setup(f => f.GetFileInfo(It.Is(x => x == path))).Returns(newFileSystemMetadata); + fileSystemMock.Setup(f => f.GetFileSystemInfo(It.Is(x => x == path))).Returns(newFileSystemMetadata); var secondResult = directoryService.GetFile(path); Assert.Equal(cachedFileSystemMetadata, result);