parent
7b5bb5891a
commit
55daad8db1
@ -0,0 +1,13 @@
|
||||
using Recyclarr.Config.Models;
|
||||
using Recyclarr.ServarrApi.MediaNaming;
|
||||
using Recyclarr.TrashGuide.MediaNaming;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases.Config;
|
||||
|
||||
public interface IServiceBasedMediaNamingConfigPhase
|
||||
{
|
||||
Task<MediaNamingDto> ProcessNaming(
|
||||
IServiceConfiguration config,
|
||||
IMediaNamingGuideService guide,
|
||||
NamingFormatLookup lookup);
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
namespace Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases.Config;
|
||||
|
||||
public class NamingFormatLookup
|
||||
{
|
||||
private readonly List<InvalidNamingConfig> _errors = new();
|
||||
public IReadOnlyCollection<InvalidNamingConfig> Errors => _errors;
|
||||
|
||||
public string? ObtainFormat(
|
||||
IReadOnlyDictionary<string, string> guideFormats,
|
||||
string? configFormatKey,
|
||||
string errorDescription)
|
||||
{
|
||||
return ObtainFormat(guideFormats, configFormatKey, null, errorDescription);
|
||||
}
|
||||
|
||||
public string? ObtainFormat(
|
||||
IReadOnlyDictionary<string, string> guideFormats,
|
||||
string? configFormatKey,
|
||||
string? keySuffix,
|
||||
string errorDescription)
|
||||
{
|
||||
if (configFormatKey is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Use lower-case for the config value because System.Text.Json doesn't let us create a case-insensitive
|
||||
// dictionary. The MediaNamingGuideService converts all parsed guide JSON keys to lower case.
|
||||
var lowerKey = configFormatKey.ToLowerInvariant();
|
||||
|
||||
var keys = new List<string> {lowerKey};
|
||||
if (keySuffix is not null)
|
||||
{
|
||||
// Put the more specific key first
|
||||
keys.Insert(0, lowerKey + keySuffix);
|
||||
}
|
||||
|
||||
foreach (var k in keys)
|
||||
{
|
||||
if (guideFormats.TryGetValue(k, out var format))
|
||||
{
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
_errors.Add(new InvalidNamingConfig(errorDescription, configFormatKey));
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
using Recyclarr.Config.Models;
|
||||
using Recyclarr.ServarrApi.MediaNaming;
|
||||
using Recyclarr.TrashGuide.MediaNaming;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases.Config;
|
||||
|
||||
public class RadarrMediaNamingConfigPhase : ServiceBasedMediaNamingConfigPhase<RadarrConfiguration>
|
||||
{
|
||||
protected override Task<MediaNamingDto> ProcessNaming(
|
||||
RadarrConfiguration config,
|
||||
IMediaNamingGuideService guide,
|
||||
NamingFormatLookup lookup)
|
||||
{
|
||||
var guideData = guide.GetRadarrNamingData();
|
||||
var configData = config.MediaNaming;
|
||||
|
||||
return Task.FromResult<MediaNamingDto>(new RadarrMediaNamingDto
|
||||
{
|
||||
StandardMovieFormat =
|
||||
lookup.ObtainFormat(guideData.File, configData.Movie?.Standard, "Standard Movie Format"),
|
||||
MovieFolderFormat = lookup.ObtainFormat(guideData.Folder, configData.Folder, "Movie Folder Format"),
|
||||
RenameMovies = configData.Movie?.Rename
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
using Recyclarr.Config.Models;
|
||||
using Recyclarr.ServarrApi.MediaNaming;
|
||||
using Recyclarr.TrashGuide.MediaNaming;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases.Config;
|
||||
|
||||
public abstract class ServiceBasedMediaNamingConfigPhase<TConfig> : IServiceBasedMediaNamingConfigPhase
|
||||
where TConfig : IServiceConfiguration
|
||||
{
|
||||
public Task<MediaNamingDto> ProcessNaming(
|
||||
IServiceConfiguration config,
|
||||
IMediaNamingGuideService guide,
|
||||
NamingFormatLookup lookup)
|
||||
{
|
||||
return ProcessNaming((TConfig) config, guide, lookup);
|
||||
}
|
||||
|
||||
protected abstract Task<MediaNamingDto> ProcessNaming(
|
||||
TConfig config,
|
||||
IMediaNamingGuideService guide,
|
||||
NamingFormatLookup lookup);
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
using Recyclarr.Compatibility.Sonarr;
|
||||
using Recyclarr.Config.Models;
|
||||
using Recyclarr.ServarrApi.MediaNaming;
|
||||
using Recyclarr.TrashGuide.MediaNaming;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases.Config;
|
||||
|
||||
public class SonarrMediaNamingConfigPhase : ServiceBasedMediaNamingConfigPhase<SonarrConfiguration>
|
||||
{
|
||||
private readonly ISonarrCapabilityFetcher _sonarrCapabilities;
|
||||
|
||||
public SonarrMediaNamingConfigPhase(ISonarrCapabilityFetcher sonarrCapabilities)
|
||||
{
|
||||
_sonarrCapabilities = sonarrCapabilities;
|
||||
}
|
||||
|
||||
protected override async Task<MediaNamingDto> ProcessNaming(
|
||||
SonarrConfiguration config,
|
||||
IMediaNamingGuideService guide,
|
||||
NamingFormatLookup lookup)
|
||||
{
|
||||
var guideData = guide.GetSonarrNamingData();
|
||||
var configData = config.MediaNaming;
|
||||
var capabilities = await _sonarrCapabilities.GetCapabilities(config);
|
||||
var keySuffix = capabilities.SupportsCustomFormats ? ":4" : ":3";
|
||||
|
||||
return new SonarrMediaNamingDto
|
||||
{
|
||||
SeasonFolderFormat = lookup.ObtainFormat(guideData.Season, configData.Season, "Season Folder Format"),
|
||||
SeriesFolderFormat = lookup.ObtainFormat(guideData.Series, configData.Series, "Series Folder Format"),
|
||||
StandardEpisodeFormat = lookup.ObtainFormat(
|
||||
guideData.Episodes.Standard,
|
||||
configData.Episodes?.Standard,
|
||||
keySuffix,
|
||||
"Standard Episode Format"),
|
||||
DailyEpisodeFormat = lookup.ObtainFormat(
|
||||
guideData.Episodes.Daily,
|
||||
configData.Episodes?.Daily,
|
||||
keySuffix,
|
||||
"Daily Episode Format"),
|
||||
AnimeEpisodeFormat = lookup.ObtainFormat(
|
||||
guideData.Episodes.Anime,
|
||||
configData.Episodes?.Anime,
|
||||
keySuffix,
|
||||
"Anime Episode Format"),
|
||||
RenameEpisodes = configData.Episodes?.Rename
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
using Autofac.Core.Registration;
|
||||
using Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases;
|
||||
using Recyclarr.Common;
|
||||
using Recyclarr.Config.Models;
|
||||
|
||||
namespace Recyclarr.Cli.IntegrationTests.Pipelines;
|
||||
|
||||
[TestFixture]
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
internal class MediaNamingConfigPhaseIntegrationTest : CliIntegrationFixture
|
||||
{
|
||||
private sealed record UnsupportedConfigType : ServiceConfiguration
|
||||
{
|
||||
public override SupportedServices ServiceType => (SupportedServices) 999;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Throw_on_unknown_config_type()
|
||||
{
|
||||
var sut = Resolve<MediaNamingConfigPhase>();
|
||||
var act = () => sut.Execute(new UnsupportedConfigType {InstanceName = ""});
|
||||
await act.Should().ThrowAsync<ComponentNotRegisteredException>();
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
using Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases.Config;
|
||||
|
||||
namespace Recyclarr.Cli.Tests.Pipelines.MediaNaming.PipelinePhases.Config;
|
||||
|
||||
[TestFixture]
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
public class NamingFormatLookupTest
|
||||
{
|
||||
[Test, AutoMockData]
|
||||
public void Assign_null_when_config_null(
|
||||
NamingFormatLookup sut)
|
||||
{
|
||||
var namingData = new Dictionary<string, string>
|
||||
{
|
||||
{"default", "folder_default"},
|
||||
{"plex", "folder_plex"},
|
||||
{"emby", "folder_emby"}
|
||||
};
|
||||
|
||||
var result = sut.ObtainFormat(namingData, null, "");
|
||||
result.Should().BeNull();
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
using Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases.Config;
|
||||
using Recyclarr.Config.Models;
|
||||
using Recyclarr.ServarrApi.MediaNaming;
|
||||
using Recyclarr.TrashGuide.MediaNaming;
|
||||
|
||||
namespace Recyclarr.Cli.Tests.Pipelines.MediaNaming.PipelinePhases.Config;
|
||||
|
||||
[TestFixture]
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
public class RadarrMediaNamingConfigPhaseTest
|
||||
{
|
||||
private static readonly RadarrMediaNamingData RadarrNamingData = new()
|
||||
{
|
||||
Folder = new Dictionary<string, string>
|
||||
{
|
||||
{"default", "folder_default"},
|
||||
{"plex", "folder_plex"},
|
||||
{"emby", "folder_emby"}
|
||||
},
|
||||
File = new Dictionary<string, string>
|
||||
{
|
||||
{"default", "file_default"},
|
||||
{"emby", "file_emby"},
|
||||
{"jellyfin", "file_jellyfin"}
|
||||
}
|
||||
};
|
||||
|
||||
[Test, AutoMockData]
|
||||
public async Task Radarr_naming(
|
||||
[Frozen] IMediaNamingGuideService guide,
|
||||
RadarrMediaNamingConfigPhase sut)
|
||||
{
|
||||
guide.GetRadarrNamingData().Returns(RadarrNamingData);
|
||||
|
||||
var config = new RadarrConfiguration
|
||||
{
|
||||
InstanceName = "radarr",
|
||||
MediaNaming = new RadarrMediaNamingConfig
|
||||
{
|
||||
Folder = "plex",
|
||||
Movie = new RadarrMovieNamingConfig
|
||||
{
|
||||
Rename = true,
|
||||
Standard = "emby"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var result = await sut.ProcessNaming(config, guide, new NamingFormatLookup());
|
||||
|
||||
result.Should().NotBeNull();
|
||||
result.Should().BeEquivalentTo(new RadarrMediaNamingDto
|
||||
{
|
||||
RenameMovies = true,
|
||||
StandardMovieFormat = "file_emby",
|
||||
MovieFolderFormat = "folder_plex"
|
||||
},
|
||||
o => o.RespectingRuntimeTypes());
|
||||
}
|
||||
}
|
@ -0,0 +1,184 @@
|
||||
using Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases;
|
||||
using Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases.Config;
|
||||
using Recyclarr.Compatibility.Sonarr;
|
||||
using Recyclarr.Config.Models;
|
||||
using Recyclarr.ServarrApi.MediaNaming;
|
||||
using Recyclarr.TrashGuide.MediaNaming;
|
||||
|
||||
namespace Recyclarr.Cli.Tests.Pipelines.MediaNaming.PipelinePhases.Config;
|
||||
|
||||
[TestFixture]
|
||||
[Parallelizable(ParallelScope.All)]
|
||||
public class SonarrMediaNamingConfigPhaseTest
|
||||
{
|
||||
private static readonly SonarrMediaNamingData SonarrNamingData = new()
|
||||
{
|
||||
Season = new Dictionary<string, string>
|
||||
{
|
||||
{"default", "season_default"}
|
||||
},
|
||||
Series = new Dictionary<string, string>
|
||||
{
|
||||
{"default", "series_default"},
|
||||
{"plex", "series_plex"},
|
||||
{"emby", "series_emby"}
|
||||
},
|
||||
Episodes = new SonarrEpisodeNamingData
|
||||
{
|
||||
Standard = new Dictionary<string, string>
|
||||
{
|
||||
{"default:3", "episodes_standard_default_3"},
|
||||
{"default:4", "episodes_standard_default_4"},
|
||||
{"original", "episodes_standard_original"}
|
||||
},
|
||||
Daily = new Dictionary<string, string>
|
||||
{
|
||||
{"default:3", "episodes_daily_default_3"},
|
||||
{"default:4", "episodes_daily_default_4"},
|
||||
{"original", "episodes_daily_original"}
|
||||
},
|
||||
Anime = new Dictionary<string, string>
|
||||
{
|
||||
{"default:3", "episodes_anime_default_3"},
|
||||
{"default:4", "episodes_anime_default_4"}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
[Test, AutoMockData]
|
||||
public async Task Sonarr_v3_naming(
|
||||
[Frozen] ISonarrCapabilityFetcher capabilities,
|
||||
[Frozen] IMediaNamingGuideService guide,
|
||||
SonarrMediaNamingConfigPhase sut)
|
||||
{
|
||||
capabilities.GetCapabilities(default!).ReturnsForAnyArgs(new SonarrCapabilities
|
||||
{
|
||||
SupportsCustomFormats = false
|
||||
});
|
||||
|
||||
guide.GetSonarrNamingData().Returns(SonarrNamingData);
|
||||
|
||||
var config = new SonarrConfiguration
|
||||
{
|
||||
InstanceName = "sonarr",
|
||||
MediaNaming = new SonarrMediaNamingConfig
|
||||
{
|
||||
Season = "default",
|
||||
Series = "plex",
|
||||
Episodes = new SonarrEpisodeNamingConfig
|
||||
{
|
||||
Rename = true,
|
||||
Standard = "default",
|
||||
Daily = "default",
|
||||
Anime = "default"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var result = await sut.ProcessNaming(config, guide, new NamingFormatLookup());
|
||||
|
||||
result.Should().NotBeNull();
|
||||
result.Should().BeEquivalentTo(new SonarrMediaNamingDto
|
||||
{
|
||||
RenameEpisodes = true,
|
||||
SeasonFolderFormat = "season_default",
|
||||
SeriesFolderFormat = "series_plex",
|
||||
StandardEpisodeFormat = "episodes_standard_default_3",
|
||||
DailyEpisodeFormat = "episodes_daily_default_3",
|
||||
AnimeEpisodeFormat = "episodes_anime_default_3"
|
||||
});
|
||||
}
|
||||
|
||||
[Test, AutoMockData]
|
||||
public async Task Sonarr_v4_naming(
|
||||
[Frozen] ISonarrCapabilityFetcher capabilities,
|
||||
[Frozen] IMediaNamingGuideService guide,
|
||||
SonarrMediaNamingConfigPhase sut)
|
||||
{
|
||||
capabilities.GetCapabilities(default!).ReturnsForAnyArgs(new SonarrCapabilities
|
||||
{
|
||||
SupportsCustomFormats = true
|
||||
});
|
||||
|
||||
guide.GetSonarrNamingData().Returns(SonarrNamingData);
|
||||
|
||||
var config = new SonarrConfiguration
|
||||
{
|
||||
InstanceName = "sonarr",
|
||||
MediaNaming = new SonarrMediaNamingConfig
|
||||
{
|
||||
Season = "default",
|
||||
Series = "plex",
|
||||
Episodes = new SonarrEpisodeNamingConfig
|
||||
{
|
||||
Rename = true,
|
||||
Standard = "default",
|
||||
Daily = "default",
|
||||
Anime = "default"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var result = await sut.ProcessNaming(config, guide, new NamingFormatLookup());
|
||||
|
||||
result.Should().NotBeNull();
|
||||
result.Should().BeEquivalentTo(new SonarrMediaNamingDto
|
||||
{
|
||||
RenameEpisodes = true,
|
||||
SeasonFolderFormat = "season_default",
|
||||
SeriesFolderFormat = "series_plex",
|
||||
StandardEpisodeFormat = "episodes_standard_default_4",
|
||||
DailyEpisodeFormat = "episodes_daily_default_4",
|
||||
AnimeEpisodeFormat = "episodes_anime_default_4"
|
||||
});
|
||||
}
|
||||
|
||||
[Test, AutoMockData]
|
||||
public async Task Sonarr_invalid_names(
|
||||
[Frozen] ISonarrCapabilityFetcher capabilities,
|
||||
[Frozen] IMediaNamingGuideService guide,
|
||||
SonarrMediaNamingConfigPhase sut)
|
||||
{
|
||||
capabilities.GetCapabilities(default!).ReturnsForAnyArgs(new SonarrCapabilities
|
||||
{
|
||||
SupportsCustomFormats = true
|
||||
});
|
||||
|
||||
guide.GetSonarrNamingData().Returns(SonarrNamingData);
|
||||
|
||||
var config = new SonarrConfiguration
|
||||
{
|
||||
InstanceName = "sonarr",
|
||||
MediaNaming = new SonarrMediaNamingConfig
|
||||
{
|
||||
Season = "bad1",
|
||||
Series = "bad2",
|
||||
Episodes = new SonarrEpisodeNamingConfig
|
||||
{
|
||||
Rename = true,
|
||||
Standard = "bad3",
|
||||
Daily = "bad4",
|
||||
Anime = "bad5"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var lookup = new NamingFormatLookup();
|
||||
var result = await sut.ProcessNaming(config, guide, lookup);
|
||||
|
||||
result.Should().NotBeNull();
|
||||
result.Should().BeEquivalentTo(new SonarrMediaNamingDto
|
||||
{
|
||||
RenameEpisodes = true
|
||||
});
|
||||
|
||||
lookup.Errors.Should().BeEquivalentTo(new[]
|
||||
{
|
||||
new InvalidNamingConfig("Season Folder Format", "bad1"),
|
||||
new InvalidNamingConfig("Series Folder Format", "bad2"),
|
||||
new InvalidNamingConfig("Standard Episode Format", "bad3"),
|
||||
new InvalidNamingConfig("Daily Episode Format", "bad4"),
|
||||
new InvalidNamingConfig("Anime Episode Format", "bad5")
|
||||
});
|
||||
}
|
||||
}
|
@ -1,281 +0,0 @@
|
||||
using Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases;
|
||||
using Recyclarr.Common;
|
||||
using Recyclarr.Compatibility.Sonarr;
|
||||
using Recyclarr.Config.Models;
|
||||
using Recyclarr.ServarrApi.MediaNaming;
|
||||
using Recyclarr.TrashGuide.MediaNaming;
|
||||
|
||||
namespace Recyclarr.Cli.Tests.Pipelines.MediaNaming;
|
||||
|
||||
[TestFixture]
|
||||
public class MediaNamingConfigPhaseTest
|
||||
{
|
||||
private static readonly SonarrMediaNamingData SonarrNamingData = new()
|
||||
{
|
||||
Season = new Dictionary<string, string>
|
||||
{
|
||||
{"default", "season_default"}
|
||||
},
|
||||
Series = new Dictionary<string, string>
|
||||
{
|
||||
{"default", "series_default"},
|
||||
{"plex", "series_plex"},
|
||||
{"emby", "series_emby"}
|
||||
},
|
||||
Episodes = new SonarrEpisodeNamingData
|
||||
{
|
||||
Standard = new Dictionary<string, string>
|
||||
{
|
||||
{"default:3", "episodes_standard_default_3"},
|
||||
{"default:4", "episodes_standard_default_4"},
|
||||
{"original", "episodes_standard_original"}
|
||||
},
|
||||
Daily = new Dictionary<string, string>
|
||||
{
|
||||
{"default:3", "episodes_daily_default_3"},
|
||||
{"default:4", "episodes_daily_default_4"},
|
||||
{"original", "episodes_daily_original"}
|
||||
},
|
||||
Anime = new Dictionary<string, string>
|
||||
{
|
||||
{"default:3", "episodes_anime_default_3"},
|
||||
{"default:4", "episodes_anime_default_4"}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static readonly RadarrMediaNamingData RadarrNamingData = new()
|
||||
{
|
||||
Folder = new Dictionary<string, string>
|
||||
{
|
||||
{"default", "folder_default"},
|
||||
{"plex", "folder_plex"},
|
||||
{"emby", "folder_emby"}
|
||||
},
|
||||
File = new Dictionary<string, string>
|
||||
{
|
||||
{"default", "file_default"},
|
||||
{"emby", "file_emby"},
|
||||
{"jellyfin", "file_jellyfin"}
|
||||
}
|
||||
};
|
||||
|
||||
[Test, AutoMockData]
|
||||
public async Task Sonarr_v3_naming(
|
||||
[Frozen] ISonarrCapabilityFetcher capabilities,
|
||||
[Frozen] IMediaNamingGuideService guide,
|
||||
MediaNamingConfigPhase sut)
|
||||
{
|
||||
capabilities.GetCapabilities(default!).ReturnsForAnyArgs(new SonarrCapabilities
|
||||
{
|
||||
SupportsCustomFormats = false
|
||||
});
|
||||
|
||||
guide.GetSonarrNamingData().Returns(SonarrNamingData);
|
||||
|
||||
var config = new SonarrConfiguration
|
||||
{
|
||||
InstanceName = "sonarr",
|
||||
MediaNaming = new SonarrMediaNamingConfig
|
||||
{
|
||||
Season = "default",
|
||||
Series = "plex",
|
||||
Episodes = new SonarrEpisodeNamingConfig
|
||||
{
|
||||
Rename = true,
|
||||
Standard = "default",
|
||||
Daily = "default",
|
||||
Anime = "default"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var result = await sut.Execute(config);
|
||||
|
||||
result.Should().NotBeNull();
|
||||
result.Should().BeEquivalentTo(new ProcessedNamingConfig
|
||||
{
|
||||
Dto = new SonarrMediaNamingDto
|
||||
{
|
||||
RenameEpisodes = true,
|
||||
SeasonFolderFormat = "season_default",
|
||||
SeriesFolderFormat = "series_plex",
|
||||
StandardEpisodeFormat = "episodes_standard_default_3",
|
||||
DailyEpisodeFormat = "episodes_daily_default_3",
|
||||
AnimeEpisodeFormat = "episodes_anime_default_3"
|
||||
}
|
||||
},
|
||||
o => o.RespectingRuntimeTypes());
|
||||
}
|
||||
|
||||
[Test, AutoMockData]
|
||||
public async Task Sonarr_v4_naming(
|
||||
[Frozen] ISonarrCapabilityFetcher capabilities,
|
||||
[Frozen] IMediaNamingGuideService guide,
|
||||
MediaNamingConfigPhase sut)
|
||||
{
|
||||
capabilities.GetCapabilities(default!).ReturnsForAnyArgs(new SonarrCapabilities
|
||||
{
|
||||
SupportsCustomFormats = true
|
||||
});
|
||||
|
||||
guide.GetSonarrNamingData().Returns(SonarrNamingData);
|
||||
|
||||
var config = new SonarrConfiguration
|
||||
{
|
||||
InstanceName = "sonarr",
|
||||
MediaNaming = new SonarrMediaNamingConfig
|
||||
{
|
||||
Season = "default",
|
||||
Series = "plex",
|
||||
Episodes = new SonarrEpisodeNamingConfig
|
||||
{
|
||||
Rename = true,
|
||||
Standard = "default",
|
||||
Daily = "default",
|
||||
Anime = "default"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var result = await sut.Execute(config);
|
||||
|
||||
result.Should().NotBeNull();
|
||||
result.Should().BeEquivalentTo(new ProcessedNamingConfig
|
||||
{
|
||||
Dto = new SonarrMediaNamingDto
|
||||
{
|
||||
RenameEpisodes = true,
|
||||
SeasonFolderFormat = "season_default",
|
||||
SeriesFolderFormat = "series_plex",
|
||||
StandardEpisodeFormat = "episodes_standard_default_4",
|
||||
DailyEpisodeFormat = "episodes_daily_default_4",
|
||||
AnimeEpisodeFormat = "episodes_anime_default_4"
|
||||
}
|
||||
},
|
||||
o => o.RespectingRuntimeTypes());
|
||||
}
|
||||
|
||||
[Test, AutoMockData]
|
||||
public async Task Sonarr_invalid_names(
|
||||
[Frozen] ISonarrCapabilityFetcher capabilities,
|
||||
[Frozen] IMediaNamingGuideService guide,
|
||||
MediaNamingConfigPhase sut)
|
||||
{
|
||||
capabilities.GetCapabilities(default!).ReturnsForAnyArgs(new SonarrCapabilities
|
||||
{
|
||||
SupportsCustomFormats = true
|
||||
});
|
||||
|
||||
guide.GetSonarrNamingData().Returns(SonarrNamingData);
|
||||
|
||||
var config = new SonarrConfiguration
|
||||
{
|
||||
InstanceName = "sonarr",
|
||||
MediaNaming = new SonarrMediaNamingConfig
|
||||
{
|
||||
Season = "bad1",
|
||||
Series = "bad2",
|
||||
Episodes = new SonarrEpisodeNamingConfig
|
||||
{
|
||||
Rename = true,
|
||||
Standard = "bad3",
|
||||
Daily = "bad4",
|
||||
Anime = "bad5"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var result = await sut.Execute(config);
|
||||
|
||||
result.Should().NotBeNull();
|
||||
result.Should().BeEquivalentTo(new ProcessedNamingConfig
|
||||
{
|
||||
Dto = new SonarrMediaNamingDto
|
||||
{
|
||||
RenameEpisodes = true
|
||||
},
|
||||
InvalidNaming = new[]
|
||||
{
|
||||
new InvalidNamingConfig("Season Folder Format", "bad1"),
|
||||
new InvalidNamingConfig("Series Folder Format", "bad2"),
|
||||
new InvalidNamingConfig("Standard Episode Format", "bad3"),
|
||||
new InvalidNamingConfig("Daily Episode Format", "bad4"),
|
||||
new InvalidNamingConfig("Anime Episode Format", "bad5")
|
||||
}
|
||||
},
|
||||
o => o.RespectingRuntimeTypes());
|
||||
}
|
||||
|
||||
[Test, AutoMockData]
|
||||
public async Task Radarr_naming(
|
||||
[Frozen] IMediaNamingGuideService guide,
|
||||
MediaNamingConfigPhase sut)
|
||||
{
|
||||
guide.GetRadarrNamingData().Returns(RadarrNamingData);
|
||||
|
||||
var config = new RadarrConfiguration
|
||||
{
|
||||
InstanceName = "radarr",
|
||||
MediaNaming = new RadarrMediaNamingConfig
|
||||
{
|
||||
Folder = "plex",
|
||||
Movie = new RadarrMovieNamingConfig
|
||||
{
|
||||
Rename = true,
|
||||
Standard = "emby"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var result = await sut.Execute(config);
|
||||
|
||||
result.Should().NotBeNull();
|
||||
result.Should().BeEquivalentTo(new ProcessedNamingConfig
|
||||
{
|
||||
Dto = new RadarrMediaNamingDto
|
||||
{
|
||||
RenameMovies = true,
|
||||
StandardMovieFormat = "file_emby",
|
||||
MovieFolderFormat = "folder_plex"
|
||||
}
|
||||
},
|
||||
o => o.RespectingRuntimeTypes());
|
||||
}
|
||||
|
||||
private sealed record UnsupportedConfigType : ServiceConfiguration
|
||||
{
|
||||
public override SupportedServices ServiceType => default!;
|
||||
}
|
||||
|
||||
[Test, AutoMockData]
|
||||
public async Task Throw_on_unknown_config_type(
|
||||
MediaNamingConfigPhase sut)
|
||||
{
|
||||
var act = () => sut.Execute(new UnsupportedConfigType {InstanceName = ""});
|
||||
await act.Should().ThrowAsync<ArgumentException>();
|
||||
}
|
||||
|
||||
[Test, AutoMockData]
|
||||
public async Task Assign_null_when_config_null(
|
||||
[Frozen] IMediaNamingGuideService guide,
|
||||
MediaNamingConfigPhase sut)
|
||||
{
|
||||
guide.GetRadarrNamingData().Returns(RadarrNamingData);
|
||||
|
||||
var config = new RadarrConfiguration
|
||||
{
|
||||
InstanceName = "",
|
||||
MediaNaming = new RadarrMediaNamingConfig
|
||||
{
|
||||
Folder = null
|
||||
}
|
||||
};
|
||||
|
||||
var result = await sut.Execute(config);
|
||||
|
||||
result.Should().NotBeNull();
|
||||
result.Dto.Should().BeOfType<RadarrMediaNamingDto>()
|
||||
.Which.MovieFolderFormat.Should().BeNull();
|
||||
}
|
||||
}
|
Loading…
Reference in new issue