Fixed: Misc Extra File Improvements (This changes mapping of backdrop images to Fanart instead of Banner) (#2642)

Fixes #2556
Fixes #2639
Fixes #2547
pull/2/head
Qstick 7 years ago committed by Leonardo Galli
parent 0f6c5533f1
commit 39346b6127

@ -8,7 +8,7 @@ using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Movies; using NzbDrone.Core.Movies;
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.Movies; using NzbDrone.Core.Movies;
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.Movies;
using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.Extras.Metadata.Consumers.Xbmc
{
[TestFixture]
public class FindMetadataFileFixture : CoreTest<XbmcMetadata>
{
private Movie _movie;
[SetUp]
public void Setup()
{
_movie = Builder<Movie>.CreateNew()
.With(s => s.Path = @"C:\Test\Movies\The.Movie".AsOsAgnostic())
.Build();
}
[Test]
public void should_return_null_if_filename_is_not_handled()
{
var path = Path.Combine(_movie.Path, "file.jpg");
Subject.FindMetadataFile(_movie, path).Should().BeNull();
}
[Test]
public void should_return_metadata_for_xbmc_nfo()
{
var path = Path.Combine(_movie.Path, "the.movie.2017.nfo");
Mocker.GetMock<IDetectXbmcNfo>()
.Setup(v => v.IsXbmcNfoFile(path))
.Returns(true);
Subject.FindMetadataFile(_movie, path).Type.Should().Be(MetadataType.MovieMetadata);
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(_movie.Path, "the.movie.2017.nfo");
Mocker.GetMock<IDetectXbmcNfo>()
.Setup(v => v.IsXbmcNfoFile(path))
.Returns(false);
Subject.FindMetadataFile(_movie, path).Should().BeNull();
Mocker.GetMock<IDetectXbmcNfo>()
.Verify(v => v.IsXbmcNfoFile(It.IsAny<string>()), Times.Once());
}
}
}

@ -198,6 +198,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" />
@ -300,8 +301,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\OnDownloadFixture.cs" /> <Compile Include="NotificationTests\Xbmc\OnDownloadFixture.cs" />

@ -0,0 +1,17 @@
using FluentMigrator;
using NzbDrone.Core.Datastore.Migration.Framework;
namespace NzbDrone.Core.Datastore.Migration
{
[Migration(145)]
public class banner_to_fanart : NzbDroneMigrationBase
{
protected override void MainDbUpgrade()
{
Execute.Sql("UPDATE Movies SET Images = replace(Images, \'\"coverType\": \"banner\"\', \'\"coverType\": \"fanart\"\')");
// Remove Link for images to specific MovieFiles, Images are now related to the Movie object only
Execute.Sql("UPDATE MetadataFiles SET MovieFileId = null WHERE Type = 2");
}
}
}

@ -19,11 +19,12 @@ namespace NzbDrone.Core.Extras
{ {
public interface IExtraService public interface IExtraService
{ {
void ImportExtraFiles(LocalMovie localMovie, MovieFile movieFile, bool isReadOnly); void ImportMovie(LocalMovie localMovie, MovieFile movieFile, bool isReadOnly);
} }
public class ExtraService : IExtraService, public class ExtraService : IExtraService,
IHandle<MediaCoversUpdatedEvent>, IHandle<MediaCoversUpdatedEvent>,
IHandle<MovieFolderCreatedEvent>,
IHandle<MovieRenamedEvent> IHandle<MovieRenamedEvent>
{ {
private readonly IMediaFileService _mediaFileService; private readonly IMediaFileService _mediaFileService;
@ -48,15 +49,15 @@ namespace NzbDrone.Core.Extras
_logger = logger; _logger = logger;
} }
public void ImportExtraFiles(LocalMovie localMovie, MovieFile movieFile, bool isReadOnly) public void ImportMovie(LocalMovie localMovie, MovieFile movieFile, bool isReadOnly)
{ {
var movie = localMovie.Movie; ImportExtraFiles(localMovie, movieFile, isReadOnly);
foreach (var extraFileManager in _extraFileManagers) CreateAfterImport(localMovie.Movie, movieFile);
{ }
extraFileManager.CreateAfterMovieImport(movie, movieFile);
}
public void ImportExtraFiles(LocalMovie localMovie, MovieFile movieFile, bool isReadOnly)
{
if (!_configService.ImportExtraFiles) if (!_configService.ImportExtraFiles)
{ {
return; return;
@ -87,7 +88,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(movie, movieFile, matchingFilename, extension, isReadOnly); var extraFile = extraFileManager.Import(localMovie.Movie, movieFile, matchingFilename, extension, isReadOnly);
if (extraFile != null) if (extraFile != null)
{ {
@ -102,6 +103,14 @@ namespace NzbDrone.Core.Extras
} }
} }
private void CreateAfterImport(Movie movie, MovieFile movieFile)
{
foreach (var extraFileManager in _extraFileManagers)
{
extraFileManager.CreateAfterMovieImport(movie, movieFile);
}
}
public void Handle(MediaCoversUpdatedEvent message) public void Handle(MediaCoversUpdatedEvent message)
{ {
var movie = message.Movie; var movie = message.Movie;
@ -113,6 +122,16 @@ namespace NzbDrone.Core.Extras
} }
} }
public void Handle(MovieFolderCreatedEvent message)
{
var movie = message.Movie;
foreach (var extraFileManager in _extraFileManagers)
{
extraFileManager.CreateAfterMovieImport(movie, message.MovieFolder);
}
}
public void Handle(MovieRenamedEvent message) public void Handle(MovieRenamedEvent message)
{ {
var movie = message.Movie; var movie = message.Movie;

@ -16,6 +16,7 @@ namespace NzbDrone.Core.Extras.Files
int Order { get; } int Order { get; }
IEnumerable<ExtraFile> CreateAfterMovieScan(Movie movie, List<MovieFile> movieFiles); IEnumerable<ExtraFile> CreateAfterMovieScan(Movie movie, List<MovieFile> movieFiles);
IEnumerable<ExtraFile> CreateAfterMovieImport(Movie movie, MovieFile movieFile); IEnumerable<ExtraFile> CreateAfterMovieImport(Movie movie, MovieFile movieFile);
IEnumerable<ExtraFile> CreateAfterMovieImport(Movie movie, string movieFolder);
IEnumerable<ExtraFile> MoveFilesAfterRename(Movie movie, List<MovieFile> movieFiles); IEnumerable<ExtraFile> MoveFilesAfterRename(Movie movie, List<MovieFile> movieFiles);
ExtraFile Import(Movie movie, MovieFile movieFile, string path, string extension, bool readOnly); ExtraFile Import(Movie movie, MovieFile movieFile, string path, string extension, bool readOnly);
} }
@ -43,6 +44,7 @@ namespace NzbDrone.Core.Extras.Files
public abstract int Order { get; } public abstract int Order { get; }
public abstract IEnumerable<ExtraFile> CreateAfterMovieScan(Movie movie, List<MovieFile> movieFiles); public abstract IEnumerable<ExtraFile> CreateAfterMovieScan(Movie movie, List<MovieFile> movieFiles);
public abstract IEnumerable<ExtraFile> CreateAfterMovieImport(Movie movie, MovieFile movieFile); public abstract IEnumerable<ExtraFile> CreateAfterMovieImport(Movie movie, MovieFile movieFile);
public abstract IEnumerable<ExtraFile> CreateAfterMovieImport(Movie movie, string movieFolder);
public abstract IEnumerable<ExtraFile> MoveFilesAfterRename(Movie movie, List<MovieFile> movieFiles); public abstract IEnumerable<ExtraFile> MoveFilesAfterRename(Movie movie, List<MovieFile> movieFiles);
public abstract ExtraFile Import(Movie movie, MovieFile movieFile, string path, string extension, bool readOnly); public abstract ExtraFile Import(Movie movie, MovieFile movieFile, string path, string extension, bool readOnly);

@ -48,8 +48,6 @@ namespace NzbDrone.Core.Extras.Files
_logger = logger; _logger = logger;
} }
public virtual bool PermanentlyDelete => false;
public List<TExtraFile> GetFilesByMovie(int movieId) public List<TExtraFile> GetFilesByMovie(int movieId)
{ {
return _repository.GetFilesByMovie(movieId); return _repository.GetFilesByMovie(movieId);
@ -121,16 +119,8 @@ 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
{ _recycleBinProvider.DeleteFile(path);
_diskProvider.DeleteFile(path);
}
else
{
// Send extra files to the recycling bin so they can be recovered if necessary
_recycleBinProvider.DeleteFile(path);
}
} }
} }
} }

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -87,7 +87,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.MediaBrowser
} }
} }
public override List<ImageFileResult> MovieImages(Movie movie, MovieFile movieFile) public override List<ImageFileResult> MovieImages(Movie movie)
{ {
return new List<ImageFileResult>(); return new List<ImageFileResult>();
} }

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -131,7 +131,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
return new MetadataFileResult(GetMovieFileMetadataFilename(movieFile.RelativePath), xmlResult.Trim(Environment.NewLine.ToCharArray())); return new MetadataFileResult(GetMovieFileMetadataFilename(movieFile.RelativePath), xmlResult.Trim(Environment.NewLine.ToCharArray()));
} }
public override List<ImageFileResult> MovieImages(Movie movie, MovieFile movieFile) public override List<ImageFileResult> MovieImages(Movie movie)
{ {
if (!Settings.MovieImages) if (!Settings.MovieImages)
{ {

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -129,7 +129,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
return new MetadataFileResult(filename, xmlResult.Trim(Environment.NewLine.ToCharArray())); return new MetadataFileResult(filename, xmlResult.Trim(Environment.NewLine.ToCharArray()));
} }
public override List<ImageFileResult> MovieImages(Movie movie, MovieFile moviefile) public override List<ImageFileResult> MovieImages(Movie movie)
{ {
if (!Settings.MovieImages) if (!Settings.MovieImages)
{ {

@ -7,6 +7,7 @@ using System.Text.RegularExpressions;
using System.Xml; using System.Xml;
using System.Xml.Linq; using System.Xml.Linq;
using NLog; using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Extras.Metadata.Files; using NzbDrone.Core.Extras.Metadata.Files;
using NzbDrone.Core.MediaCover; using NzbDrone.Core.MediaCover;
@ -19,16 +20,23 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
{ {
private readonly IMapCoversToLocal _mediaCoverService; private readonly IMapCoversToLocal _mediaCoverService;
private readonly Logger _logger; private readonly Logger _logger;
private readonly IDetectXbmcNfo _detectNfo;
private readonly IDiskProvider _diskProvider;
public XbmcMetadata(IMapCoversToLocal mediaCoverService, public XbmcMetadata(IDetectXbmcNfo detectNfo,
IDiskProvider diskProvider,
IMapCoversToLocal mediaCoverService,
Logger logger) Logger logger)
{ {
_mediaCoverService = mediaCoverService;
_logger = logger; _logger = logger;
_mediaCoverService = mediaCoverService;
_diskProvider = diskProvider;
_detectNfo = detectNfo;
} }
private static readonly Regex MovieImagesRegex = new Regex(@"^(?<type>poster|banner|fanart|clearart|disc|landscape|logo)\.(?:png|jpg)", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex MovieImagesRegex = new Regex(@"^(?<type>poster|banner|fanart|clearart|discart|landscape|logo|backdrop|clearlogo)\.(?:png|jpg)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
private static readonly Regex MovieFileImageRegex = new Regex(@"(?<type>-thumb|-poster|-banner|-fanart)\.(?:png|jpg)", RegexOptions.Compiled | RegexOptions.IgnoreCase); private static readonly Regex MovieFileImageRegex = new Regex(@"(?<type>-thumb|-poster|-banner|-fanart|-clearart|-discart|-landscape|-logo|-backdrop|-clearlogo)\.(?:png|jpg)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
public override string Name => "Kodi (XBMC) / Emby"; public override string Name => "Kodi (XBMC) / Emby";
@ -42,11 +50,6 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
return GetMovieMetadataFilename(movieFilePath); return GetMovieMetadataFilename(movieFilePath);
} }
if (metadataFile.Type == MetadataType.MovieImage)
{
return GetMovieImageFilename(movieFilePath, metadataPath);
}
_logger.Debug("Unknown movie file metadata: {0}", metadataFile.RelativePath); _logger.Debug("Unknown movie file metadata: {0}", metadataFile.RelativePath);
return Path.Combine(movie.Path, metadataFile.RelativePath); return Path.Combine(movie.Path, metadataFile.RelativePath);
} }
@ -76,7 +79,8 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
return metadata; return metadata;
} }
if (filename.Equals("movie.nfo", StringComparison.OrdinalIgnoreCase)) if (filename.Equals("movie.nfo", StringComparison.OrdinalIgnoreCase) &&
_detectNfo.IsXbmcNfoFile(path))
{ {
metadata.Type = MetadataType.MovieMetadata; metadata.Type = MetadataType.MovieMetadata;
return metadata; return metadata;
@ -85,7 +89,8 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
var parseResult = Parser.Parser.ParseMovieTitle(filename, false); var parseResult = Parser.Parser.ParseMovieTitle(filename, false);
if (parseResult != null && if (parseResult != null &&
Path.GetExtension(filename).Equals(".nfo", StringComparison.OrdinalIgnoreCase)) Path.GetExtension(filename).Equals(".nfo", StringComparison.OrdinalIgnoreCase) &&
_detectNfo.IsXbmcNfoFile(path))
{ {
metadata.Type = MetadataType.MovieMetadata; metadata.Type = MetadataType.MovieMetadata;
return metadata; return metadata;
@ -103,6 +108,8 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
_logger.Debug("Generating Movie Metadata for: {0}", Path.Combine(movie.Path, movieFile.RelativePath)); _logger.Debug("Generating Movie Metadata for: {0}", Path.Combine(movie.Path, movieFile.RelativePath));
var watched = GetExistingWatchedStatus(movie, movieFile.RelativePath);
var xmlResult = string.Empty; var xmlResult = string.Empty;
var sb = new StringBuilder(); var sb = new StringBuilder();
@ -150,7 +157,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
details.Add(new XElement("thumb", image.Url)); details.Add(new XElement("thumb", image.Url));
} }
details.Add(new XElement("watched", "false")); details.Add(new XElement("watched", watched));
if (movieFile.MediaInfo != null) if (movieFile.MediaInfo != null)
{ {
@ -210,7 +217,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
return new MetadataFileResult(metadataFileName, xmlResult.Trim(Environment.NewLine.ToCharArray())); return new MetadataFileResult(metadataFileName, xmlResult.Trim(Environment.NewLine.ToCharArray()));
} }
public override List<ImageFileResult> MovieImages(Movie movie, MovieFile movieFile) public override List<ImageFileResult> MovieImages(Movie movie)
{ {
if (!Settings.MovieImages) if (!Settings.MovieImages)
{ {
@ -225,7 +232,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
foreach (var image in movie.Images) foreach (var image in movie.Images)
{ {
var source = _mediaCoverService.GetCoverPath(movie.Id, image.CoverType); var source = _mediaCoverService.GetCoverPath(movie.Id, image.CoverType);
var destination = Path.ChangeExtension(movie.MovieFile.RelativePath,"").TrimEnd(".") + "-" + image.CoverType.ToString().ToLowerInvariant() + Path.GetExtension(source); var destination = image.CoverType.ToString().ToLowerInvariant() + Path.GetExtension(source);
yield return new ImageFileResult(destination, source); yield return new ImageFileResult(destination, source);
} }
@ -236,28 +243,28 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
return Path.ChangeExtension(movieFilePath, "nfo"); return Path.ChangeExtension(movieFilePath, "nfo");
} }
private string GetMovieImageFilename(string movieFilePath, string existingImageName) private string GetAudioCodec(string audioCodec)
{ {
var fileExtention = Path.GetExtension(existingImageName); if (audioCodec == "AC-3")
var match = MovieFileImageRegex.Matches(existingImageName);
if (match.Count > 0)
{ {
var imageType = match[0].Groups["type"].Value; return "AC3";
return Parser.Parser.RemoveFileExtension(movieFilePath) + imageType + fileExtention;
} }
return existingImageName; return audioCodec;
} }
private string GetAudioCodec(string audioCodec) private bool GetExistingWatchedStatus(Movie movie, string movieFilePath)
{ {
if (audioCodec == "AC-3") var fullPath = Path.Combine(movie.Path, GetMovieMetadataFilename(movieFilePath));
if (!_diskProvider.FileExists(fullPath))
{ {
return "AC3"; return false;
} }
return audioCodec; var fileContent = _diskProvider.ReadAllText(fullPath);
return Regex.IsMatch(fileContent, "<watched>true</watched>");
} }
} }
} }

@ -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, movieService, diskProvider, recycleBinProvider, logger) : base(repository, movieService, diskProvider, recycleBinProvider, logger)
{ {
} }
public override bool PermanentlyDelete => true;
} }
} }

