New: Detect Kodi .nfo vs Scene .nfo and handle as appropriate. Rename scene .nfo to .nfo-orig only when needed.

This commit is contained in:
Taloth Saldono 2018-03-01 18:29:05 +01:00
parent f0eba619f3
commit d284969379
10 changed files with 238 additions and 23 deletions

View File

@ -0,0 +1,65 @@
using System.IO;
using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using NzbDrone.Core.Extras.Metadata;
using NzbDrone.Core.Extras.Metadata.Consumers.Xbmc;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.Extras.Metadata.Consumers.Xbmc
{
[TestFixture]
public class FindMetadataFileFixture : CoreTest<XbmcMetadata>
{
private Series _series;
[SetUp]
public void Setup()
{
_series = Builder<Series>.CreateNew()
.With(s => s.Path = @"C:\Test\TV\The.Series".AsOsAgnostic())
.Build();
}
[Test]
public void should_return_null_if_filename_is_not_handled()
{
var path = Path.Combine(_series.Path, "file.jpg");
Subject.FindMetadataFile(_series, path).Should().BeNull();
}
[Test]
public void should_return_metadata_for_xbmc_nfo()
{
var path = Path.Combine(_series.Path, "the.series.s01e01.episode.nfo");
Mocker.GetMock<IDetectXbmcNfo>()
.Setup(v => v.IsXbmcNfoFile(path))
.Returns(true);
Subject.FindMetadataFile(_series, path).Type.Should().Be(MetadataType.EpisodeMetadata);
Mocker.GetMock<IDetectXbmcNfo>()
.Verify(v => v.IsXbmcNfoFile(It.IsAny<string>()), Times.Once());
}
[Test]
public void should_return_null_for_scene_nfo()
{
var path = Path.Combine(_series.Path, "the.series.s01e01.episode.nfo");
Mocker.GetMock<IDetectXbmcNfo>()
.Setup(v => v.IsXbmcNfoFile(path))
.Returns(false);
Subject.FindMetadataFile(_series, path).Should().BeNull();
Mocker.GetMock<IDetectXbmcNfo>()
.Verify(v => v.IsXbmcNfoFile(It.IsAny<string>()), Times.Once());
}
}
}

View File

@ -220,6 +220,7 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<Compile Include="Download\TrackedDownloads\TrackedDownloadServiceFixture.cs" />
<Compile Include="Extras\Metadata\Consumers\Xbmc\FindMetadataFileFixture.cs" />
<Compile Include="FluentTest.cs" />
<Compile Include="Framework\CoreTest.cs" />
<Compile Include="Framework\DbTest.cs" />
@ -340,8 +341,8 @@
<Compile Include="Messaging\Commands\CommandEqualityComparerFixture.cs" />
<Compile Include="Messaging\Commands\CommandExecutorFixture.cs" />
<Compile Include="Messaging\Events\EventAggregatorFixture.cs" />
<Compile Include="Metadata\Consumers\Roksbox\FindMetadataFileFixture.cs" />
<Compile Include="Metadata\Consumers\Wdtv\FindMetadataFileFixture.cs" />
<Compile Include="Extras\Metadata\Consumers\Roksbox\FindMetadataFileFixture.cs" />
<Compile Include="Extras\Metadata\Consumers\Wdtv\FindMetadataFileFixture.cs" />
<Compile Include="NotificationTests\PlexClientServiceTest.cs" />
<Compile Include="NotificationTests\ProwlProviderTest.cs" />
<Compile Include="NotificationTests\Xbmc\Http\ActivePlayersFixture.cs" />

View File

