mirror of
https://github.com/Sonarr/Sonarr.git
synced 2024-12-16 11:37:58 +02:00
Almost everything working except importing episode thumbs
This commit is contained in:
parent
a6361d0bbd
commit
3ca5e478ff
@ -34,10 +34,7 @@ public static string GetRelativePath(string parentPath, string childPath)
|
|||||||
throw new NotParentException("{0} is not a child of {1}", childPath, parentPath);
|
throw new NotParentException("{0} is not a child of {1}", childPath, parentPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
var parentUri = new Uri(parentPath, UriKind.Absolute);
|
return childPath.Substring(parentPath.Length).Trim(Path.DirectorySeparatorChar);
|
||||||
var childUri = new Uri(childPath, UriKind.Absolute);
|
|
||||||
|
|
||||||
return childUri.MakeRelativeUri(parentUri).ToString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsParent(string parentPath, string childPath)
|
public static bool IsParent(string parentPath, string childPath)
|
||||||
|
@ -33,13 +33,6 @@ private void GivenChildOfSeries()
|
|||||||
_localEpisode.ExistingFile = true;
|
_localEpisode.ExistingFile = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenNewFile()
|
|
||||||
{
|
|
||||||
Mocker.GetMock<IDiskProvider>()
|
|
||||||
.Setup(s => s.IsParent(_localEpisode.Series.Path, _localEpisode.Path))
|
|
||||||
.Returns(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_return_true_if_file_is_under_series_folder()
|
public void should_return_true_if_file_is_under_series_folder()
|
||||||
{
|
{
|
||||||
@ -62,8 +55,6 @@ public void should_not_check_for_file_in_use_if_child_of_series_folder()
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_return_false_if_file_is_in_use()
|
public void should_return_false_if_file_is_in_use()
|
||||||
{
|
{
|
||||||
GivenNewFile();
|
|
||||||
|
|
||||||
Mocker.GetMock<IDiskProvider>()
|
Mocker.GetMock<IDiskProvider>()
|
||||||
.Setup(s => s.IsFileLocked(It.IsAny<string>()))
|
.Setup(s => s.IsFileLocked(It.IsAny<string>()))
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
@ -74,8 +65,6 @@ public void should_return_false_if_file_is_in_use()
|
|||||||
[Test]
|
[Test]
|
||||||
public void should_return_true_if_file_is_not_in_use()
|
public void should_return_true_if_file_is_not_in_use()
|
||||||
{
|
{
|
||||||
GivenNewFile();
|
|
||||||
|
|
||||||
Mocker.GetMock<IDiskProvider>()
|
Mocker.GetMock<IDiskProvider>()
|
||||||
.Setup(s => s.IsFileLocked(It.IsAny<string>()))
|
.Setup(s => s.IsFileLocked(It.IsAny<string>()))
|
||||||
.Returns(false);
|
.Returns(false);
|
||||||
|
@ -36,10 +36,6 @@ public void SetUp()
|
|||||||
Mocker.GetMock<IEpisodeService>()
|
Mocker.GetMock<IEpisodeService>()
|
||||||
.Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
.Setup(c => c.GetEpisodeBySeries(It.IsAny<int>()))
|
||||||
.Returns(_episodes);
|
.Returns(_episodes);
|
||||||
|
|
||||||
Mocker.GetMock<IDiskProvider>()
|
|
||||||
.Setup(s => s.IsParent(It.IsAny<String>(), It.IsAny<String>()))
|
|
||||||
.Returns(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenEpisodeFiles(IEnumerable<EpisodeFile> episodeFiles)
|
private void GivenEpisodeFiles(IEnumerable<EpisodeFile> episodeFiles)
|
||||||
@ -58,13 +54,6 @@ private void GivenFilesAreNotAttachedToEpisode()
|
|||||||
.Returns(_episodes);
|
.Returns(_episodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GivenFileIsNotInSeriesFolder()
|
|
||||||
{
|
|
||||||
Mocker.GetMock<IDiskProvider>()
|
|
||||||
.Setup(s => s.IsParent(It.IsAny<String>(), It.IsAny<String>()))
|
|
||||||
.Returns(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void should_skip_files_that_exist_in_disk()
|
public void should_skip_files_that_exist_in_disk()
|
||||||
{
|
{
|
||||||
@ -118,7 +107,6 @@ public void should_delete_files_that_do_not_belong_to_the_series_path()
|
|||||||
.Build();
|
.Build();
|
||||||
|
|
||||||
GivenEpisodeFiles(episodeFiles);
|
GivenEpisodeFiles(episodeFiles);
|
||||||
GivenFileIsNotInSeriesFolder();
|
|
||||||
|
|
||||||
Subject.Execute(new CleanMediaFileDb(0));
|
Subject.Execute(new CleanMediaFileDb(0));
|
||||||
|
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
using FluentMigrator;
|
|
||||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Datastore.Migration
|
|
||||||
{
|
|
||||||
[Migration(37)]
|
|
||||||
public class add_episode_file_metadata : NzbDroneMigrationBase
|
|
||||||
{
|
|
||||||
protected override void MainDbUpgrade()
|
|
||||||
{
|
|
||||||
Create.TableForModel("EpisodeFileMetaData")
|
|
||||||
.WithColumn("SeriesId").AsInt32().NotNullable()
|
|
||||||
.WithColumn("EpisodeFileId").AsInt32().NotNullable()
|
|
||||||
.WithColumn("Provider").AsString().NotNullable()
|
|
||||||
.WithColumn("Type").AsInt32().NotNullable()
|
|
||||||
.WithColumn("LastUpdated").AsDateTime().NotNullable()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
using FluentMigrator;
|
|
||||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Datastore.Migration
|
|
||||||
{
|
|
||||||
[Migration(37)]
|
|
||||||
public class add_metadata_consumers : NzbDroneMigrationBase
|
|
||||||
{
|
|
||||||
protected override void MainDbUpgrade()
|
|
||||||
{
|
|
||||||
Create.TableForModel("MetadataConsumers")
|
|
||||||
.WithColumn("Enable").AsBoolean().NotNullable()
|
|
||||||
.WithColumn("Name").AsString().NotNullable()
|
|
||||||
.WithColumn("Implementation").AsString().NotNullable()
|
|
||||||
.WithColumn("Settings").AsString().NotNullable()
|
|
||||||
.WithColumn("ConfigContract").AsString().NotNullable();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,28 @@
|
|||||||
|
using FluentMigrator;
|
||||||
|
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Datastore.Migration
|
||||||
|
{
|
||||||
|
[Migration(37)]
|
||||||
|
public class add_metadata_tables : NzbDroneMigrationBase
|
||||||
|
{
|
||||||
|
protected override void MainDbUpgrade()
|
||||||
|
{
|
||||||
|
Create.TableForModel("Metadata")
|
||||||
|
.WithColumn("Enable").AsBoolean().NotNullable()
|
||||||
|
.WithColumn("Name").AsString().NotNullable()
|
||||||
|
.WithColumn("Implementation").AsString().NotNullable()
|
||||||
|
.WithColumn("Settings").AsString().NotNullable()
|
||||||
|
.WithColumn("ConfigContract").AsString().NotNullable();
|
||||||
|
|
||||||
|
Create.TableForModel("MetadataFiles")
|
||||||
|
.WithColumn("SeriesId").AsInt32().NotNullable()
|
||||||
|
.WithColumn("Consumer").AsString().NotNullable()
|
||||||
|
.WithColumn("Type").AsInt32().NotNullable()
|
||||||
|
.WithColumn("RelativePath").AsString().NotNullable()
|
||||||
|
.WithColumn("LastUpdated").AsDateTime().NotNullable()
|
||||||
|
.WithColumn("SeasonNumber").AsInt32().Nullable()
|
||||||
|
.WithColumn("EpisodeFileId").AsInt32().Nullable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@
|
|||||||
using NzbDrone.Core.Jobs;
|
using NzbDrone.Core.Jobs;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
using NzbDrone.Core.Metadata;
|
using NzbDrone.Core.Metadata;
|
||||||
|
using NzbDrone.Core.Metadata.Files;
|
||||||
using NzbDrone.Core.Notifications;
|
using NzbDrone.Core.Notifications;
|
||||||
using NzbDrone.Core.Organizer;
|
using NzbDrone.Core.Organizer;
|
||||||
using NzbDrone.Core.Qualities;
|
using NzbDrone.Core.Qualities;
|
||||||
@ -37,7 +38,7 @@ public static void Map()
|
|||||||
Mapper.Entity<IndexerDefinition>().RegisterModel("Indexers");
|
Mapper.Entity<IndexerDefinition>().RegisterModel("Indexers");
|
||||||
Mapper.Entity<ScheduledTask>().RegisterModel("ScheduledTasks");
|
Mapper.Entity<ScheduledTask>().RegisterModel("ScheduledTasks");
|
||||||
Mapper.Entity<NotificationDefinition>().RegisterModel("Notifications");
|
Mapper.Entity<NotificationDefinition>().RegisterModel("Notifications");
|
||||||
Mapper.Entity<MetadataDefinition>().RegisterModel("MetadataConsumers");
|
Mapper.Entity<MetadataDefinition>().RegisterModel("Metadata");
|
||||||
|
|
||||||
Mapper.Entity<SceneMapping>().RegisterModel("SceneMappings");
|
Mapper.Entity<SceneMapping>().RegisterModel("SceneMappings");
|
||||||
|
|
||||||
@ -60,16 +61,13 @@ public static void Map()
|
|||||||
.Relationships.AutoMapICollectionOrComplexProperties();
|
.Relationships.AutoMapICollectionOrComplexProperties();
|
||||||
|
|
||||||
Mapper.Entity<QualityProfile>().RegisterModel("QualityProfiles");
|
Mapper.Entity<QualityProfile>().RegisterModel("QualityProfiles");
|
||||||
|
|
||||||
Mapper.Entity<QualityDefinition>().RegisterModel("QualityDefinitions");
|
Mapper.Entity<QualityDefinition>().RegisterModel("QualityDefinitions");
|
||||||
|
|
||||||
Mapper.Entity<Log>().RegisterModel("Logs");
|
Mapper.Entity<Log>().RegisterModel("Logs");
|
||||||
|
|
||||||
Mapper.Entity<NamingConfig>().RegisterModel("NamingConfig");
|
Mapper.Entity<NamingConfig>().RegisterModel("NamingConfig");
|
||||||
|
|
||||||
Mapper.Entity<SeriesStatistics>().MapResultSet();
|
Mapper.Entity<SeriesStatistics>().MapResultSet();
|
||||||
|
|
||||||
Mapper.Entity<Blacklist>().RegisterModel("Blacklist");
|
Mapper.Entity<Blacklist>().RegisterModel("Blacklist");
|
||||||
|
|
||||||
|
Mapper.Entity<MetadataFile>().RegisterModel("MetadataFiles");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RegisterMappers()
|
private static void RegisterMappers()
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using NzbDrone.Core.Datastore;
|
using NzbDrone.Core.Datastore;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
|
||||||
@ -9,6 +12,7 @@ public interface IMediaFileRepository : IBasicRepository<EpisodeFile>
|
|||||||
{
|
{
|
||||||
List<EpisodeFile> GetFilesBySeries(int seriesId);
|
List<EpisodeFile> GetFilesBySeries(int seriesId);
|
||||||
List<EpisodeFile> GetFilesBySeason(int seriesId, int seasonNumber);
|
List<EpisodeFile> GetFilesBySeason(int seriesId, int seasonNumber);
|
||||||
|
EpisodeFile FindFileByPath(string path, bool includeExtension = true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -31,5 +35,14 @@ public List<EpisodeFile> GetFilesBySeason(int seriesId, int seasonNumber)
|
|||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EpisodeFile FindFileByPath(string path, bool includeExtension = true)
|
||||||
|
{
|
||||||
|
if (includeExtension)
|
||||||
|
{
|
||||||
|
return Query.SingleOrDefault(c => c.Path == path);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Query.SingleOrDefault(c => c.Path.StartsWith(Path.ChangeExtension(path, "")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,6 +19,7 @@ public interface IMediaFileService
|
|||||||
List<string> FilterExistingFiles(List<string> files, int seriesId);
|
List<string> FilterExistingFiles(List<string> files, int seriesId);
|
||||||
EpisodeFile Get(int id);
|
EpisodeFile Get(int id);
|
||||||
List<EpisodeFile> Get(IEnumerable<int> ids);
|
List<EpisodeFile> Get(IEnumerable<int> ids);
|
||||||
|
EpisodeFile FindByPath(string path, bool includeExtension = true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MediaFileService : IMediaFileService, IHandleAsync<SeriesDeletedEvent>
|
public class MediaFileService : IMediaFileService, IHandleAsync<SeriesDeletedEvent>
|
||||||
@ -82,6 +83,11 @@ public List<EpisodeFile> Get(IEnumerable<int> ids)
|
|||||||
return _mediaFileRepository.Get(ids).ToList();
|
return _mediaFileRepository.Get(ids).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EpisodeFile FindByPath(string path, bool includeExtension = true)
|
||||||
|
{
|
||||||
|
return _mediaFileRepository.FindFileByPath(path, includeExtension);
|
||||||
|
}
|
||||||
|
|
||||||
public void HandleAsync(SeriesDeletedEvent message)
|
public void HandleAsync(SeriesDeletedEvent message)
|
||||||
{
|
{
|
||||||
var files = GetFilesBySeries(message.Series.Id);
|
var files = GetFilesBySeries(message.Series.Id);
|
||||||
|
@ -7,11 +7,12 @@
|
|||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common;
|
using NzbDrone.Common;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.Metadata.Files;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Metadata.Consumers.Fake
|
namespace NzbDrone.Core.Metadata.Consumers.Fake
|
||||||
{
|
{
|
||||||
public class FakeMetadata : MetadataConsumerBase<FakeMetadataSettings>
|
public class FakeMetadata : MetadataBase<FakeMetadataSettings>
|
||||||
{
|
{
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
private readonly IHttpProvider _httpProvider;
|
private readonly IHttpProvider _httpProvider;
|
||||||
@ -25,19 +26,24 @@ public FakeMetadata(IDiskProvider diskProvider, IHttpProvider httpProvider, Logg
|
|||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnSeriesUpdated(Series series)
|
public override void OnSeriesUpdated(Tv.Series series)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnEpisodeImport(Series series, EpisodeFile episodeFile, bool newDownload)
|
public override void OnEpisodeImport(Tv.Series series, EpisodeFile episodeFile, bool newDownload)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void AfterRename(Series series)
|
public override void AfterRename(Tv.Series series)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override MetadataFile FindMetadataFile(Series series, string path)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
@ -10,21 +10,25 @@
|
|||||||
using NzbDrone.Core.MediaCover;
|
using NzbDrone.Core.MediaCover;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Metadata.Events;
|
using NzbDrone.Core.Metadata.Files;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Metadata.Consumers.Xbmc
|
namespace NzbDrone.Core.Metadata.Consumers.Xbmc
|
||||||
{
|
{
|
||||||
public class XbmcMetadata : MetadataConsumerBase<XbmcMetadataSettings>
|
public class XbmcMetadata : MetadataBase<XbmcMetadataSettings>
|
||||||
{
|
{
|
||||||
private readonly IEventAggregator _eventAggregator;
|
private readonly IEventAggregator _eventAggregator;
|
||||||
private readonly IMapCoversToLocal _mediaCoverService;
|
private readonly IMapCoversToLocal _mediaCoverService;
|
||||||
|
private readonly IMediaFileService _mediaFileService;
|
||||||
|
private readonly IMetadataFileService _metadataFileService;
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
private readonly IHttpProvider _httpProvider;
|
private readonly IHttpProvider _httpProvider;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public XbmcMetadata(IEventAggregator eventAggregator,
|
public XbmcMetadata(IEventAggregator eventAggregator,
|
||||||
IMapCoversToLocal mediaCoverService,
|
IMapCoversToLocal mediaCoverService,
|
||||||
|
IMediaFileService mediaFileService,
|
||||||
|
IMetadataFileService metadataFileService,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IHttpProvider httpProvider,
|
IHttpProvider httpProvider,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
@ -32,11 +36,17 @@ public XbmcMetadata(IEventAggregator eventAggregator,
|
|||||||
{
|
{
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
_mediaCoverService = mediaCoverService;
|
_mediaCoverService = mediaCoverService;
|
||||||
|
_mediaFileService = mediaFileService;
|
||||||
|
_metadataFileService = metadataFileService;
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
_httpProvider = httpProvider;
|
_httpProvider = httpProvider;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly Regex SeriesImagesRegex = new Regex(@"^(?<type>poster|banner|fanart)\.(?:png|jpg)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
private static readonly Regex SeasonImagesRegex = new Regex(@"^season(?<season>\d{2,}|-all|-specials)-(?<type>poster|banner|fanart)\.(?:png|jpg)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
private static readonly Regex EpisodeImageRegex = new Regex(@"-thumb\.(?:png|jpg)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
|
|
||||||
public override void OnSeriesUpdated(Series series)
|
public override void OnSeriesUpdated(Series series)
|
||||||
{
|
{
|
||||||
if (Settings.SeriesMetadata)
|
if (Settings.SeriesMetadata)
|
||||||
@ -62,7 +72,7 @@ public override void OnEpisodeImport(Series series, EpisodeFile episodeFile, boo
|
|||||||
{
|
{
|
||||||
if (Settings.EpisodeMetadata)
|
if (Settings.EpisodeMetadata)
|
||||||
{
|
{
|
||||||
WriteEpisodeNfo(episodeFile);
|
WriteEpisodeNfo(series, episodeFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings.EpisodeImages)
|
if (Settings.EpisodeImages)
|
||||||
@ -73,9 +83,97 @@ public override void OnEpisodeImport(Series series, EpisodeFile episodeFile, boo
|
|||||||
|
|
||||||
public override void AfterRename(Series series)
|
public override void AfterRename(Series series)
|
||||||
{
|
{
|
||||||
//TODO: Rename media files to match episode files
|
var episodeFiles = _mediaFileService.GetFilesBySeries(series.Id);
|
||||||
|
var episodeFilesMetadata = _metadataFileService.GetFilesBySeries(series.Id).Where(c => c.EpisodeFileId > 0).ToList();
|
||||||
|
|
||||||
throw new NotImplementedException();
|
foreach (var episodeFile in episodeFiles)
|
||||||
|
{
|
||||||
|
var metadataFiles = episodeFilesMetadata.Where(m => m.EpisodeFileId == episodeFile.Id).ToList();
|
||||||
|
var episodeFilenameWithoutExtension =
|
||||||
|
Path.GetFileNameWithoutExtension(DiskProvider.GetRelativePath(series.Path, episodeFile.Path));
|
||||||
|
|
||||||
|
foreach (var metadataFile in metadataFiles)
|
||||||
|
{
|
||||||
|
var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(metadataFile.RelativePath);
|
||||||
|
var extension = Path.GetExtension(metadataFile.RelativePath);
|
||||||
|
|
||||||
|
if (!fileNameWithoutExtension.Equals(episodeFilenameWithoutExtension))
|
||||||
|
{
|
||||||
|
var source = Path.Combine(series.Path, metadataFile.RelativePath);
|
||||||
|
var destination = Path.Combine(series.Path, fileNameWithoutExtension + extension);
|
||||||
|
|
||||||
|
_diskProvider.MoveFile(source, destination);
|
||||||
|
metadataFile.RelativePath = fileNameWithoutExtension + extension;
|
||||||
|
|
||||||
|
_eventAggregator.PublishEvent(new MetadataFileUpdated(metadataFile));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override MetadataFile FindMetadataFile(Series series, string path)
|
||||||
|
{
|
||||||
|
var filename = Path.GetFileName(path);
|
||||||
|
|
||||||
|
if (filename == null) return null;
|
||||||
|
|
||||||
|
var metadata = new MetadataFile
|
||||||
|
{
|
||||||
|
SeriesId = series.Id,
|
||||||
|
Consumer = GetType().Name,
|
||||||
|
RelativePath = DiskProvider.GetRelativePath(series.Path, path)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (SeriesImagesRegex.IsMatch(filename))
|
||||||
|
{
|
||||||
|
metadata.Type = MetadataType.SeriesImage;
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
var seasonMatch = SeasonImagesRegex.Match(filename);
|
||||||
|
|
||||||
|
if (seasonMatch.Success)
|
||||||
|
{
|
||||||
|
metadata.Type = MetadataType.SeasonImage;
|
||||||
|
|
||||||
|
var seasonNumber = seasonMatch.Groups["season"].Value;
|
||||||
|
|
||||||
|
if (seasonNumber.Contains("specials"))
|
||||||
|
{
|
||||||
|
metadata.SeasonNumber = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
metadata.SeasonNumber = Convert.ToInt32(seasonNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EpisodeImageRegex.IsMatch(filename))
|
||||||
|
{
|
||||||
|
metadata.Type = MetadataType.EpisodeImage;
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filename.Equals("tvshow.nfo", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
metadata.Type = MetadataType.SeriesMetadata;
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
var parseResult = Parser.Parser.ParseTitle(filename);
|
||||||
|
|
||||||
|
if (parseResult != null &&
|
||||||
|
!parseResult.FullSeason &&
|
||||||
|
Path.GetExtension(filename) == ".nfo")
|
||||||
|
{
|
||||||
|
metadata.Type = MetadataType.EpisodeMetadata;
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteTvShowNfo(Series series)
|
private void WriteTvShowNfo(Series series)
|
||||||
@ -130,7 +228,15 @@ private void WriteTvShowNfo(Series series)
|
|||||||
|
|
||||||
_diskProvider.WriteAllText(path, doc.ToString());
|
_diskProvider.WriteAllText(path, doc.ToString());
|
||||||
|
|
||||||
_eventAggregator.PublishEvent(new SeriesMetadataUpdated(series, GetType().Name, MetadataType.SeriesMetadata, DiskProvider.GetRelativePath(series.Path, path)));
|
var metadata = new MetadataFile
|
||||||
|
{
|
||||||
|
SeriesId = series.Id,
|
||||||
|
Consumer = GetType().Name,
|
||||||
|
Type = MetadataType.SeriesMetadata,
|
||||||
|
RelativePath = DiskProvider.GetRelativePath(series.Path, path)
|
||||||
|
};
|
||||||
|
|
||||||
|
_eventAggregator.PublishEvent(new MetadataFileUpdated(metadata));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +255,16 @@ private void WriteSeriesImages(Series series)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_diskProvider.CopyFile(source, destination, false);
|
_diskProvider.CopyFile(source, destination, false);
|
||||||
_eventAggregator.PublishEvent(new SeriesMetadataUpdated(series, GetType().Name, MetadataType.SeriesImage, DiskProvider.GetRelativePath(series.Path, destination)));
|
|
||||||
|
var metadata = new MetadataFile
|
||||||
|
{
|
||||||
|
SeriesId = series.Id,
|
||||||
|
Consumer = GetType().Name,
|
||||||
|
Type = MetadataType.SeriesImage,
|
||||||
|
RelativePath = DiskProvider.GetRelativePath(series.Path, destination)
|
||||||
|
};
|
||||||
|
|
||||||
|
_eventAggregator.PublishEvent(new MetadataFileUpdated(metadata));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,12 +284,22 @@ private void WriteSeasonImages(Series series)
|
|||||||
var path = Path.Combine(series.Path, filename);
|
var path = Path.Combine(series.Path, filename);
|
||||||
|
|
||||||
DownloadImage(series, image.Url, path);
|
DownloadImage(series, image.Url, path);
|
||||||
_eventAggregator.PublishEvent(new SeasonMetadataUpdated(series, season.SeasonNumber, GetType().Name, MetadataType.SeasonImage, DiskProvider.GetRelativePath(series.Path, path)));
|
|
||||||
|
var metadata = new MetadataFile
|
||||||
|
{
|
||||||
|
SeriesId = series.Id,
|
||||||
|
SeasonNumber = season.SeasonNumber,
|
||||||
|
Consumer = GetType().Name,
|
||||||
|
Type = MetadataType.SeasonImage,
|
||||||
|
RelativePath = DiskProvider.GetRelativePath(series.Path, path)
|
||||||
|
};
|
||||||
|
|
||||||
|
_eventAggregator.PublishEvent(new MetadataFileUpdated(metadata));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteEpisodeNfo(EpisodeFile episodeFile)
|
private void WriteEpisodeNfo(Series series, EpisodeFile episodeFile)
|
||||||
{
|
{
|
||||||
var filename = episodeFile.Path.Replace(Path.GetExtension(episodeFile.Path), ".nfo");
|
var filename = episodeFile.Path.Replace(Path.GetExtension(episodeFile.Path), ".nfo");
|
||||||
|
|
||||||
@ -218,15 +343,37 @@ private void WriteEpisodeNfo(EpisodeFile episodeFile)
|
|||||||
|
|
||||||
_logger.Debug("Saving episodedetails to: {0}", filename);
|
_logger.Debug("Saving episodedetails to: {0}", filename);
|
||||||
_diskProvider.WriteAllText(filename, xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
_diskProvider.WriteAllText(filename, xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||||
|
|
||||||
|
var metadata = new MetadataFile
|
||||||
|
{
|
||||||
|
SeriesId = series.Id,
|
||||||
|
EpisodeFileId = episodeFile.Id,
|
||||||
|
Consumer = GetType().Name,
|
||||||
|
Type = MetadataType.SeasonImage,
|
||||||
|
RelativePath = DiskProvider.GetRelativePath(series.Path, filename)
|
||||||
|
};
|
||||||
|
|
||||||
|
_eventAggregator.PublishEvent(new MetadataFileUpdated(metadata));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WriteEpisodeImages(Series series, EpisodeFile episodeFile)
|
private void WriteEpisodeImages(Series series, EpisodeFile episodeFile)
|
||||||
{
|
{
|
||||||
var screenshot = episodeFile.Episodes.Value.First().Images.Single(i => i.CoverType == MediaCoverTypes.Screenshot);
|
var screenshot = episodeFile.Episodes.Value.First().Images.Single(i => i.CoverType == MediaCoverTypes.Screenshot);
|
||||||
var filename = Path.ChangeExtension(episodeFile.Path, "jpg");
|
|
||||||
|
var filename = Path.GetFileNameWithoutExtension(episodeFile.Path) + "-thumb.jpg";
|
||||||
|
|
||||||
DownloadImage(series, screenshot.Url, filename);
|
DownloadImage(series, screenshot.Url, filename);
|
||||||
_eventAggregator.PublishEvent(new EpisodeMetadataUpdated(series, episodeFile, GetType().Name, MetadataType.SeasonImage, DiskProvider.GetRelativePath(series.Path, filename)));
|
|
||||||
|
var metadata = new MetadataFile
|
||||||
|
{
|
||||||
|
SeriesId = series.Id,
|
||||||
|
EpisodeFileId = episodeFile.Id,
|
||||||
|
Consumer = GetType().Name,
|
||||||
|
Type = MetadataType.SeasonImage,
|
||||||
|
RelativePath = DiskProvider.GetRelativePath(series.Path, filename)
|
||||||
|
};
|
||||||
|
|
||||||
|
_eventAggregator.PublishEvent(new MetadataFileUpdated(metadata));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
using System;
|
|
||||||
using NzbDrone.Common.Messaging;
|
|
||||||
using NzbDrone.Core.MediaFiles;
|
|
||||||
using NzbDrone.Core.Tv;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Metadata.Events
|
|
||||||
{
|
|
||||||
public class EpisodeMetadataUpdated : IEvent
|
|
||||||
{
|
|
||||||
public Series Series { get; set; }
|
|
||||||
public EpisodeFile EpisodeFile { get; set; }
|
|
||||||
public String Consumer { get; set; }
|
|
||||||
public MetadataType MetadataType { get; set; }
|
|
||||||
public String Path { get; set; }
|
|
||||||
|
|
||||||
public EpisodeMetadataUpdated(Series series, EpisodeFile episodeFile, string consumer, MetadataType metadataType, string path)
|
|
||||||
{
|
|
||||||
Series = series;
|
|
||||||
EpisodeFile = episodeFile;
|
|
||||||
Consumer = consumer;
|
|
||||||
MetadataType = metadataType;
|
|
||||||
Path = path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
using System;
|
|
||||||
using NzbDrone.Common.Messaging;
|
|
||||||
using NzbDrone.Core.Tv;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Metadata.Events
|
|
||||||
{
|
|
||||||
public class SeasonMetadataUpdated : IEvent
|
|
||||||
{
|
|
||||||
public Series Series { get; set; }
|
|
||||||
public Int32 SeasonNumber { get; set; }
|
|
||||||
public String Consumer { get; set; }
|
|
||||||
public MetadataType MetadataType { get; set; }
|
|
||||||
public String Path { get; set; }
|
|
||||||
|
|
||||||
public SeasonMetadataUpdated(Series series, int seasonNumber, string consumer, MetadataType metadataType, string path)
|
|
||||||
{
|
|
||||||
Series = series;
|
|
||||||
SeasonNumber = seasonNumber;
|
|
||||||
Consumer = consumer;
|
|
||||||
MetadataType = metadataType;
|
|
||||||
Path = path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
using System;
|
|
||||||
using NzbDrone.Common.Messaging;
|
|
||||||
using NzbDrone.Core.Tv;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Metadata.Events
|
|
||||||
{
|
|
||||||
public class SeriesMetadataUpdated : IEvent
|
|
||||||
{
|
|
||||||
public Series Series { get; set; }
|
|
||||||
public String Consumer { get; set; }
|
|
||||||
public MetadataType MetadataType { get; set; }
|
|
||||||
public String Path { get; set; }
|
|
||||||
|
|
||||||
public SeriesMetadataUpdated(Series series, string consumer, MetadataType metadataType, string path)
|
|
||||||
{
|
|
||||||
Series = series;
|
|
||||||
Consumer = consumer;
|
|
||||||
MetadataType = metadataType;
|
|
||||||
Path = path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +1,5 @@
|
|||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.Metadata.Files;
|
||||||
using NzbDrone.Core.ThingiProvider;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
@ -9,5 +10,6 @@ public interface IMetadata : IProvider
|
|||||||
void OnSeriesUpdated(Series series);
|
void OnSeriesUpdated(Series series);
|
||||||
void OnEpisodeImport(Series series, EpisodeFile episodeFile, bool newDownload);
|
void OnEpisodeImport(Series series, EpisodeFile episodeFile, bool newDownload);
|
||||||
void AfterRename(Series series);
|
void AfterRename(Series series);
|
||||||
|
MetadataFile FindMetadataFile(Series series, string path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
using NLog;
|
using System.IO;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common;
|
||||||
using NzbDrone.Core.MediaFiles.Events;
|
using NzbDrone.Core.MediaFiles.Events;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
using NzbDrone.Core.Tv.Events;
|
using NzbDrone.Core.Tv.Events;
|
||||||
@ -11,13 +13,11 @@ public class NotificationService
|
|||||||
IHandle<SeriesRenamedEvent>
|
IHandle<SeriesRenamedEvent>
|
||||||
{
|
{
|
||||||
private readonly IMetadataFactory _metadataFactory;
|
private readonly IMetadataFactory _metadataFactory;
|
||||||
private readonly IMetadataRepository _metadataRepository;
|
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public NotificationService(IMetadataFactory metadataFactory, IMetadataRepository metadataRepository, Logger logger)
|
public NotificationService(IMetadataFactory metadataFactory, Logger logger)
|
||||||
{
|
{
|
||||||
_metadataFactory = metadataFactory;
|
_metadataFactory = metadataFactory;
|
||||||
_metadataRepository = metadataRepository;
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
70
src/NzbDrone.Core/Metadata/ExistingMetadataService.cs
Normal file
70
src/NzbDrone.Core/Metadata/ExistingMetadataService.cs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.Metadata.Files;
|
||||||
|
using NzbDrone.Core.Tv.Events;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Metadata
|
||||||
|
{
|
||||||
|
public class ExistingMetadataService : IHandleAsync<SeriesUpdatedEvent>
|
||||||
|
{
|
||||||
|
private readonly IDiskProvider _diskProvider;
|
||||||
|
private readonly IMetadataFileService _metadataFileService;
|
||||||
|
private readonly IMediaFileService _mediaFileService;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
private readonly List<IMetadata> _consumers;
|
||||||
|
|
||||||
|
public ExistingMetadataService(IDiskProvider diskProvider,
|
||||||
|
IEnumerable<IMetadata> consumers,
|
||||||
|
IMetadataFileService metadataFileService,
|
||||||
|
IMediaFileService mediaFileService,
|
||||||
|
Logger logger)
|
||||||
|
{
|
||||||
|
_diskProvider = diskProvider;
|
||||||
|
_metadataFileService = metadataFileService;
|
||||||
|
_mediaFileService = mediaFileService;
|
||||||
|
_logger = logger;
|
||||||
|
_consumers = consumers.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleAsync(SeriesUpdatedEvent message)
|
||||||
|
{
|
||||||
|
if (!_diskProvider.FolderExists(message.Series.Path)) return;
|
||||||
|
|
||||||
|
_logger.Trace("Looking for existing metadata in {0}", message.Series.Path);
|
||||||
|
|
||||||
|
var filesOnDisk = _diskProvider.GetFiles(message.Series.Path, SearchOption.AllDirectories);
|
||||||
|
var possibleMetadataFiles = filesOnDisk.Where(c => !MediaFileExtensions.Extensions.Contains(Path.GetExtension(c).ToLower())).ToList();
|
||||||
|
var filteredFiles = _metadataFileService.FilterExistingFiles(possibleMetadataFiles, message.Series);
|
||||||
|
|
||||||
|
foreach (var possibleMetadataFile in filteredFiles)
|
||||||
|
{
|
||||||
|
foreach (var consumer in _consumers)
|
||||||
|
{
|
||||||
|
var metadata = consumer.FindMetadataFile(message.Series, possibleMetadataFile);
|
||||||
|
|
||||||
|
if (metadata == null) continue;
|
||||||
|
|
||||||
|
if (metadata.Type == MetadataType.EpisodeImage ||
|
||||||
|
metadata.Type == MetadataType.EpisodeMetadata)
|
||||||
|
{
|
||||||
|
//TODO: replace this with parser lookup, otherwise its impossible to link thumbs without knowing too much about the consumers
|
||||||
|
//We might want to resort to parsing the file name and
|
||||||
|
//then finding it via episodes incase the file names get out of sync
|
||||||
|
var episodeFile = _mediaFileService.FindByPath(possibleMetadataFile, false);
|
||||||
|
|
||||||
|
if (episodeFile == null) break;
|
||||||
|
|
||||||
|
metadata.EpisodeFileId = episodeFile.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
_metadataFileService.Upsert(metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/NzbDrone.Core/Metadata/Files/MetadataFile.cs
Normal file
16
src/NzbDrone.Core/Metadata/Files/MetadataFile.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Metadata.Files
|
||||||
|
{
|
||||||
|
public class MetadataFile : ModelBase
|
||||||
|
{
|
||||||
|
public Int32 SeriesId { get; set; }
|
||||||
|
public String Consumer { get; set; }
|
||||||
|
public MetadataType Type { get; set; }
|
||||||
|
public String RelativePath { get; set; }
|
||||||
|
public DateTime LastUpdated { get; set; }
|
||||||
|
public Int32? EpisodeFileId { get; set; }
|
||||||
|
public Int32? SeasonNumber { get; set; }
|
||||||
|
}
|
||||||
|
}
|
62
src/NzbDrone.Core/Metadata/Files/MetadataFileRepository.cs
Normal file
62
src/NzbDrone.Core/Metadata/Files/MetadataFileRepository.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NzbDrone.Core.Datastore;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Metadata.Files
|
||||||
|
{
|
||||||
|
public interface IMetadataFileRepository : IBasicRepository<MetadataFile>
|
||||||
|
{
|
||||||
|
void DeleteForSeries(int seriesId);
|
||||||
|
void DeleteForSeason(int seriesId, int seasonNumber);
|
||||||
|
void DeleteForEpisodeFile(int episodeFileId);
|
||||||
|
List<MetadataFile> GetFilesBySeries(int seriesId);
|
||||||
|
List<MetadataFile> GetFilesBySeason(int seriesId, int seasonNumber);
|
||||||
|
List<MetadataFile> GetFilesByEpisodeFile(int episodeFileId);
|
||||||
|
MetadataFile FindByPath(string path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MetadataFileRepository : BasicRepository<MetadataFile>, IMetadataFileRepository
|
||||||
|
{
|
||||||
|
public MetadataFileRepository(IDatabase database, IEventAggregator eventAggregator)
|
||||||
|
: base(database, eventAggregator)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteForSeries(int seriesId)
|
||||||
|
{
|
||||||
|
Delete(c => c.SeriesId == seriesId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteForSeason(int seriesId, int seasonNumber)
|
||||||
|
{
|
||||||
|
Delete(c => c.SeriesId == seriesId && c.SeasonNumber == seasonNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteForEpisodeFile(int episodeFileId)
|
||||||
|
{
|
||||||
|
Delete(c => c.EpisodeFileId == episodeFileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MetadataFile> GetFilesBySeries(int seriesId)
|
||||||
|
{
|
||||||
|
return Query.Where(c => c.SeriesId == seriesId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MetadataFile> GetFilesBySeason(int seriesId, int seasonNumber)
|
||||||
|
{
|
||||||
|
return Query.Where(c => c.SeriesId == seriesId && c.SeasonNumber == seasonNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MetadataFile> GetFilesByEpisodeFile(int episodeFileId)
|
||||||
|
{
|
||||||
|
return Query.Where(c => c.EpisodeFileId == episodeFileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetadataFile FindByPath(string path)
|
||||||
|
{
|
||||||
|
return Query.SingleOrDefault(c => c.RelativePath == path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
104
src/NzbDrone.Core/Metadata/Files/MetadataFileService.cs
Normal file
104
src/NzbDrone.Core/Metadata/Files/MetadataFileService.cs
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.MediaFiles.Events;
|
||||||
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Core.Tv.Events;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Metadata.Files
|
||||||
|
{
|
||||||
|
public interface IMetadataFileService
|
||||||
|
{
|
||||||
|
List<MetadataFile> GetFilesBySeries(int seriesId);
|
||||||
|
List<MetadataFile> GetFilesByEpisodeFile(int episodeFileId);
|
||||||
|
MetadataFile FindByPath(string path);
|
||||||
|
List<string> FilterExistingFiles(List<string> files, Series series);
|
||||||
|
MetadataFile Upsert(MetadataFile metadataFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MetadataFileService : IMetadataFileService,
|
||||||
|
IHandleAsync<SeriesDeletedEvent>,
|
||||||
|
IHandleAsync<EpisodeFileDeletedEvent>,
|
||||||
|
IHandle<MetadataFileUpdated>
|
||||||
|
{
|
||||||
|
private readonly IMetadataFileRepository _repository;
|
||||||
|
private readonly ISeriesService _seriesService;
|
||||||
|
private readonly IDiskProvider _diskProvider;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public MetadataFileService(IMetadataFileRepository repository,
|
||||||
|
ISeriesService seriesService,
|
||||||
|
IDiskProvider diskProvider,
|
||||||
|
Logger logger)
|
||||||
|
{
|
||||||
|
_repository = repository;
|
||||||
|
_seriesService = seriesService;
|
||||||
|
_diskProvider = diskProvider;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MetadataFile> GetFilesBySeries(int seriesId)
|
||||||
|
{
|
||||||
|
return _repository.GetFilesBySeries(seriesId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<MetadataFile> GetFilesByEpisodeFile(int episodeFileId)
|
||||||
|
{
|
||||||
|
return _repository.GetFilesByEpisodeFile(episodeFileId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetadataFile FindByPath(string path)
|
||||||
|
{
|
||||||
|
return _repository.FindByPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> FilterExistingFiles(List<string> files, Series series)
|
||||||
|
{
|
||||||
|
var seriesFiles = GetFilesBySeries(series.Id).Select(f => Path.Combine(series.Path, f.RelativePath)).ToList();
|
||||||
|
|
||||||
|
if (!seriesFiles.Any()) return files;
|
||||||
|
|
||||||
|
return files.Except(seriesFiles, PathEqualityComparer.Instance).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MetadataFile Upsert(MetadataFile metadataFile)
|
||||||
|
{
|
||||||
|
metadataFile.LastUpdated = DateTime.UtcNow;
|
||||||
|
return _repository.Upsert(metadataFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleAsync(SeriesDeletedEvent message)
|
||||||
|
{
|
||||||
|
_logger.Trace("Deleting Metadata from database for series: {0}", message.Series);
|
||||||
|
_repository.DeleteForSeries(message.Series.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleAsync(EpisodeFileDeletedEvent message)
|
||||||
|
{
|
||||||
|
var episodeFile = message.EpisodeFile;
|
||||||
|
var series = _seriesService.GetSeries(message.EpisodeFile.SeriesId);
|
||||||
|
|
||||||
|
foreach (var metadata in _repository.GetFilesByEpisodeFile(episodeFile.Id))
|
||||||
|
{
|
||||||
|
var path = Path.Combine(series.Path, metadata.RelativePath);
|
||||||
|
|
||||||
|
if (_diskProvider.FileExists(path))
|
||||||
|
{
|
||||||
|
_diskProvider.DeleteFile(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Trace("Deleting Metadata from database for episode file: {0}", episodeFile);
|
||||||
|
_repository.DeleteForEpisodeFile(episodeFile.Id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(MetadataFileUpdated message)
|
||||||
|
{
|
||||||
|
Upsert(message.Metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
14
src/NzbDrone.Core/Metadata/Files/MetadataFileUpdated.cs
Normal file
14
src/NzbDrone.Core/Metadata/Files/MetadataFileUpdated.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using NzbDrone.Common.Messaging;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Metadata.Files
|
||||||
|
{
|
||||||
|
public class MetadataFileUpdated : IEvent
|
||||||
|
{
|
||||||
|
public MetadataFile Metadata { get; set; }
|
||||||
|
|
||||||
|
public MetadataFileUpdated(MetadataFile metadata)
|
||||||
|
{
|
||||||
|
Metadata = metadata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,22 +1,22 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common;
|
using NzbDrone.Common;
|
||||||
using NzbDrone.Core.MediaFiles;
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.Metadata.Files;
|
||||||
using NzbDrone.Core.ThingiProvider;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Metadata
|
namespace NzbDrone.Core.Metadata
|
||||||
{
|
{
|
||||||
public abstract class MetadataConsumerBase<TSettings> : IMetadata where TSettings : IProviderConfig, new()
|
public abstract class MetadataBase<TSettings> : IMetadata where TSettings : IProviderConfig, new()
|
||||||
{
|
{
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
private readonly IHttpProvider _httpProvider;
|
private readonly IHttpProvider _httpProvider;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
protected MetadataConsumerBase(IDiskProvider diskProvider, IHttpProvider httpProvider, Logger logger)
|
protected MetadataBase(IDiskProvider diskProvider, IHttpProvider httpProvider, Logger logger)
|
||||||
{
|
{
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
_httpProvider = httpProvider;
|
_httpProvider = httpProvider;
|
||||||
@ -44,6 +44,7 @@ public IEnumerable<ProviderDefinition> DefaultDefinitions
|
|||||||
public abstract void OnSeriesUpdated(Series series);
|
public abstract void OnSeriesUpdated(Series series);
|
||||||
public abstract void OnEpisodeImport(Series series, EpisodeFile episodeFile, bool newDownload);
|
public abstract void OnEpisodeImport(Series series, EpisodeFile episodeFile, bool newDownload);
|
||||||
public abstract void AfterRename(Series series);
|
public abstract void AfterRename(Series series);
|
||||||
|
public abstract MetadataFile FindMetadataFile(Series series, string path);
|
||||||
|
|
||||||
protected TSettings Settings
|
protected TSettings Settings
|
||||||
{
|
{
|
@ -230,7 +230,11 @@ private static Tv.Ratings GetRatings(Trakt.Ratings ratings)
|
|||||||
SeasonNumber = traktSeason.season
|
SeasonNumber = traktSeason.season
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (traktSeason.images != null)
|
||||||
|
{
|
||||||
season.Images.Add(new MediaCover.MediaCover(MediaCoverTypes.Poster, traktSeason.images.poster));
|
season.Images.Add(new MediaCover.MediaCover(MediaCoverTypes.Poster, traktSeason.images.poster));
|
||||||
|
}
|
||||||
|
|
||||||
seasons.Add(season);
|
seasons.Add(season);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@
|
|||||||
<Compile Include="Datastore\Migration\037_add_configurable_qualities.cs" />
|
<Compile Include="Datastore\Migration\037_add_configurable_qualities.cs" />
|
||||||
<Compile Include="Datastore\Migration\038_add_on_upgrade_to_notifications.cs" />
|
<Compile Include="Datastore\Migration\038_add_on_upgrade_to_notifications.cs" />
|
||||||
<Compile Include="Datastore\Migration\036_add_metadata_to_episodes_and_series.cs" />
|
<Compile Include="Datastore\Migration\036_add_metadata_to_episodes_and_series.cs" />
|
||||||
<Compile Include="Datastore\Migration\037_add_metadata_consumers.cs" />
|
<Compile Include="Datastore\Migration\037_add_metadata_tables.cs" />
|
||||||
<Compile Include="Datastore\Migration\Framework\MigrationContext.cs" />
|
<Compile Include="Datastore\Migration\Framework\MigrationContext.cs" />
|
||||||
<Compile Include="Datastore\Migration\Framework\MigrationController.cs" />
|
<Compile Include="Datastore\Migration\Framework\MigrationController.cs" />
|
||||||
<Compile Include="Datastore\Migration\Framework\MigrationExtension.cs" />
|
<Compile Include="Datastore\Migration\Framework\MigrationExtension.cs" />
|
||||||
@ -319,11 +319,13 @@
|
|||||||
<Compile Include="Metadata\Consumers\Fake\FakeSettings.cs" />
|
<Compile Include="Metadata\Consumers\Fake\FakeSettings.cs" />
|
||||||
<Compile Include="Metadata\Consumers\Xbmc\XbmcMetadata.cs" />
|
<Compile Include="Metadata\Consumers\Xbmc\XbmcMetadata.cs" />
|
||||||
<Compile Include="Metadata\Consumers\Xbmc\XbmcMetadataSettings.cs" />
|
<Compile Include="Metadata\Consumers\Xbmc\XbmcMetadataSettings.cs" />
|
||||||
<Compile Include="Metadata\Events\EpisodeMetadataUpdated.cs" />
|
<Compile Include="Metadata\ExistingMetadataService.cs" />
|
||||||
<Compile Include="Metadata\Events\SeasonMetadataUpdated.cs" />
|
<Compile Include="Metadata\Files\MetadataFile.cs" />
|
||||||
<Compile Include="Metadata\Events\SeriesMetadataUpdated.cs" />
|
<Compile Include="Metadata\Files\MetadataFileRepository.cs" />
|
||||||
|
<Compile Include="Metadata\Files\MetadataFileService.cs" />
|
||||||
|
<Compile Include="Metadata\Files\MetadataFileUpdated.cs" />
|
||||||
<Compile Include="Metadata\IMetadata.cs" />
|
<Compile Include="Metadata\IMetadata.cs" />
|
||||||
<Compile Include="Metadata\MetadataConsumerBase.cs" />
|
<Compile Include="Metadata\MetadataBase.cs" />
|
||||||
<Compile Include="MetadataSource\Trakt\TraktException.cs" />
|
<Compile Include="MetadataSource\Trakt\TraktException.cs" />
|
||||||
<Compile Include="Metadata\MetadataDefinition.cs" />
|
<Compile Include="Metadata\MetadataDefinition.cs" />
|
||||||
<Compile Include="Metadata\MetadataFactory.cs" />
|
<Compile Include="Metadata\MetadataFactory.cs" />
|
||||||
@ -696,9 +698,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Download\Clients\uTorrent\" />
|
<Folder Include="Download\Clients\uTorrent\" />
|
||||||
<Folder Include="Metadata\EpisodeFiles\" />
|
|
||||||
<Folder Include="Metadata\Seasons\" />
|
|
||||||
<Folder Include="Metadata\Series\" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
Loading…
Reference in New Issue
Block a user