@ -11,6 +11,6 @@ namespace NzbDrone.Core.Extras.Metadata
string GetFilenameAfterMove(Movie movie, MovieFile movieFile, MetadataFile metadataFile); string GetFilenameAfterMove(Movie movie, MovieFile movieFile, MetadataFile metadataFile);
MetadataFile FindMetadataFile(Movie movie, string path); MetadataFile FindMetadataFile(Movie movie, string path);
MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFile); MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFile);
List<ImageFileResult> MovieImages(Movie movie, MovieFile movieFile); List<ImageFileResult> MovieImages(Movie movie);
} }
} }

@ -41,7 +41,7 @@ namespace NzbDrone.Core.Extras.Metadata
public abstract MetadataFile FindMetadataFile(Movie movie, string path); public abstract MetadataFile FindMetadataFile(Movie movie, string path);
public abstract MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFile); public abstract MetadataFileResult MovieMetadata(Movie movie, MovieFile movieFile);
public abstract List<ImageFileResult> MovieImages(Movie movie, MovieFile movieFile); public abstract List<ImageFileResult> MovieImages(Movie movie);
public virtual object RequestAction(string action, IDictionary<string, string> query) { return null; } public virtual object RequestAction(string action, IDictionary<string, string> query) { return null; }

@ -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.Movies; using NzbDrone.Core.Movies;
@ -19,6 +20,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 IDiskProvider _diskProvider; private readonly IDiskProvider _diskProvider;
private readonly IDiskTransferService _diskTransferService; private readonly IDiskTransferService _diskTransferService;
private readonly IHttpClient _httpClient; private readonly IHttpClient _httpClient;
@ -29,6 +32,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,
@ -39,6 +44,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;
@ -66,10 +73,11 @@ namespace NzbDrone.Core.Extras.Metadata
{ {
var consumerFiles = GetMetadataFilesForConsumer(consumer, metadataFiles); var consumerFiles = GetMetadataFilesForConsumer(consumer, metadataFiles);
files.AddRange(ProcessMovieImages(consumer, movie, consumerFiles));
foreach (var movieFile in movieFiles) foreach (var movieFile in movieFiles)
{ {
files.AddIfNotNull(ProcessMovieMetadata(consumer, movie, movieFile, consumerFiles)); files.AddIfNotNull(ProcessMovieMetadata(consumer, movie, movieFile, consumerFiles));
files.AddRange(ProcessMovieImages(consumer, movie, movieFile, consumerFiles));
} }
} }
@ -84,9 +92,33 @@ namespace NzbDrone.Core.Extras.Metadata
foreach (var consumer in _metadataFactory.Enabled()) foreach (var consumer in _metadataFactory.Enabled())
{ {
files.AddIfNotNull(ProcessMovieMetadata(consumer, movie, movieFile, new List<MetadataFile>())); files.AddIfNotNull(ProcessMovieMetadata(consumer, movie, movieFile, new List<MetadataFile>()));
files.AddRange(ProcessMovieImages(consumer, movie, movieFile, new List<MetadataFile>())); }
_metadataFileService.Upsert(files);
return files;
}
public override IEnumerable<ExtraFile> CreateAfterMovieImport(Movie movie, string movieFolder)
{
var metadataFiles = _metadataFileService.GetFilesByMovie(movie.Id);
if (movieFolder.IsNullOrWhiteSpace())
{
return new List<MetadataFile>();
}
var files = new List<MetadataFile>();
foreach (var consumer in _metadataFactory.Enabled())
{
var consumerFiles = GetMetadataFilesForConsumer(consumer, metadataFiles);
if (movieFolder.IsNotNullOrWhiteSpace())
{
files.AddRange(ProcessMovieImages(consumer, movie, consumerFiles));
}
} }
_metadataFileService.Upsert(files); _metadataFileService.Upsert(files);
@ -156,6 +188,8 @@ namespace NzbDrone.Core.Extras.Metadata
var fullPath = Path.Combine(movie.Path, movieFileMetadata.RelativePath); var fullPath = Path.Combine(movie.Path, movieFileMetadata.RelativePath);
_otherExtraFileRenamer.RenameOtherExtraFile(movie, fullPath);
var existingMetadata = GetMetadataFile(movie, existingMetadataFiles, c => c.Type == MetadataType.MovieMetadata && var existingMetadata = GetMetadataFile(movie, existingMetadataFiles, c => c.Type == MetadataType.MovieMetadata &&
c.MovieFileId == movieFile.Id); c.MovieFileId == movieFile.Id);
@ -194,12 +228,12 @@ namespace NzbDrone.Core.Extras.Metadata
return metadata; return metadata;
} }
private List<MetadataFile> ProcessMovieImages(IMetadata consumer, Movie movie, MovieFile movieFile, List<MetadataFile> existingMetadataFiles) private List<MetadataFile> ProcessMovieImages(IMetadata consumer, Movie movie, List<MetadataFile> existingMetadataFiles)
{ {
var result = new List<MetadataFile>(); var result = new List<MetadataFile>();
foreach (var image in consumer.MovieImages(movie, movieFile)) foreach (var image in consumer.MovieImages(movie))
{ {
var fullPath = Path.Combine(movie.Path, image.RelativePath); var fullPath = Path.Combine(movie.Path, image.RelativePath);
@ -209,26 +243,13 @@ namespace NzbDrone.Core.Extras.Metadata
continue; continue;
} }
var existingMetadata = GetMetadataFile(movie, existingMetadataFiles, c => c.Type == MetadataType.MovieImage && _otherExtraFileRenamer.RenameOtherExtraFile(movie, fullPath);
c.RelativePath == image.RelativePath);
if (existingMetadata != null)
{
var existingFullPath = Path.Combine(movie.Path, existingMetadata.RelativePath);
if (fullPath.PathNotEquals(existingFullPath))
{
_diskTransferService.TransferFile(existingFullPath, fullPath, TransferMode.Move);
existingMetadata.RelativePath = image.RelativePath;
return new List<MetadataFile>{ existingMetadata };
}
}
var metadata = existingMetadata ?? var metadata = GetMetadataFile(movie, existingMetadataFiles, c => c.Type == MetadataType.MovieImage &&
c.RelativePath == image.RelativePath) ??
new MetadataFile new MetadataFile
{ {
MovieId = movie.Id, MovieId = movie.Id,
MovieFileId = movieFile.Id,
Consumer = consumer.GetType().Name, Consumer = consumer.GetType().Name,
Type = MetadataType.MovieImage, Type = MetadataType.MovieImage,
RelativePath = image.RelativePath, RelativePath = image.RelativePath,
@ -291,7 +312,7 @@ namespace NzbDrone.Core.Extras.Metadata
_logger.Debug("Removing duplicate Metadata file: {0}", path); _logger.Debug("Removing duplicate Metadata file: {0}", path);
_diskProvider.DeleteFile(path); _recycleBinProvider.DeleteFile(path);
_metadataFileService.Delete(file.Id); _metadataFileService.Delete(file.Id);
} }

@ -0,0 +1,81 @@
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.Movies;
namespace NzbDrone.Core.Extras.Others
{
public interface IOtherExtraFileRenamer
{
void RenameOtherExtraFile(Movie movie, string path);
}
public class OtherExtraFileRenamer : IOtherExtraFileRenamer
{
private readonly Logger _logger;
private readonly IDiskProvider _diskProvider;
private readonly IRecycleBinProvider _recycleBinProvider;
private readonly IMovieService _movieService;
private readonly IOtherExtraFileService _otherExtraFileService;
public OtherExtraFileRenamer(IOtherExtraFileService otherExtraFileService,
IMovieService movieService,
IRecycleBinProvider recycleBinProvider,
IDiskProvider diskProvider,
Logger logger)
{
_logger = logger;
_diskProvider = diskProvider;
_recycleBinProvider = recycleBinProvider;
_movieService = movieService;
_otherExtraFileService = otherExtraFileService;
}
public void RenameOtherExtraFile(Movie movie, string path)
{
if (!_diskProvider.FileExists(path))
{
return;
}
var relativePath = movie.Path.GetRelativePath(path);
var otherExtraFile = _otherExtraFileService.FindByPath(relativePath);
if (otherExtraFile != null)
{
var newPath = path + "-orig";
// Recycle an existing -orig file.
RemoveOtherExtraFile(movie, newPath);
// Rename the file to .*-orig
_diskProvider.MoveFile(path, newPath);
otherExtraFile.RelativePath = relativePath + "-orig";
otherExtraFile.Extension += "-orig";
_otherExtraFileService.Upsert(otherExtraFile);
}
}
private void RemoveOtherExtraFile(Movie movie, string path)
{
if (!_diskProvider.FileExists(path))
{
return;
}
var relativePath = movie.Path.GetRelativePath(path);
var otherExtraFile = _otherExtraFileService.FindByPath(relativePath);
if (otherExtraFile != null)
{
_recycleBinProvider.DeleteFile(path);
}
}
}
}

@ -38,6 +38,11 @@ namespace NzbDrone.Core.Extras.Others
return Enumerable.Empty<ExtraFile>(); return Enumerable.Empty<ExtraFile>();
} }
public override IEnumerable<ExtraFile> CreateAfterMovieImport(Movie movie, string movieFolder)
{
return Enumerable.Empty<ExtraFile>();
}
public override IEnumerable<ExtraFile> MoveFilesAfterRename(Movie movie, List<MovieFile> movieFiles) public override IEnumerable<ExtraFile> MoveFilesAfterRename(Movie movie, List<MovieFile> movieFiles)
{ {
var extraFiles = _otherExtraFileService.GetFilesByMovie(movie.Id); var extraFiles = _otherExtraFileService.GetFilesByMovie(movie.Id);
@ -60,12 +65,6 @@ namespace NzbDrone.Core.Extras.Others
public override ExtraFile Import(Movie movie, MovieFile movieFile, string path, string extension, bool readOnly) public override ExtraFile Import(Movie movie, MovieFile movieFile, 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(movie, movieFile, path, readOnly, extension, null); var extraFile = ImportFile(movie, movieFile, path, readOnly, extension, null);
_otherExtraFileService.Upsert(extraFile); _otherExtraFileService.Upsert(extraFile);

@ -42,6 +42,11 @@ namespace NzbDrone.Core.Extras.Subtitles
return Enumerable.Empty<SubtitleFile>(); return Enumerable.Empty<SubtitleFile>();
} }
public override IEnumerable<ExtraFile> CreateAfterMovieImport(Movie movie, string movieFolder)
{
return Enumerable.Empty<SubtitleFile>();
}
public override IEnumerable<ExtraFile> MoveFilesAfterRename(Movie movie, List<MovieFile> movieFiles) public override IEnumerable<ExtraFile> MoveFilesAfterRename(Movie movie, List<MovieFile> movieFiles)
{ {
var subtitleFiles = _subtitleFileService.GetFilesByMovie(movie.Id); var subtitleFiles = _subtitleFileService.GetFilesByMovie(movie.Id);

@ -120,7 +120,7 @@ namespace NzbDrone.Core.MediaFiles.MovieImport
if (newDownload) if (newDownload)
{ {
_extraService.ImportExtraFiles(localMovie, movieFile, copyOnly); _extraService.ImportMovie(localMovie, movieFile, copyOnly);
} }
if (downloadClientItem != null) if (downloadClientItem != null)

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
@ -160,7 +160,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
movie.TitleSlug += "-" + movie.TmdbId.ToString(); movie.TitleSlug += "-" + movie.TmdbId.ToString();
movie.Images.Add(_configService.GetCoverForURL(resource.poster_path, MediaCoverTypes.Poster));//TODO: Update to load image specs from tmdb page! movie.Images.Add(_configService.GetCoverForURL(resource.poster_path, MediaCoverTypes.Poster));//TODO: Update to load image specs from tmdb page!
movie.Images.Add(_configService.GetCoverForURL(resource.backdrop_path, MediaCoverTypes.Banner)); movie.Images.Add(_configService.GetCoverForURL(resource.backdrop_path, MediaCoverTypes.Fanart));
movie.Runtime = resource.runtime; movie.Runtime = resource.runtime;
//foreach(Title title in resource.alternative_titles.titles) //foreach(Title title in resource.alternative_titles.titles)

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -44,7 +44,7 @@ namespace NzbDrone.Core.MetadataSource
switch (type) switch (type)
{ {
case MediaCoverTypes.Banner: case MediaCoverTypes.Fanart:
realUrl += images.backdrop_sizes.Last(); realUrl += images.backdrop_sizes.Last();
break; break;
case MediaCoverTypes.Poster: case MediaCoverTypes.Poster:

@ -128,9 +128,12 @@
<Compile Include="Datastore\Migration\142_movie_extras.cs" /> <Compile Include="Datastore\Migration\142_movie_extras.cs" />
<Compile Include="Datastore\Migration\140_add_alternative_titles_table.cs" /> <Compile Include="Datastore\Migration\140_add_alternative_titles_table.cs" />
<Compile Include="Datastore\Migration\141_fix_duplicate_alt_titles.cs" /> <Compile Include="Datastore\Migration\141_fix_duplicate_alt_titles.cs" />
<Compile Include="Datastore\Migration\145_banner_to_fanart.cs" />
<Compile Include="Datastore\Migration\144_add_cookies_to_indexer_status.cs" /> <Compile Include="Datastore\Migration\144_add_cookies_to_indexer_status.cs" />
<Compile Include="DecisionEngine\Specifications\MaximumSizeSpecification.cs" /> <Compile Include="DecisionEngine\Specifications\MaximumSizeSpecification.cs" />
<Compile Include="DecisionEngine\Specifications\RequiredIndexerFlagsSpecification.cs" /> <Compile Include="DecisionEngine\Specifications\RequiredIndexerFlagsSpecification.cs" />
<Compile Include="Extras\Metadata\Consumers\Xbmc\XbmcNfoDetector.cs" />
<Compile Include="Extras\Others\OtherExtraFileRenamer.cs" />
<Compile Include="Housekeeping\Housekeepers\CleanupOrphanedAlternativeTitles.cs" /> <Compile Include="Housekeeping\Housekeepers\CleanupOrphanedAlternativeTitles.cs" />
<Compile Include="MediaFiles\MovieImport\Specifications\GrabbedReleaseQualitySpecification.cs" /> <Compile Include="MediaFiles\MovieImport\Specifications\GrabbedReleaseQualitySpecification.cs" />
<Compile Include="MediaFiles\MovieImport\Specifications\SameFileSpecification.cs" /> <Compile Include="MediaFiles\MovieImport\Specifications\SameFileSpecification.cs" />

@ -262,7 +262,7 @@ module.exports = Marionette.Layout.extend({
_showBackdrop : function () { _showBackdrop : function () {
$('body').addClass('backdrop'); $('body').addClass('backdrop');
var fanArt = this._getImage('banner'); var fanArt = this._getImage('fanart');
if (fanArt) { if (fanArt) {
this._backstrech = $.backstretch(fanArt); this._backstrech = $.backstretch(fanArt);

Loading…
Cancel
Save