mirror of
https://github.com/Readarr/Readarr.git
synced 2026-03-05 13:20:32 -05:00
New: Author folder hint when selecting a root folder while adding a new author
(cherry picked from commit dd09f31abb4dd3f699bcff0a47577075300c70ee) Fix AuthorFolderAsRootFolderValidator (cherry picked from commit 0ce81e1ab69d43fde382cc4ae22cd46fe626dea7)
This commit is contained in:
@@ -108,6 +108,15 @@ namespace NzbDrone.Common.Extensions
|
||||
return Directory.GetParent(cleanPath)?.FullName;
|
||||
}
|
||||
|
||||
public static string GetCleanPath(this string path)
|
||||
{
|
||||
var cleanPath = OsInfo.IsWindows
|
||||
? PARENT_PATH_END_SLASH_REGEX.Replace(path, "")
|
||||
: path.TrimEnd(Path.DirectorySeparatorChar);
|
||||
|
||||
return cleanPath;
|
||||
}
|
||||
|
||||
public static bool IsParentPath(this string parentPath, string childPath)
|
||||
{
|
||||
if (parentPath != "/" && !parentPath.EndsWith(":\\"))
|
||||
|
||||
@@ -11,7 +11,11 @@
|
||||
"AddListExclusion": "Add List Exclusion",
|
||||
"AddMissing": "Add missing",
|
||||
"AddNew": "Add New",
|
||||
"AddNewBook": "Add New Book",
|
||||
"AddNewAuthor": "Add New Author",
|
||||
"AddNewAuthorRootFolderHelpText": "'{folder}' subfolder will be created automatically",
|
||||
"AddNewItem": "Add New Item",
|
||||
"AddRootFolder": "Add Root Folder",
|
||||
"AddedAuthorSettings": "Added Author Settings",
|
||||
"AddingTag": "Adding tag",
|
||||
"AgeWhenGrabbed": "Age (when grabbed)",
|
||||
|
||||
@@ -59,7 +59,8 @@ namespace Readarr.Api.V1.Author
|
||||
AuthorAncestorValidator authorAncestorValidator,
|
||||
SystemFolderValidator systemFolderValidator,
|
||||
QualityProfileExistsValidator qualityProfileExistsValidator,
|
||||
MetadataProfileExistsValidator metadataProfileExistsValidator)
|
||||
MetadataProfileExistsValidator metadataProfileExistsValidator,
|
||||
AuthorFolderAsRootFolderValidator authorFolderAsRootFolderValidator)
|
||||
: base(signalRBroadcaster)
|
||||
{
|
||||
_authorService = authorService;
|
||||
@@ -89,7 +90,10 @@ namespace Readarr.Api.V1.Author
|
||||
SharedValidator.RuleFor(s => s.MetadataProfileId).SetValidator(metadataProfileExistsValidator);
|
||||
|
||||
PostValidator.RuleFor(s => s.Path).IsValidPath().When(s => s.RootFolderPath.IsNullOrWhiteSpace());
|
||||
PostValidator.RuleFor(s => s.RootFolderPath).IsValidPath().When(s => s.Path.IsNullOrWhiteSpace());
|
||||
PostValidator.RuleFor(s => s.RootFolderPath)
|
||||
.IsValidPath()
|
||||
.SetValidator(authorFolderAsRootFolderValidator)
|
||||
.When(s => s.Path.IsNullOrWhiteSpace());
|
||||
PostValidator.RuleFor(s => s.AuthorName).NotEmpty();
|
||||
PostValidator.RuleFor(s => s.ForeignAuthorId).NotEmpty().SetValidator(authorExistsValidator);
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using FluentValidation.Validators;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Organizer;
|
||||
|
||||
namespace Readarr.Api.V1.Author
|
||||
{
|
||||
public class AuthorFolderAsRootFolderValidator : PropertyValidator
|
||||
{
|
||||
private readonly IBuildFileNames _fileNameBuilder;
|
||||
|
||||
public AuthorFolderAsRootFolderValidator(IBuildFileNames fileNameBuilder)
|
||||
{
|
||||
_fileNameBuilder = fileNameBuilder;
|
||||
}
|
||||
|
||||
protected override string GetDefaultMessageTemplate() => "Root folder path contains author folder";
|
||||
|
||||
protected override bool IsValid(PropertyValidatorContext context)
|
||||
{
|
||||
if (context.PropertyValue == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var authorResource = context.ParentContext.InstanceToValidate as AuthorResource;
|
||||
|
||||
if (authorResource == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var rootFolderPath = context.PropertyValue.ToString();
|
||||
var rootFolder = new DirectoryInfo(rootFolderPath).Name;
|
||||
var author = authorResource.ToModel();
|
||||
var authorFolder = _fileNameBuilder.GetAuthorFolder(author);
|
||||
|
||||
if (authorFolder == rootFolder)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var distance = authorFolder.LevenshteinDistance(rootFolder);
|
||||
|
||||
return distance >= Math.Max(1, authorFolder.Length * 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using Readarr.Http;
|
||||
|
||||
namespace Readarr.Api.V1.Author
|
||||
@@ -11,11 +12,13 @@ namespace Readarr.Api.V1.Author
|
||||
public class AuthorLookupController : Controller
|
||||
{
|
||||
private readonly ISearchForNewAuthor _searchProxy;
|
||||
private readonly IBuildFileNames _fileNameBuilder;
|
||||
private readonly IMapCoversToLocal _coverMapper;
|
||||
|
||||
public AuthorLookupController(ISearchForNewAuthor searchProxy, IMapCoversToLocal coverMapper)
|
||||
public AuthorLookupController(ISearchForNewAuthor searchProxy, IBuildFileNames fileNameBuilder, IMapCoversToLocal coverMapper)
|
||||
{
|
||||
_searchProxy = searchProxy;
|
||||
_fileNameBuilder = fileNameBuilder;
|
||||
_coverMapper = coverMapper;
|
||||
}
|
||||
|
||||
@@ -41,6 +44,8 @@ namespace Readarr.Api.V1.Author
|
||||
resource.RemotePoster = poster.Url;
|
||||
}
|
||||
|
||||
resource.Folder = _fileNameBuilder.GetAuthorFolder(currentAuthor);
|
||||
|
||||
yield return resource;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ namespace Readarr.Api.V1.Author
|
||||
public NewItemMonitorTypes MonitorNewItems { get; set; }
|
||||
|
||||
public string RootFolderPath { get; set; }
|
||||
public string Folder { get; set; }
|
||||
public List<string> Genres { get; set; }
|
||||
public string CleanName { get; set; }
|
||||
public string SortName { get; set; }
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Books;
|
||||
using NzbDrone.Core.Books.Calibre;
|
||||
using NzbDrone.Core.RootFolders;
|
||||
@@ -47,7 +48,7 @@ namespace Readarr.Api.V1.RootFolders
|
||||
Id = model.Id,
|
||||
|
||||
Name = model.Name,
|
||||
Path = model.Path,
|
||||
Path = model.Path.GetCleanPath(),
|
||||
DefaultMetadataProfileId = model.DefaultMetadataProfileId,
|
||||
DefaultQualityProfileId = model.DefaultQualityProfileId,
|
||||
DefaultMonitorOption = model.DefaultMonitorOption,
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NzbDrone.Core.MediaCover;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using Readarr.Api.V1.Author;
|
||||
using Readarr.Api.V1.Books;
|
||||
using Readarr.Http;
|
||||
@@ -14,11 +15,13 @@ namespace Readarr.Api.V1.Search
|
||||
public class SearchController : Controller
|
||||
{
|
||||
private readonly ISearchForNewEntity _searchProxy;
|
||||
private readonly IBuildFileNames _fileNameBuilder;
|
||||
private readonly IMapCoversToLocal _coverMapper;
|
||||
|
||||
public SearchController(ISearchForNewEntity searchProxy, IMapCoversToLocal coverMapper)
|
||||
public SearchController(ISearchForNewEntity searchProxy, IBuildFileNames fileNameBuilder, IMapCoversToLocal coverMapper)
|
||||
{
|
||||
_searchProxy = searchProxy;
|
||||
_fileNameBuilder = fileNameBuilder;
|
||||
_coverMapper = coverMapper;
|
||||
}
|
||||
|
||||
@@ -50,6 +53,8 @@ namespace Readarr.Api.V1.Search
|
||||
{
|
||||
resource.Author.RemotePoster = poster.Url;
|
||||
}
|
||||
|
||||
resource.Author.Folder = _fileNameBuilder.GetAuthorFolder(author);
|
||||
}
|
||||
else if (result is NzbDrone.Core.Books.Book book)
|
||||
{
|
||||
@@ -67,6 +72,8 @@ namespace Readarr.Api.V1.Search
|
||||
{
|
||||
resource.Book.RemoteCover = cover.Url;
|
||||
}
|
||||
|
||||
resource.Book.Author.Folder = _fileNameBuilder.GetAuthorFolder(book.Author);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user