mirror of https://github.com/lidarr/Lidarr
Fixed: Detect Kodi nfo vs. Scene nfo. Other extras fixes
Fixes #240 Co-Authored-By: taloth <taloth@users.noreply.github.com>
This commit is contained in:
parent
9d056006cc
commit
b03b3d8243
|
@ -8,7 +8,7 @@ using NzbDrone.Core.Test.Framework;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
using NzbDrone.Test.Common;
|
using NzbDrone.Test.Common;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.Metadata.Consumers.Roksbox
|
namespace NzbDrone.Core.Test.Extras.Metadata.Consumers.Roksbox
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class FindMetadataFileFixture : CoreTest<RoksboxMetadata>
|
public class FindMetadataFileFixture : CoreTest<RoksboxMetadata>
|
|
@ -8,7 +8,7 @@ using NzbDrone.Core.Test.Framework;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
using NzbDrone.Test.Common;
|
using NzbDrone.Test.Common;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Test.Metadata.Consumers.Wdtv
|
namespace NzbDrone.Core.Test.Extras.Metadata.Consumers.Wdtv
|
||||||
{
|
{
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class FindMetadataFileFixture : CoreTest<WdtvMetadata>
|
public class FindMetadataFileFixture : CoreTest<WdtvMetadata>
|
|
@ -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<XbmcMetadata>
|
||||||
|
{
|
||||||
|
private Artist _artist;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_artist = Builder<Artist>.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<IDetectXbmcNfo>()
|
||||||
|
.Setup(v => v.IsXbmcNfoFile(path))
|
||||||
|
.Returns(true);
|
||||||
|
|
||||||
|
Subject.FindMetadataFile(_artist, path).Type.Should().Be(MetadataType.AlbumMetadata);
|
||||||
|
|
||||||
|
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(_artist.Path, "album.nfo");
|
||||||
|
|
||||||
|
Mocker.GetMock<IDetectXbmcNfo>()
|
||||||
|
.Setup(v => v.IsXbmcNfoFile(path))
|
||||||
|
.Returns(false);
|
||||||
|
|
||||||
|
Subject.FindMetadataFile(_artist, path).Should().BeNull();
|
||||||
|
|
||||||
|
Mocker.GetMock<IDetectXbmcNfo>()
|
||||||
|
.Verify(v => v.IsXbmcNfoFile(It.IsAny<string>()), Times.Once());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -194,6 +194,7 @@
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
<Compile Include="Download\TrackedDownloads\TrackedDownloadServiceFixture.cs" />
|
<Compile Include="Download\TrackedDownloads\TrackedDownloadServiceFixture.cs" />
|
||||||
|
<Compile Include="Extras\Metadata\Consumers\Xbmc\FindMetadataFileFixture.cs" />
|
||||||
<Compile Include="FluentTest.cs" />
|
<Compile Include="FluentTest.cs" />
|
||||||
<Compile Include="Framework\CoreTest.cs" />
|
<Compile Include="Framework\CoreTest.cs" />
|
||||||
<Compile Include="Framework\DbTest.cs" />
|
<Compile Include="Framework\DbTest.cs" />
|
||||||
|
@ -324,8 +325,8 @@
|
||||||
<Compile Include="Messaging\Commands\CommandEqualityComparerFixture.cs" />
|
<Compile Include="Messaging\Commands\CommandEqualityComparerFixture.cs" />
|
||||||
<Compile Include="Messaging\Commands\CommandExecutorFixture.cs" />
|
<Compile Include="Messaging\Commands\CommandExecutorFixture.cs" />
|
||||||
<Compile Include="Messaging\Events\EventAggregatorFixture.cs" />
|
<Compile Include="Messaging\Events\EventAggregatorFixture.cs" />
|
||||||
<Compile Include="Metadata\Consumers\Roksbox\FindMetadataFileFixture.cs" />
|
<Compile Include="Extras\Metadata\Consumers\Roksbox\FindMetadataFileFixture.cs" />
|
||||||
<Compile Include="Metadata\Consumers\Wdtv\FindMetadataFileFixture.cs" />
|
<Compile Include="Extras\Metadata\Consumers\Wdtv\FindMetadataFileFixture.cs" />
|
||||||
<Compile Include="NotificationTests\PlexClientServiceTest.cs" />
|
<Compile Include="NotificationTests\PlexClientServiceTest.cs" />
|
||||||
<Compile Include="NotificationTests\ProwlProviderTest.cs" />
|
<Compile Include="NotificationTests\ProwlProviderTest.cs" />
|
||||||
<Compile Include="NotificationTests\Xbmc\Http\ActivePlayersFixture.cs" />
|
<Compile Include="NotificationTests\Xbmc\Http\ActivePlayersFixture.cs" />
|
||||||
|
|
|
@ -18,7 +18,7 @@ namespace NzbDrone.Core.Extras
|
||||||
{
|
{
|
||||||
public interface IExtraService
|
public interface IExtraService
|
||||||
{
|
{
|
||||||
void ImportExtraFiles(LocalTrack localEpisode, TrackFile episodeFile, bool isReadOnly);
|
void ImportTrack(LocalTrack localTrack, TrackFile trackFile, bool isReadOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ExtraService : IExtraService,
|
public class ExtraService : IExtraService,
|
||||||
|
@ -51,15 +51,15 @@ namespace NzbDrone.Core.Extras
|
||||||
_logger = logger;
|
_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)
|
CreateAfterImport(localTrack.Artist, trackFile);
|
||||||
{
|
|
||||||
extraFileManager.CreateAfterTrackImport(artist, trackFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ImportExtraFiles(LocalTrack localTrack, TrackFile trackFile, bool isReadOnly)
|
||||||
|
{
|
||||||
if (!_configService.ImportExtraFiles)
|
if (!_configService.ImportExtraFiles)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
@ -90,7 +90,7 @@ namespace NzbDrone.Core.Extras
|
||||||
foreach (var extraFileManager in _extraFileManagers)
|
foreach (var extraFileManager in _extraFileManagers)
|
||||||
{
|
{
|
||||||
var extension = Path.GetExtension(matchingFilename);
|
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)
|
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)
|
public void Handle(MediaCoversUpdatedEvent message)
|
||||||
{
|
{
|
||||||
var artist = message.Artist;
|
var artist = message.Artist;
|
||||||
|
|
|
@ -49,8 +49,6 @@ namespace NzbDrone.Core.Extras.Files
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool PermanentlyDelete => false;
|
|
||||||
|
|
||||||
public List<TExtraFile> GetFilesByArtist(int artistId)
|
public List<TExtraFile> GetFilesByArtist(int artistId)
|
||||||
{
|
{
|
||||||
return _repository.GetFilesByArtist(artistId);
|
return _repository.GetFilesByArtist(artistId);
|
||||||
|
@ -122,20 +120,12 @@ namespace NzbDrone.Core.Extras.Files
|
||||||
|
|
||||||
if (_diskProvider.FileExists(path))
|
if (_diskProvider.FileExists(path))
|
||||||
{
|
{
|
||||||
if (PermanentlyDelete)
|
// Send to the recycling bin so they can be recovered if necessary
|
||||||
{
|
|
||||||
_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));
|
var subfolder = _diskProvider.GetParentFolder(artist.Path).GetRelativePath(_diskProvider.GetParentFolder(path));
|
||||||
_recycleBinProvider.DeleteFile(path, subfolder);
|
_recycleBinProvider.DeleteFile(path, subfolder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Debug("Deleting Extra from database for track file: {0}", trackFile);
|
_logger.Debug("Deleting Extra from database for track file: {0}", trackFile);
|
||||||
_repository.DeleteForTrackFile(trackFile.Id);
|
_repository.DeleteForTrackFile(trackFile.Id);
|
||||||
|
|
|
@ -17,14 +17,17 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||||
{
|
{
|
||||||
public class XbmcMetadata : MetadataBase<XbmcMetadataSettings>
|
public class XbmcMetadata : MetadataBase<XbmcMetadataSettings>
|
||||||
{
|
{
|
||||||
private readonly IMapCoversToLocal _mediaCoverService;
|
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
private readonly IMapCoversToLocal _mediaCoverService;
|
||||||
|
private readonly IDetectXbmcNfo _detectNfo;
|
||||||
|
|
||||||
public XbmcMetadata(IMapCoversToLocal mediaCoverService,
|
public XbmcMetadata(IDetectXbmcNfo detectNfo,
|
||||||
|
IMapCoversToLocal mediaCoverService,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_mediaCoverService = mediaCoverService;
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_mediaCoverService = mediaCoverService;
|
||||||
|
_detectNfo = detectNfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly Regex ArtistImagesRegex = new Regex(@"^(?<type>poster|banner|fanart|logo)\.(?:png|jpg|jpeg)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
private static readonly Regex ArtistImagesRegex = new Regex(@"^(?<type>poster|banner|fanart|logo)\.(?:png|jpg|jpeg)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
@ -72,27 +75,22 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||||
return metadata;
|
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;
|
metadata.Type = MetadataType.ArtistMetadata;
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filename.Equals("album.nfo", StringComparison.OrdinalIgnoreCase))
|
if (filename.Equals("album.nfo", StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
isXbmcNfoFile)
|
||||||
{
|
{
|
||||||
metadata.Type = MetadataType.AlbumMetadata;
|
metadata.Type = MetadataType.AlbumMetadata;
|
||||||
return metadata;
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,96 +193,10 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||||
}
|
}
|
||||||
|
|
||||||
public override MetadataFileResult TrackMetadata(Artist artist, TrackFile trackFile)
|
public override MetadataFileResult TrackMetadata(Artist artist, TrackFile trackFile)
|
||||||
{
|
|
||||||
if (!Settings.TrackMetadata)
|
|
||||||
{
|
{
|
||||||
return null;
|
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()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override List<ImageFileResult> ArtistImages(Artist artist)
|
public override List<ImageFileResult> ArtistImages(Artist artist)
|
||||||
{
|
{
|
||||||
if (!Settings.ArtistImages)
|
if (!Settings.ArtistImages)
|
||||||
|
@ -339,14 +251,5 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||||
return Path.ChangeExtension(trackFilePath, "nfo");
|
return Path.ChangeExtension(trackFilePath, "nfo");
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetAudioCodec(string audioCodec)
|
|
||||||
{
|
|
||||||
if (audioCodec == "AC-3")
|
|
||||||
{
|
|
||||||
return "AC3";
|
|
||||||
}
|
|
||||||
|
|
||||||
return audioCodec;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,20 +17,16 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
||||||
{
|
{
|
||||||
ArtistMetadata = true;
|
ArtistMetadata = true;
|
||||||
AlbumMetadata = true;
|
AlbumMetadata = true;
|
||||||
TrackMetadata = true;
|
|
||||||
ArtistImages = true;
|
ArtistImages = true;
|
||||||
AlbumImages = 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; }
|
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; }
|
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)]
|
[FieldDefinition(3, Label = "Artist Images", Type = FieldType.Checkbox)]
|
||||||
public bool ArtistImages { get; set; }
|
public bool ArtistImages { get; set; }
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,5 @@ namespace NzbDrone.Core.Extras.Metadata.Files
|
||||||
: base(repository, artistService, diskProvider, recycleBinProvider, logger)
|
: base(repository, artistService, diskProvider, recycleBinProvider, logger)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool PermanentlyDelete => true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Configuration;
|
using NzbDrone.Core.Configuration;
|
||||||
using NzbDrone.Core.Extras.Files;
|
using NzbDrone.Core.Extras.Files;
|
||||||
using NzbDrone.Core.Extras.Metadata.Files;
|
using NzbDrone.Core.Extras.Metadata.Files;
|
||||||
|
using NzbDrone.Core.Extras.Others;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
using NzbDrone.Core.Music;
|
using NzbDrone.Core.Music;
|
||||||
using NzbDrone.Core.Organizer;
|
using NzbDrone.Core.Organizer;
|
||||||
|
@ -20,6 +21,8 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||||
{
|
{
|
||||||
private readonly IMetadataFactory _metadataFactory;
|
private readonly IMetadataFactory _metadataFactory;
|
||||||
private readonly ICleanMetadataService _cleanMetadataService;
|
private readonly ICleanMetadataService _cleanMetadataService;
|
||||||
|
private readonly IRecycleBinProvider _recycleBinProvider;
|
||||||
|
private readonly IOtherExtraFileRenamer _otherExtraFileRenamer;
|
||||||
private readonly IDiskTransferService _diskTransferService;
|
private readonly IDiskTransferService _diskTransferService;
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
private readonly IHttpClient _httpClient;
|
private readonly IHttpClient _httpClient;
|
||||||
|
@ -31,6 +34,8 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||||
public MetadataService(IConfigService configService,
|
public MetadataService(IConfigService configService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IDiskTransferService diskTransferService,
|
IDiskTransferService diskTransferService,
|
||||||
|
IRecycleBinProvider recycleBinProvider,
|
||||||
|
IOtherExtraFileRenamer otherExtraFileRenamer,
|
||||||
IMetadataFactory metadataFactory,
|
IMetadataFactory metadataFactory,
|
||||||
ICleanMetadataService cleanMetadataService,
|
ICleanMetadataService cleanMetadataService,
|
||||||
IHttpClient httpClient,
|
IHttpClient httpClient,
|
||||||
|
@ -42,6 +47,8 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||||
{
|
{
|
||||||
_metadataFactory = metadataFactory;
|
_metadataFactory = metadataFactory;
|
||||||
_cleanMetadataService = cleanMetadataService;
|
_cleanMetadataService = cleanMetadataService;
|
||||||
|
_otherExtraFileRenamer = otherExtraFileRenamer;
|
||||||
|
_recycleBinProvider = recycleBinProvider;
|
||||||
_diskTransferService = diskTransferService;
|
_diskTransferService = diskTransferService;
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
_httpClient = httpClient;
|
_httpClient = httpClient;
|
||||||
|
@ -249,6 +256,8 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||||
|
|
||||||
var fullPath = Path.Combine(artist.Path, artistMetadata.RelativePath);
|
var fullPath = Path.Combine(artist.Path, artistMetadata.RelativePath);
|
||||||
|
|
||||||
|
_otherExtraFileRenamer.RenameOtherExtraFile(artist, fullPath);
|
||||||
|
|
||||||
_logger.Debug("Writing Artist Metadata to: {0}", fullPath);
|
_logger.Debug("Writing Artist Metadata to: {0}", fullPath);
|
||||||
SaveMetadataFile(fullPath, artistMetadata.Contents);
|
SaveMetadataFile(fullPath, artistMetadata.Contents);
|
||||||
|
|
||||||
|
@ -293,6 +302,8 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||||
|
|
||||||
var fullPath = Path.Combine(artist.Path, albumMetadata.RelativePath);
|
var fullPath = Path.Combine(artist.Path, albumMetadata.RelativePath);
|
||||||
|
|
||||||
|
_otherExtraFileRenamer.RenameOtherExtraFile(artist, fullPath);
|
||||||
|
|
||||||
_logger.Debug("Writing Album Metadata to: {0}", fullPath);
|
_logger.Debug("Writing Album Metadata to: {0}", fullPath);
|
||||||
SaveMetadataFile(fullPath, albumMetadata.Contents);
|
SaveMetadataFile(fullPath, albumMetadata.Contents);
|
||||||
|
|
||||||
|
@ -314,6 +325,8 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||||
|
|
||||||
var fullPath = Path.Combine(artist.Path, trackMetadata.RelativePath);
|
var fullPath = Path.Combine(artist.Path, trackMetadata.RelativePath);
|
||||||
|
|
||||||
|
_otherExtraFileRenamer.RenameOtherExtraFile(artist, fullPath);
|
||||||
|
|
||||||
var existingMetadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.TrackMetadata &&
|
var existingMetadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.TrackMetadata &&
|
||||||
c.TrackFileId == trackFile.Id);
|
c.TrackFileId == trackFile.Id);
|
||||||
|
|
||||||
|
@ -368,6 +381,8 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_otherExtraFileRenamer.RenameOtherExtraFile(artist, fullPath);
|
||||||
|
|
||||||
var metadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.ArtistImage &&
|
var metadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.ArtistImage &&
|
||||||
c.RelativePath == image.RelativePath) ??
|
c.RelativePath == image.RelativePath) ??
|
||||||
new MetadataFile
|
new MetadataFile
|
||||||
|
@ -401,6 +416,8 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_otherExtraFileRenamer.RenameOtherExtraFile(artist, fullPath);
|
||||||
|
|
||||||
var metadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.AlbumImage &&
|
var metadata = GetMetadataFile(artist, existingMetadataFiles, c => c.Type == MetadataType.AlbumImage &&
|
||||||
c.AlbumId == album.Id &&
|
c.AlbumId == album.Id &&
|
||||||
c.RelativePath == image.RelativePath) ??
|
c.RelativePath == image.RelativePath) ??
|
||||||
|
@ -471,11 +488,11 @@ namespace NzbDrone.Core.Extras.Metadata
|
||||||
|
|
||||||
_logger.Debug("Removing duplicate Metadata file: {0}", path);
|
_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);
|
_metadataFileService.Delete(file.Id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return matchingMetadataFiles.First();
|
return matchingMetadataFiles.First();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -65,12 +65,6 @@ namespace NzbDrone.Core.Extras.Others
|
||||||
|
|
||||||
public override ExtraFile Import(Artist artist, TrackFile trackFile, string path, string extension, bool readOnly)
|
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);
|
var extraFile = ImportFile(artist, trackFile, path, readOnly, extension, null);
|
||||||
|
|
||||||
_otherExtraFileService.Upsert(extraFile);
|
_otherExtraFileService.Upsert(extraFile);
|
||||||
|
|
|
@ -127,7 +127,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
|
||||||
|
|
||||||
if (newDownload)
|
if (newDownload)
|
||||||
{
|
{
|
||||||
_extraService.ImportExtraFiles(localTrack, trackFile, copyOnly);
|
_extraService.ImportTrack(localTrack, trackFile, copyOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
_eventAggregator.PublishEvent(new TrackImportedEvent(localTrack, trackFile, oldFiles, newDownload, downloadClientItem));
|
_eventAggregator.PublishEvent(new TrackImportedEvent(localTrack, trackFile, oldFiles, newDownload, downloadClientItem));
|
||||||
|
|
|
@ -440,10 +440,12 @@
|
||||||
<Compile Include="Extras\IImportExistingExtraFiles.cs" />
|
<Compile Include="Extras\IImportExistingExtraFiles.cs" />
|
||||||
<Compile Include="Extras\ImportExistingExtraFileFilterResult.cs" />
|
<Compile Include="Extras\ImportExistingExtraFileFilterResult.cs" />
|
||||||
<Compile Include="Extras\ImportExistingExtraFilesBase.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\MetadataFile.cs" />
|
||||||
<Compile Include="Extras\Metadata\Files\MetadataFileRepository.cs" />
|
<Compile Include="Extras\Metadata\Files\MetadataFileRepository.cs" />
|
||||||
<Compile Include="Extras\Metadata\Files\MetadataFileService.cs" />
|
<Compile Include="Extras\Metadata\Files\MetadataFileService.cs" />
|
||||||
<Compile Include="Extras\Others\ExistingOtherExtraImporter.cs" />
|
<Compile Include="Extras\Others\ExistingOtherExtraImporter.cs" />
|
||||||
|
<Compile Include="Extras\Others\OtherExtraFileRenamer.cs" />
|
||||||
<Compile Include="Extras\Others\OtherExtraFileRepository.cs" />
|
<Compile Include="Extras\Others\OtherExtraFileRepository.cs" />
|
||||||
<Compile Include="Extras\Others\OtherExtraFileService.cs" />
|
<Compile Include="Extras\Others\OtherExtraFileService.cs" />
|
||||||
<Compile Include="Extras\Others\OtherExtraFile.cs" />
|
<Compile Include="Extras\Others\OtherExtraFile.cs" />
|
||||||
|
|
Loading…
Reference in New Issue