@ -18,7 +18,7 @@ namespace NzbDrone.Core.Extras
{
public interface IExtraService
{
void ImportExtraFiles(LocalEpisode localEpisode, EpisodeFile episodeFile, bool isReadOnly);
void ImportEpisode(LocalEpisode localEpisode, EpisodeFile episodeFile, bool isReadOnly);
}
public class ExtraService : IExtraService,
@ -48,15 +48,15 @@ namespace NzbDrone.Core.Extras
_logger = logger;
}
public void ImportExtraFiles(LocalEpisode localEpisode, EpisodeFile episodeFile, bool isReadOnly)
public void ImportEpisode(LocalEpisode localEpisode, EpisodeFile episodeFile, bool isReadOnly)
{
var series = localEpisode.Series;
foreach (var extraFileManager in _extraFileManagers)
{
extraFileManager.CreateAfterEpisodeImport(series, episodeFile);
}
ImportExtraFiles(localEpisode, episodeFile, isReadOnly);
CreateAfterImport(localEpisode.Series, episodeFile);
}
private void ImportExtraFiles(LocalEpisode localEpisode, EpisodeFile episodeFile, bool isReadOnly)
{
if (!_configService.ImportExtraFiles)
{
return;
@ -87,7 +87,7 @@ namespace NzbDrone.Core.Extras
foreach (var extraFileManager in _extraFileManagers)
{
var extension = Path.GetExtension(matchingFilename);
var extraFile = extraFileManager.Import(series, episodeFile, matchingFilename, extension, isReadOnly);
var extraFile = extraFileManager.Import(localEpisode.Series, episodeFile, matchingFilename, extension, isReadOnly);
if (extraFile != null)
{
@ -102,6 +102,14 @@ namespace NzbDrone.Core.Extras
}
}
private void CreateAfterImport(Series series, EpisodeFile episodeFile)
{
foreach (var extraFileManager in _extraFileManagers)
{
extraFileManager.CreateAfterEpisodeImport(series, episodeFile);
}
}
public void Handle(MediaCoversUpdatedEvent message)
{
var series = message.Series;

View File

@ -18,14 +18,17 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
{
public class XbmcMetadata : MetadataBase<XbmcMetadataSettings>
{
private readonly IMapCoversToLocal _mediaCoverService;
private readonly Logger _logger;
private readonly IMapCoversToLocal _mediaCoverService;
private readonly IDetectXbmcNfo _detectNfo;
public XbmcMetadata(IMapCoversToLocal mediaCoverService,
public XbmcMetadata(IDetectXbmcNfo detectNfo,
IMapCoversToLocal mediaCoverService,
Logger logger)
{
_mediaCoverService = mediaCoverService;
_logger = logger;
_mediaCoverService = mediaCoverService;
_detectNfo = detectNfo;
}
private static readonly Regex SeriesImagesRegex = new Regex(@"^(?<type>poster|banner|fanart)\.(?:png|jpg)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
@ -114,7 +117,8 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
if (parseResult != null &&
!parseResult.FullSeason &&
Path.GetExtension(filename).Equals(".nfo", StringComparison.OrdinalIgnoreCase))
Path.GetExtension(filename).Equals(".nfo", StringComparison.OrdinalIgnoreCase) &&
_detectNfo.IsXbmcNfoFile(path))
{
metadata.Type = MetadataType.EpisodeMetadata;
return metadata;
@ -294,6 +298,9 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
}
}
RenameExistingNfo(GetEpisodeMetadataFilename(episodeFile.RelativePath));
return new MetadataFileResult(GetEpisodeMetadataFilename(episodeFile.RelativePath), xmlResult.Trim(Environment.NewLine.ToCharArray()));
}
@ -373,6 +380,11 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
}
}
private void RenameExistingNfo(string nfoFilePath)
{
}
private string GetEpisodeMetadataFilename(string episodeFilePath)
{
return Path.ChangeExtension(episodeFilePath, "nfo");

View File

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using NzbDrone.Common.Disk;
namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
{
public interface IDetectXbmcNfo
{
bool IsXbmcNfoFile(string path);
}
public class XbmcNfoDetector : IDetectXbmcNfo
{
private readonly IDiskProvider _diskProvider;
private readonly Regex _regex = new Regex("<(movie|tvshow|episodedetails|artist|album|musicvideo)>", RegexOptions.Compiled);
public XbmcNfoDetector(IDiskProvider diskProvider)
{
_diskProvider = diskProvider;
}
public bool IsXbmcNfoFile(string path)
{
// Lets make sure we're not reading huge files.
if (_diskProvider.GetFileSize(path) > 10.Megabytes())
{
return false;
}
// Check if it contains some of the kodi/xbmc xml tags
var content = _diskProvider.ReadAllText(path);
return _regex.IsMatch(content);
}
}
}

View File

@ -10,6 +10,7 @@ using NzbDrone.Common.Http;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Extras.Files;
using NzbDrone.Core.Extras.Metadata.Files;
using NzbDrone.Core.Extras.Others;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Tv;
@ -20,6 +21,7 @@ namespace NzbDrone.Core.Extras.Metadata
private readonly IMetadataFactory _metadataFactory;
private readonly ICleanMetadataService _cleanMetadataService;
private readonly IRecycleBinProvider _recycleBinProvider;
private readonly IOtherExtraFileRenamer _otherExtraFileRenamer;
private readonly IDiskTransferService _diskTransferService;
private readonly IDiskProvider _diskProvider;
private readonly IHttpClient _httpClient;
@ -31,6 +33,7 @@ namespace NzbDrone.Core.Extras.Metadata
IDiskProvider diskProvider,
IDiskTransferService diskTransferService,
IRecycleBinProvider recycleBinProvider,
IOtherExtraFileRenamer otherExtraFileRenamer,
IMetadataFactory metadataFactory,
ICleanMetadataService cleanMetadataService,
IHttpClient httpClient,
@ -41,6 +44,7 @@ namespace NzbDrone.Core.Extras.Metadata
{
_metadataFactory = metadataFactory;
_cleanMetadataService = cleanMetadataService;
_otherExtraFileRenamer = otherExtraFileRenamer;
_recycleBinProvider = recycleBinProvider;
_diskTransferService = diskTransferService;
_diskProvider = diskProvider;
@ -91,7 +95,6 @@ namespace NzbDrone.Core.Extras.Metadata
foreach (var consumer in _metadataFactory.Enabled())
{
files.AddIfNotNull(ProcessEpisodeMetadata(consumer, series, episodeFile, new List<MetadataFile>()));
files.AddRange(ProcessEpisodeImages(consumer, series, episodeFile, new List<MetadataFile>()));
}
@ -238,6 +241,8 @@ namespace NzbDrone.Core.Extras.Metadata
var fullPath = Path.Combine(series.Path, episodeMetadata.RelativePath);
_otherExtraFileRenamer.RenameOtherExtraFile(series, fullPath);
var existingMetadata = GetMetadataFile(series, existingMetadataFiles, c => c.Type == MetadataType.EpisodeMetadata &&
c.EpisodeFileId == episodeFile.Id);
@ -292,6 +297,8 @@ namespace NzbDrone.Core.Extras.Metadata
continue;
}
_otherExtraFileRenamer.RenameOtherExtraFile(series, fullPath);
var metadata = GetMetadataFile(series, existingMetadataFiles, c => c.Type == MetadataType.SeriesImage &&
c.RelativePath == image.RelativePath) ??
new MetadataFile
@ -327,6 +334,8 @@ namespace NzbDrone.Core.Extras.Metadata
continue;
}
_otherExtraFileRenamer.RenameOtherExtraFile(series, fullPath);
var metadata = GetMetadataFile(series, existingMetadataFiles, c => c.Type == MetadataType.SeasonImage &&
c.SeasonNumber == season.SeasonNumber &&
c.RelativePath == image.RelativePath) ??
@ -363,6 +372,8 @@ namespace NzbDrone.Core.Extras.Metadata
continue;
}
_otherExtraFileRenamer.RenameOtherExtraFile(series, fullPath);
var existingMetadata = GetMetadataFile(series, existingMetadataFiles, c => c.Type == MetadataType.EpisodeImage &&
c.EpisodeFileId == episodeFile.Id);

View File

@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Extras.Others
{
public interface IOtherExtraFileRenamer
{
void RenameOtherExtraFile(Series series, string path);
}
public class OtherExtraFileRenamer : IOtherExtraFileRenamer
{
private readonly Logger _logger;
private readonly IDiskProvider _diskProvider;
private readonly IRecycleBinProvider _recycleBinProvider;
private readonly ISeriesService _seriesService;
private readonly IOtherExtraFileService _otherExtraFileService;
public OtherExtraFileRenamer(IOtherExtraFileService otherExtraFileService,
ISeriesService seriesService,
IRecycleBinProvider recycleBinProvider,
IDiskProvider diskProvider,
Logger logger)
{
_logger = logger;
_diskProvider = diskProvider;
_recycleBinProvider = recycleBinProvider;
_seriesService = seriesService;
_otherExtraFileService = otherExtraFileService;
}
public void RenameOtherExtraFile(Series series, string path)
{
if (!_diskProvider.FileExists(path))
{
return;
}
var relativePath = series.Path.GetRelativePath(path);
var otherExtraFile = _otherExtraFileService.FindByPath(relativePath);
if (otherExtraFile != null)
{
var newPath = path + "-orig";
// Recycle an existing -orig file.
RemoveOtherExtraFile(series, newPath);
// Rename the file to .*-orig
_diskProvider.MoveFile(path, newPath);
otherExtraFile.RelativePath = relativePath + "-orig";
otherExtraFile.Extension += "-orig";
_otherExtraFileService.Upsert(otherExtraFile);
}
}
private void RemoveOtherExtraFile(Series series, string path)
{
if (!_diskProvider.FileExists(path))
{
return;
}
var relativePath = series.Path.GetRelativePath(path);
var otherExtraFile = _otherExtraFileService.FindByPath(relativePath);
if (otherExtraFile != null)
{
var subfolder = Path.GetDirectoryName(relativePath);
_recycleBinProvider.DeleteFile(path, subfolder);
}
}
}
}

View File

@ -65,12 +65,6 @@ namespace NzbDrone.Core.Extras.Others
public override ExtraFile Import(Series series, EpisodeFile episodeFile, string path, string extension, bool readOnly)
{
// If the extension is .nfo we need to change it to .nfo-orig
if (Path.GetExtension(path).Equals(".nfo", StringComparison.OrdinalIgnoreCase))
{
extension += "-orig";
}
var extraFile = ImportFile(series, episodeFile, path, readOnly, extension, null);
_otherExtraFileService.Upsert(extraFile);

View File

@ -117,7 +117,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
if (newDownload)
{
_extraService.ImportExtraFiles(localEpisode, episodeFile, copyOnly);
_extraService.ImportEpisode(localEpisode, episodeFile, copyOnly);
}
_eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile, oldFiles, newDownload, downloadClientItem));

View File

@ -554,6 +554,7 @@
<Compile Include="Extras\IImportExistingExtraFiles.cs" />
<Compile Include="Extras\ImportExistingExtraFileFilterResult.cs" />
<Compile Include="Extras\ImportExistingExtraFilesBase.cs" />
<Compile Include="Extras\Metadata\Consumers\Xbmc\XbmcNfoDetector.cs" />
<Compile Include="Extras\Metadata\Files\MetadataFile.cs" />
<Compile Include="Extras\Metadata\Files\MetadataFileRepository.cs" />
<Compile Include="Extras\Metadata\Files\MetadataFileService.cs" />
@ -562,6 +563,7 @@
<Compile Include="Extras\Others\OtherExtraFileService.cs" />
<Compile Include="Extras\Others\OtherExtraFile.cs" />
<Compile Include="Extras\Others\OtherExtraService.cs" />
<Compile Include="Extras\Others\OtherExtraFileRenamer.cs" />
<Compile Include="Extras\Subtitles\ExistingSubtitleImporter.cs" />
<Compile Include="Extras\Subtitles\SubtitleFileRepository.cs" />
<Compile Include="Extras\Subtitles\SubtitleFileService.cs" />