From b03b3d82437d4f8ca18745da77c595a007b1c9c5 Mon Sep 17 00:00:00 2001 From: Qstick Date: Mon, 19 Mar 2018 21:38:02 -0400 Subject: [PATCH] Fixed: Detect Kodi nfo vs. Scene nfo. Other extras fixes Fixes #240 Co-Authored-By: taloth --- .../Roksbox/FindMetadataFileFixture.cs | 2 +- .../Consumers/Wdtv/FindMetadataFileFixture.cs | 2 +- .../Consumers/Xbmc/FindMetadataFileFixture.cs | 65 +++++++++ .../NzbDrone.Core.Test.csproj | 5 +- src/NzbDrone.Core/Extras/ExtraService.cs | 24 ++-- .../Extras/Files/ExtraFileService.cs | 16 +-- .../Metadata/Consumers/Xbmc/XbmcMetadata.cs | 123 ++---------------- .../Consumers/Xbmc/XbmcMetadataSettings.cs | 8 +- .../Consumers/Xbmc/XbmcNfoDetector.cs | 40 ++++++ .../Metadata/Files/MetadataFileService.cs | 2 - .../Extras/Metadata/MetadataService.cs | 21 ++- .../Extras/Others/OtherExtraFileRenamer.cs | 82 ++++++++++++ .../Extras/Others/OtherExtraService.cs | 6 - .../TrackImport/ImportApprovedTracks.cs | 2 +- src/NzbDrone.Core/NzbDrone.Core.csproj | 2 + 15 files changed, 248 insertions(+), 152 deletions(-) rename src/NzbDrone.Core.Test/{ => Extras}/Metadata/Consumers/Roksbox/FindMetadataFileFixture.cs (97%) rename src/NzbDrone.Core.Test/{ => Extras}/Metadata/Consumers/Wdtv/FindMetadataFileFixture.cs (97%) create mode 100644 src/NzbDrone.Core.Test/Extras/Metadata/Consumers/Xbmc/FindMetadataFileFixture.cs create mode 100644 src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcNfoDetector.cs create mode 100644 src/NzbDrone.Core/Extras/Others/OtherExtraFileRenamer.cs diff --git a/src/NzbDrone.Core.Test/Metadata/Consumers/Roksbox/FindMetadataFileFixture.cs b/src/NzbDrone.Core.Test/Extras/Metadata/Consumers/Roksbox/FindMetadataFileFixture.cs similarity index 97% rename from src/NzbDrone.Core.Test/Metadata/Consumers/Roksbox/FindMetadataFileFixture.cs rename to src/NzbDrone.Core.Test/Extras/Metadata/Consumers/Roksbox/FindMetadataFileFixture.cs index 5e47ee97c..c295ed6de 100644 --- a/src/NzbDrone.Core.Test/Metadata/Consumers/Roksbox/FindMetadataFileFixture.cs +++ b/src/NzbDrone.Core.Test/Extras/Metadata/Consumers/Roksbox/FindMetadataFileFixture.cs @@ -8,7 +8,7 @@ using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Music; using NzbDrone.Test.Common; -namespace NzbDrone.Core.Test.Metadata.Consumers.Roksbox +namespace NzbDrone.Core.Test.Extras.Metadata.Consumers.Roksbox { [TestFixture] public class FindMetadataFileFixture : CoreTest diff --git a/src/NzbDrone.Core.Test/Metadata/Consumers/Wdtv/FindMetadataFileFixture.cs b/src/NzbDrone.Core.Test/Extras/Metadata/Consumers/Wdtv/FindMetadataFileFixture.cs similarity index 97% rename from src/NzbDrone.Core.Test/Metadata/Consumers/Wdtv/FindMetadataFileFixture.cs rename to src/NzbDrone.Core.Test/Extras/Metadata/Consumers/Wdtv/FindMetadataFileFixture.cs index 1c1ac264b..bae637d7c 100644 --- a/src/NzbDrone.Core.Test/Metadata/Consumers/Wdtv/FindMetadataFileFixture.cs +++ b/src/NzbDrone.Core.Test/Extras/Metadata/Consumers/Wdtv/FindMetadataFileFixture.cs @@ -8,7 +8,7 @@ using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Music; using NzbDrone.Test.Common; -namespace NzbDrone.Core.Test.Metadata.Consumers.Wdtv +namespace NzbDrone.Core.Test.Extras.Metadata.Consumers.Wdtv { [TestFixture] public class FindMetadataFileFixture : CoreTest diff --git a/src/NzbDrone.Core.Test/Extras/Metadata/Consumers/Xbmc/FindMetadataFileFixture.cs b/src/NzbDrone.Core.Test/Extras/Metadata/Consumers/Xbmc/FindMetadataFileFixture.cs new file mode 100644 index 000000000..dd335843e --- /dev/null +++ b/src/NzbDrone.Core.Test/Extras/Metadata/Consumers/Xbmc/FindMetadataFileFixture.cs @@ -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.Music; +using NzbDrone.Test.Common; + +namespace NzbDrone.Core.Test.Extras.Metadata.Consumers.Xbmc +{ + [TestFixture] + public class FindMetadataFileFixture : CoreTest + { + private Artist _artist; + + [SetUp] + public void Setup() + { + _artist = Builder.CreateNew() + .With(s => s.Path = @"C:\Test\Music\The.Artist".AsOsAgnostic()) + .Build(); + } + + [Test] + public void should_return_null_if_filename_is_not_handled() + { + var path = Path.Combine(_artist.Path, "file.jpg"); + + Subject.FindMetadataFile(_artist, path).Should().BeNull(); + } + + [Test] + public void should_return_metadata_for_xbmc_nfo() + { + var path = Path.Combine(_artist.Path, "album.nfo"); + + Mocker.GetMock() + .Setup(v => v.IsXbmcNfoFile(path)) + .Returns(true); + + Subject.FindMetadataFile(_artist, path).Type.Should().Be(MetadataType.AlbumMetadata); + + Mocker.GetMock() + .Verify(v => v.IsXbmcNfoFile(It.IsAny()), Times.Once()); + } + + [Test] + public void should_return_null_for_scene_nfo() + { + var path = Path.Combine(_artist.Path, "album.nfo"); + + Mocker.GetMock() + .Setup(v => v.IsXbmcNfoFile(path)) + .Returns(false); + + Subject.FindMetadataFile(_artist, path).Should().BeNull(); + + Mocker.GetMock() + .Verify(v => v.IsXbmcNfoFile(It.IsAny()), Times.Once()); + } + } +} diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index a0b9d9b8e..e01f3dc9c 100644 --- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -194,6 +194,7 @@ Always + @@ -324,8 +325,8 @@ - - + + diff --git a/src/NzbDrone.Core/Extras/ExtraService.cs b/src/NzbDrone.Core/Extras/ExtraService.cs index 85604773c..ced94df47 100644 --- a/src/NzbDrone.Core/Extras/ExtraService.cs +++ b/src/NzbDrone.Core/Extras/ExtraService.cs @@ -18,7 +18,7 @@ namespace NzbDrone.Core.Extras { public interface IExtraService { - void ImportExtraFiles(LocalTrack localEpisode, TrackFile episodeFile, bool isReadOnly); + void ImportTrack(LocalTrack localTrack, TrackFile trackFile, bool isReadOnly); } public class ExtraService : IExtraService, @@ -51,15 +51,15 @@ namespace NzbDrone.Core.Extras _logger = logger; } - public void ImportExtraFiles(LocalTrack localTrack, TrackFile trackFile, bool isReadOnly) + public void ImportTrack(LocalTrack localTrack, TrackFile trackFile, bool isReadOnly) { - var artist = localTrack.Artist; + ImportExtraFiles(localTrack, trackFile, isReadOnly); - foreach (var extraFileManager in _extraFileManagers) - { - extraFileManager.CreateAfterTrackImport(artist, trackFile); - } + CreateAfterImport(localTrack.Artist, trackFile); + } + public void ImportExtraFiles(LocalTrack localTrack, TrackFile trackFile, bool isReadOnly) + { if (!_configService.ImportExtraFiles) { return; @@ -90,7 +90,7 @@ namespace NzbDrone.Core.Extras foreach (var extraFileManager in _extraFileManagers) { var extension = Path.GetExtension(matchingFilename); - var extraFile = extraFileManager.Import(artist, trackFile, matchingFilename, extension, isReadOnly); + var extraFile = extraFileManager.Import(localTrack.Artist, trackFile, matchingFilename, extension, isReadOnly); if (extraFile != null) { @@ -105,6 +105,14 @@ namespace NzbDrone.Core.Extras } } + private void CreateAfterImport(Artist artist, TrackFile trackFile) + { + foreach (var extraFileManager in _extraFileManagers) + { + extraFileManager.CreateAfterTrackImport(artist, trackFile); + } + } + public void Handle(MediaCoversUpdatedEvent message) { var artist = message.Artist; diff --git a/src/NzbDrone.Core/Extras/Files/ExtraFileService.cs b/src/NzbDrone.Core/Extras/Files/ExtraFileService.cs index 8f7f10acd..1a74a1545 100644 --- a/src/NzbDrone.Core/Extras/Files/ExtraFileService.cs +++ b/src/NzbDrone.Core/Extras/Files/ExtraFileService.cs @@ -49,8 +49,6 @@ namespace NzbDrone.Core.Extras.Files _logger = logger; } - public virtual bool PermanentlyDelete => false; - public List GetFilesByArtist(int artistId) { return _repository.GetFilesByArtist(artistId); @@ -122,17 +120,9 @@ namespace NzbDrone.Core.Extras.Files if (_diskProvider.FileExists(path)) { - if (PermanentlyDelete) - { - _diskProvider.DeleteFile(path); - } - - else - { - // Send extra files to the recycling bin so they can be recovered if necessary - var subfolder = _diskProvider.GetParentFolder(artist.Path).GetRelativePath(_diskProvider.GetParentFolder(path)); - _recycleBinProvider.DeleteFile(path, subfolder); - } + // Send to the recycling bin so they can be recovered if necessary + var subfolder = _diskProvider.GetParentFolder(artist.Path).GetRelativePath(_diskProvider.GetParentFolder(path)); + _recycleBinProvider.DeleteFile(path, subfolder); } } } diff --git a/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadata.cs b/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadata.cs index 747a20920..61064f306 100644 --- a/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadata.cs +++ b/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadata.cs @@ -17,14 +17,17 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc { public class XbmcMetadata : MetadataBase { - 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 ArtistImagesRegex = new Regex(@"^(?poster|banner|fanart|logo)\.(?:png|jpg|jpeg)", RegexOptions.Compiled | RegexOptions.IgnoreCase); @@ -72,27 +75,22 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc return metadata; } - if (filename.Equals("artist.nfo", StringComparison.OrdinalIgnoreCase)) + var isXbmcNfoFile = _detectNfo.IsXbmcNfoFile(path); + + if (filename.Equals("artist.nfo", StringComparison.OrdinalIgnoreCase) && + isXbmcNfoFile) { metadata.Type = MetadataType.ArtistMetadata; return metadata; } - if (filename.Equals("album.nfo", StringComparison.OrdinalIgnoreCase)) + if (filename.Equals("album.nfo", StringComparison.OrdinalIgnoreCase) && + isXbmcNfoFile) { metadata.Type = MetadataType.AlbumMetadata; return metadata; } - var parseResult = Parser.Parser.ParseMusicTitle(filename); - - if (parseResult != null && - Path.GetExtension(filename).Equals(".nfo", StringComparison.OrdinalIgnoreCase)) - { - metadata.Type = MetadataType.TrackMetadata; - return metadata; - } - return null; } @@ -196,93 +194,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc public override MetadataFileResult TrackMetadata(Artist artist, TrackFile trackFile) { - if (!Settings.TrackMetadata) - { - return null; - } - - _logger.Debug("Generating Track Metadata for: {0}", Path.Combine(artist.Path, trackFile.RelativePath)); - - var xmlResult = string.Empty; - foreach (var episode in trackFile.Tracks.Value) - { - var sb = new StringBuilder(); - var xws = new XmlWriterSettings(); - xws.OmitXmlDeclaration = true; - xws.Indent = false; - - using (var xw = XmlWriter.Create(sb, xws)) - { - var doc = new XDocument(); - - var details = new XElement("episodedetails"); - details.Add(new XElement("title", episode.Title)); - details.Add(new XElement("episode", episode.TrackNumber)); - - //If trakt ever gets airs before information for specials we should add set it - details.Add(new XElement("displayseason")); - details.Add(new XElement("displayepisode")); - - details.Add(new XElement("watched", "false")); - - if (episode.Ratings != null && episode.Ratings.Votes > 0) - { - details.Add(new XElement("rating", episode.Ratings.Value)); - } - - if (trackFile.MediaInfo != null) - { - var fileInfo = new XElement("fileinfo"); - var streamDetails = new XElement("streamdetails"); - - var video = new XElement("video"); - video.Add(new XElement("aspect", (float)trackFile.MediaInfo.Width / (float)trackFile.MediaInfo.Height)); - video.Add(new XElement("bitrate", trackFile.MediaInfo.VideoBitrate)); - video.Add(new XElement("codec", trackFile.MediaInfo.VideoCodec)); - video.Add(new XElement("framerate", trackFile.MediaInfo.VideoFps)); - video.Add(new XElement("height", trackFile.MediaInfo.Height)); - video.Add(new XElement("scantype", trackFile.MediaInfo.ScanType)); - video.Add(new XElement("width", trackFile.MediaInfo.Width)); - - if (trackFile.MediaInfo.RunTime != null) - { - video.Add(new XElement("duration", trackFile.MediaInfo.RunTime.TotalMinutes)); - video.Add(new XElement("durationinseconds", trackFile.MediaInfo.RunTime.TotalSeconds)); - } - - streamDetails.Add(video); - - var audio = new XElement("audio"); - audio.Add(new XElement("bitrate", trackFile.MediaInfo.AudioBitrate)); - audio.Add(new XElement("channels", trackFile.MediaInfo.AudioChannels)); - audio.Add(new XElement("codec", GetAudioCodec(trackFile.MediaInfo.AudioFormat))); - audio.Add(new XElement("language", trackFile.MediaInfo.AudioLanguages)); - streamDetails.Add(audio); - - if (trackFile.MediaInfo.Subtitles != null && trackFile.MediaInfo.Subtitles.Length > 0) - { - var subtitle = new XElement("subtitle"); - subtitle.Add(new XElement("language", trackFile.MediaInfo.Subtitles)); - streamDetails.Add(subtitle); - } - - fileInfo.Add(streamDetails); - details.Add(fileInfo); - } - - //Todo: get guest stars, writer and director - //details.Add(new XElement("credits", tvdbEpisode.Writer.FirstOrDefault())); - //details.Add(new XElement("director", tvdbEpisode.Directors.FirstOrDefault())); - - doc.Add(details); - doc.Save(xw); - - xmlResult += doc.ToString(); - xmlResult += Environment.NewLine; - } - } - - return new MetadataFileResult(GetTrackMetadataFilename(trackFile.RelativePath), xmlResult.Trim(Environment.NewLine.ToCharArray())); + return null; } public override List ArtistImages(Artist artist) @@ -339,14 +251,5 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc return Path.ChangeExtension(trackFilePath, "nfo"); } - private string GetAudioCodec(string audioCodec) - { - if (audioCodec == "AC-3") - { - return "AC3"; - } - - return audioCodec; - } } } diff --git a/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadataSettings.cs b/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadataSettings.cs index 6879ae79e..102803695 100644 --- a/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadataSettings.cs +++ b/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcMetadataSettings.cs @@ -17,20 +17,16 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc { ArtistMetadata = true; AlbumMetadata = true; - TrackMetadata = true; ArtistImages = true; AlbumImages = true; } - [FieldDefinition(0, Label = "Artist Metadata", Type = FieldType.Checkbox)] + [FieldDefinition(0, Label = "Artist Metadata", Type = FieldType.Checkbox, HelpText = "artist.nfo")] public bool ArtistMetadata { get; set; } - [FieldDefinition(1, Label = "Album Metadata", Type = FieldType.Checkbox)] + [FieldDefinition(1, Label = "Album Metadata", Type = FieldType.Checkbox, HelpText = "album.nfo")] public bool AlbumMetadata { get; set; } - [FieldDefinition(2, Label = "Track Metadata", Type = FieldType.Checkbox)] - public bool TrackMetadata { get; set; } - [FieldDefinition(3, Label = "Artist Images", Type = FieldType.Checkbox)] public bool ArtistImages { get; set; } diff --git a/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcNfoDetector.cs b/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcNfoDetector.cs new file mode 100644 index 000000000..234d27f22 --- /dev/null +++ b/src/NzbDrone.Core/Extras/Metadata/Consumers/Xbmc/XbmcNfoDetector.cs @@ -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); + } + } +} diff --git a/src/NzbDrone.Core/Extras/Metadata/Files/MetadataFileService.cs b/src/NzbDrone.Core/Extras/Metadata/Files/MetadataFileService.cs index 571fec828..7789cfe44 100644 --- a/src/NzbDrone.Core/Extras/Metadata/Files/MetadataFileService.cs +++ b/src/NzbDrone.Core/Extras/Metadata/Files/MetadataFileService.cs @@ -16,7 +16,5 @@ namespace NzbDrone.Core.Extras.Metadata.Files : base(repository, artistService, diskProvider, recycleBinProvider, logger) { } - - public override bool PermanentlyDelete => true; } } diff --git a/src/NzbDrone.Core/Extras/Metadata/MetadataService.cs b/src/NzbDrone.Core/Extras/Metadata/MetadataService.cs index ca66db98d..8caaa0bc1 100644 --- a/src/NzbDrone.Core/Extras/Metadata/MetadataService.cs +++ b/src/NzbDrone.Core/Extras/Metadata/MetadataService.cs @@ -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.Music; using NzbDrone.Core.Organizer; @@ -20,6 +21,8 @@ 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 +34,8 @@ namespace NzbDrone.Core.Extras.Metadata public MetadataService(IConfigService configService, IDiskProvider diskProvider, IDiskTransferService diskTransferService, + IRecycleBinProvider recycleBinProvider, + IOtherExtraFileRenamer otherExtraFileRenamer, IMetadataFactory metadataFactory, ICleanMetadataService cleanMetadataService, IHttpClient httpClient, @@ -42,6 +47,8 @@ namespace NzbDrone.Core.Extras.Metadata { _metadataFactory = metadataFactory; _cleanMetadataService = cleanMetadataService; + _otherExtraFileRenamer = otherExtraFileRenamer; + _recycleBinProvider = recycleBinProvider; _diskTransferService = diskTransferService; _diskProvider = diskProvider; _httpClient = httpClient; @@ -249,6 +256,8 @@ namespace NzbDrone.Core.Extras.Metadata var fullPath = Path.Combine(artist.Path, artistMetadata.RelativePath); + _otherExtraFileRenamer.RenameOtherExtraFile(artist, fullPath); + _logger.Debug("Writing Artist Metadata to: {0}", fullPath); SaveMetadataFile(fullPath, artistMetadata.Contents); @@ -293,6 +302,8 @@ namespace NzbDrone.Core.Extras.Metadata var fullPath = Path.Combine(artist.Path, albumMetadata.RelativePath); + _otherExtraFileRenamer.RenameOtherExtraFile(artist, fullPath); + _logger.Debug("Writing Album Metadata to: {0}", fullPath); SaveMetadataFile(fullPath, albumMetadata.Contents); @@ -314,6 +325,8 @@ namespace NzbDrone.Core.Extras.Metadata var fullPath = Path.Combine(artist.Path, trackMetadata.RelativePath); + _otherExtraFileRenamer.RenameOtherExtraFile(artist, fullPath); + var existingMetadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.TrackMetadata && c.TrackFileId == trackFile.Id); @@ -368,6 +381,8 @@ namespace NzbDrone.Core.Extras.Metadata continue; } + _otherExtraFileRenamer.RenameOtherExtraFile(artist, fullPath); + var metadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.ArtistImage && c.RelativePath == image.RelativePath) ?? new MetadataFile @@ -401,6 +416,8 @@ namespace NzbDrone.Core.Extras.Metadata continue; } + _otherExtraFileRenamer.RenameOtherExtraFile(artist, fullPath); + var metadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.AlbumImage && c.AlbumId == album.Id && c.RelativePath == image.RelativePath) ?? @@ -471,10 +488,10 @@ namespace NzbDrone.Core.Extras.Metadata _logger.Debug("Removing duplicate Metadata file: {0}", path); - _diskProvider.DeleteFile(path); + var subfolder = _diskProvider.GetParentFolder(artist.Path).GetRelativePath(_diskProvider.GetParentFolder(path)); + _recycleBinProvider.DeleteFile(path, subfolder); _metadataFileService.Delete(file.Id); } - return matchingMetadataFiles.First(); } diff --git a/src/NzbDrone.Core/Extras/Others/OtherExtraFileRenamer.cs b/src/NzbDrone.Core/Extras/Others/OtherExtraFileRenamer.cs new file mode 100644 index 000000000..8231f9563 --- /dev/null +++ b/src/NzbDrone.Core/Extras/Others/OtherExtraFileRenamer.cs @@ -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.Music; + +namespace NzbDrone.Core.Extras.Others +{ + public interface IOtherExtraFileRenamer + { + void RenameOtherExtraFile(Artist artist, string path); + } + + public class OtherExtraFileRenamer : IOtherExtraFileRenamer + { + private readonly Logger _logger; + private readonly IDiskProvider _diskProvider; + private readonly IRecycleBinProvider _recycleBinProvider; + private readonly IArtistService _artistService; + private readonly IOtherExtraFileService _otherExtraFileService; + + public OtherExtraFileRenamer(IOtherExtraFileService otherExtraFileService, + IArtistService artistService, + IRecycleBinProvider recycleBinProvider, + IDiskProvider diskProvider, + Logger logger) + { + _logger = logger; + _diskProvider = diskProvider; + _recycleBinProvider = recycleBinProvider; + _artistService = artistService; + _otherExtraFileService = otherExtraFileService; + } + + public void RenameOtherExtraFile(Artist artist, string path) + { + if (!_diskProvider.FileExists(path)) + { + return; + } + + var relativePath = artist.Path.GetRelativePath(path); + + var otherExtraFile = _otherExtraFileService.FindByPath(relativePath); + if (otherExtraFile != null) + { + var newPath = path + "-orig"; + + // Recycle an existing -orig file. + RemoveOtherExtraFile(artist, newPath); + + // Rename the file to .*-orig + _diskProvider.MoveFile(path, newPath); + otherExtraFile.RelativePath = relativePath + "-orig"; + otherExtraFile.Extension += "-orig"; + _otherExtraFileService.Upsert(otherExtraFile); + } + } + + private void RemoveOtherExtraFile(Artist artist, string path) + { + if (!_diskProvider.FileExists(path)) + { + return; + } + + var relativePath = artist.Path.GetRelativePath(path); + + var otherExtraFile = _otherExtraFileService.FindByPath(relativePath); + if (otherExtraFile != null) + { + var subfolder = Path.GetDirectoryName(relativePath); + _recycleBinProvider.DeleteFile(path, subfolder); + } + } + } +} diff --git a/src/NzbDrone.Core/Extras/Others/OtherExtraService.cs b/src/NzbDrone.Core/Extras/Others/OtherExtraService.cs index 609740978..2c4dbaa20 100644 --- a/src/NzbDrone.Core/Extras/Others/OtherExtraService.cs +++ b/src/NzbDrone.Core/Extras/Others/OtherExtraService.cs @@ -65,12 +65,6 @@ namespace NzbDrone.Core.Extras.Others public override ExtraFile Import(Artist artist, TrackFile trackFile, 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(artist, trackFile, path, readOnly, extension, null); _otherExtraFileService.Upsert(extraFile); diff --git a/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs index 5bc14858b..add47d573 100644 --- a/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs +++ b/src/NzbDrone.Core/MediaFiles/TrackImport/ImportApprovedTracks.cs @@ -127,7 +127,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport if (newDownload) { - _extraService.ImportExtraFiles(localTrack, trackFile, copyOnly); + _extraService.ImportTrack(localTrack, trackFile, copyOnly); } _eventAggregator.PublishEvent(new TrackImportedEvent(localTrack, trackFile, oldFiles, newDownload, downloadClientItem)); diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj index 400c4c766..137712f62 100644 --- a/src/NzbDrone.Core/NzbDrone.Core.csproj +++ b/src/NzbDrone.Core/NzbDrone.Core.csproj @@ -440,10 +440,12 @@ + +