mirror of
https://github.com/Radarr/Radarr.git
synced 2025-04-24 14:37:07 -04:00
New: Use Movie Folder Format to improve unmapped folders within root folders
(cherry picked from commit 81d2b18ce1c079c2a9dc3de037c9dceea16733fd) Closes #8065
This commit is contained in:
parent
7198aa24a6
commit
c9da7ee0c9
8 changed files with 81 additions and 6 deletions
|
@ -10,6 +10,7 @@ import styles from './ImportMovieRow.css';
|
|||
function ImportMovieRow(props) {
|
||||
const {
|
||||
id,
|
||||
relativePath,
|
||||
monitor,
|
||||
qualityProfileId,
|
||||
minimumAvailability,
|
||||
|
@ -31,7 +32,7 @@ function ImportMovieRow(props) {
|
|||
/>
|
||||
|
||||
<VirtualTableRowCell className={styles.folder}>
|
||||
{id}
|
||||
{relativePath}
|
||||
</VirtualTableRowCell>
|
||||
|
||||
<VirtualTableRowCell className={styles.movie}>
|
||||
|
@ -73,6 +74,7 @@ function ImportMovieRow(props) {
|
|||
|
||||
ImportMovieRow.propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
relativePath: PropTypes.string.isRequired,
|
||||
monitor: PropTypes.string.isRequired,
|
||||
qualityProfileId: PropTypes.number.isRequired,
|
||||
minimumAvailability: PropTypes.string.isRequired,
|
||||
|
|
|
@ -30,7 +30,7 @@ class ImportMovieTable extends Component {
|
|||
unmappedFolders.forEach((unmappedFolder) => {
|
||||
const id = unmappedFolder.name;
|
||||
|
||||
onMovieLookup(id, unmappedFolder.path);
|
||||
onMovieLookup(id, unmappedFolder.path, unmappedFolder.relativePath);
|
||||
|
||||
onSetImportMovieValue({
|
||||
id,
|
||||
|
|
|
@ -25,10 +25,11 @@ function createMapStateToProps() {
|
|||
|
||||
function createMapDispatchToProps(dispatch, props) {
|
||||
return {
|
||||
onMovieLookup(name, path) {
|
||||
onMovieLookup(name, path, relativePath) {
|
||||
dispatch(queueLookupMovie({
|
||||
name,
|
||||
path,
|
||||
relativePath,
|
||||
term: name
|
||||
}));
|
||||
},
|
||||
|
|
|
@ -66,6 +66,7 @@ export const actionHandlers = handleThunks({
|
|||
const {
|
||||
name,
|
||||
path,
|
||||
relativePath,
|
||||
term,
|
||||
topOfQueue = false
|
||||
} = payload;
|
||||
|
@ -75,6 +76,7 @@ export const actionHandlers = handleThunks({
|
|||
id: name,
|
||||
term,
|
||||
path,
|
||||
relativePath,
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null
|
||||
|
|
|
@ -10,6 +10,7 @@ using NzbDrone.Common.Disk;
|
|||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.RootFolders;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Test.Common;
|
||||
|
@ -19,9 +20,13 @@ namespace NzbDrone.Core.Test.RootFolderTests
|
|||
[TestFixture]
|
||||
public class RootFolderServiceFixture : CoreTest<RootFolderService>
|
||||
{
|
||||
private NamingConfig _namingConfig;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_namingConfig = NamingConfig.Default;
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(m => m.FolderExists(It.IsAny<string>()))
|
||||
.Returns(true);
|
||||
|
@ -33,6 +38,10 @@ namespace NzbDrone.Core.Test.RootFolderTests
|
|||
Mocker.GetMock<IRootFolderRepository>()
|
||||
.Setup(s => s.All())
|
||||
.Returns(new List<RootFolder>());
|
||||
|
||||
Mocker.GetMock<INamingConfigService>()
|
||||
.Setup(c => c.GetConfig())
|
||||
.Returns(_namingConfig);
|
||||
}
|
||||
|
||||
private void WithNonExistingFolder()
|
||||
|
@ -254,5 +263,47 @@ namespace NzbDrone.Core.Test.RootFolderTests
|
|||
unmappedFolders.Count.Should().Be(3);
|
||||
unmappedFolders.Should().NotContain(u => u.Name == "BIN");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_get_unmapped_folders_inside_letter_subfolder()
|
||||
{
|
||||
_namingConfig.MovieFolderFormat = "{Movie TitleFirstCharacter}\\{Movie Title}".AsOsAgnostic();
|
||||
|
||||
var rootFolderPath = @"C:\Test\Movies".AsOsAgnostic();
|
||||
var rootFolder = Builder<RootFolder>.CreateNew()
|
||||
.With(r => r.Path = rootFolderPath)
|
||||
.Build();
|
||||
|
||||
var subFolderPath = Path.Combine(rootFolderPath, "M");
|
||||
|
||||
var subFolders = new[]
|
||||
{
|
||||
"Movie1",
|
||||
"Movie2",
|
||||
"Movie3",
|
||||
};
|
||||
|
||||
var folders = subFolders.Select(f => Path.Combine(subFolderPath, f)).ToArray();
|
||||
|
||||
Mocker.GetMock<IRootFolderRepository>()
|
||||
.Setup(s => s.Get(It.IsAny<int>()))
|
||||
.Returns(rootFolder);
|
||||
|
||||
Mocker.GetMock<IMovieRepository>()
|
||||
.Setup(s => s.AllMoviePaths())
|
||||
.Returns(new Dictionary<int, string>());
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetDirectories(rootFolder.Path))
|
||||
.Returns(new[] { subFolderPath });
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetDirectories(subFolderPath))
|
||||
.Returns(folders);
|
||||
|
||||
var unmappedFolders = Subject.Get(rootFolder.Id, false).UnmappedFolders;
|
||||
|
||||
unmappedFolders.Count.Should().Be(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ namespace NzbDrone.Core.RootFolders
|
|||
public class RootFolder : ModelBase
|
||||
{
|
||||
public string Path { get; set; }
|
||||
|
||||
public bool Accessible { get; set; }
|
||||
public long? FreeSpace { get; set; }
|
||||
public long? TotalSpace { get; set; }
|
||||
|
|
|
@ -9,6 +9,7 @@ using NzbDrone.Common.Disk;
|
|||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Movies;
|
||||
using NzbDrone.Core.Organizer;
|
||||
|
||||
namespace NzbDrone.Core.RootFolders
|
||||
{
|
||||
|
@ -28,6 +29,7 @@ namespace NzbDrone.Core.RootFolders
|
|||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IMovieRepository _movieRepository;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly INamingConfigService _namingConfigService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
private static readonly HashSet<string> SpecialFolders = new HashSet<string>
|
||||
|
@ -47,12 +49,14 @@ namespace NzbDrone.Core.RootFolders
|
|||
IDiskProvider diskProvider,
|
||||
IMovieRepository movieRepository,
|
||||
IConfigService configService,
|
||||
INamingConfigService namingConfigService,
|
||||
Logger logger)
|
||||
{
|
||||
_rootFolderRepository = rootFolderRepository;
|
||||
_diskProvider = diskProvider;
|
||||
_movieRepository = movieRepository;
|
||||
_configService = configService;
|
||||
_namingConfigService = namingConfigService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
|
@ -145,7 +149,17 @@ namespace NzbDrone.Core.RootFolders
|
|||
return results;
|
||||
}
|
||||
|
||||
var subFolderDepth = _namingConfigService.GetConfig().MovieFolderFormat.Count(f => f == Path.DirectorySeparatorChar);
|
||||
var possibleMovieFolders = _diskProvider.GetDirectories(path).ToList();
|
||||
|
||||
if (subFolderDepth > 0)
|
||||
{
|
||||
for (var i = 0; i < subFolderDepth; i++)
|
||||
{
|
||||
possibleMovieFolders = possibleMovieFolders.SelectMany(_diskProvider.GetDirectories).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
var unmappedFolders = possibleMovieFolders.Except(moviePaths.Select(s => s.Value), PathEqualityComparer.Instance).ToList();
|
||||
|
||||
var recycleBinPath = _configService.RecycleBin;
|
||||
|
@ -158,7 +172,12 @@ namespace NzbDrone.Core.RootFolders
|
|||
{
|
||||
if (string.IsNullOrWhiteSpace(recycleBinPath) || di.FullName.PathNotEquals(recycleBinPath))
|
||||
{
|
||||
results.Add(new UnmappedFolder { Name = di.Name, Path = di.FullName });
|
||||
results.Add(new UnmappedFolder
|
||||
{
|
||||
Name = di.Name,
|
||||
Path = di.FullName,
|
||||
RelativePath = path.GetRelativePath(di.FullName)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
namespace NzbDrone.Core.RootFolders
|
||||
namespace NzbDrone.Core.RootFolders
|
||||
{
|
||||
public class UnmappedFolder
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Path { get; set; }
|
||||
public string RelativePath { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue