mirror of https://github.com/lidarr/Lidarr
At a point where we can build. Many TODOs and existing Series-based APIs need to be removed. No track code actually works.
This commit is contained in:
parent
235e753b93
commit
1024555f75
|
@ -11,6 +11,7 @@ using NzbDrone.Core.Messaging.Events;
|
|||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.SignalR;
|
||||
using System;
|
||||
|
||||
namespace NzbDrone.Api.EpisodeFiles
|
||||
{
|
||||
|
@ -47,24 +48,26 @@ namespace NzbDrone.Api.EpisodeFiles
|
|||
|
||||
private EpisodeFileResource GetEpisodeFile(int id)
|
||||
{
|
||||
var episodeFile = _mediaFileService.Get(id);
|
||||
var series = _seriesService.GetSeries(episodeFile.SeriesId);
|
||||
throw new NotImplementedException();
|
||||
//var episodeFile = _mediaFileService.Get(id);
|
||||
//var series = _seriesService.GetSeries(episodeFile.SeriesId);
|
||||
|
||||
return episodeFile.ToResource(series, _qualityUpgradableSpecification);
|
||||
//return episodeFile.ToResource(series, _qualityUpgradableSpecification);
|
||||
}
|
||||
|
||||
private List<EpisodeFileResource> GetEpisodeFiles()
|
||||
{
|
||||
if (!Request.Query.SeriesId.HasValue)
|
||||
{
|
||||
throw new BadRequestException("seriesId is missing");
|
||||
}
|
||||
throw new NotImplementedException();
|
||||
//if (!Request.Query.SeriesId.HasValue)
|
||||
//{
|
||||
// throw new BadRequestException("seriesId is missing");
|
||||
//}
|
||||
|
||||
var seriesId = (int)Request.Query.SeriesId;
|
||||
//var seriesId = (int)Request.Query.SeriesId;
|
||||
|
||||
var series = _seriesService.GetSeries(seriesId);
|
||||
//var series = _seriesService.GetSeries(seriesId);
|
||||
|
||||
return _mediaFileService.GetFilesBySeries(seriesId).ConvertAll(f => f.ToResource(series, _qualityUpgradableSpecification));
|
||||
//return _mediaFileService.GetFilesBySeries(seriesId).ConvertAll(f => f.ToResource(series, _qualityUpgradableSpecification));
|
||||
}
|
||||
|
||||
private void SetQuality(EpisodeFileResource episodeFileResource)
|
||||
|
@ -76,14 +79,15 @@ namespace NzbDrone.Api.EpisodeFiles
|
|||
|
||||
private void DeleteEpisodeFile(int id)
|
||||
{
|
||||
var episodeFile = _mediaFileService.Get(id);
|
||||
var series = _seriesService.GetSeries(episodeFile.SeriesId);
|
||||
var fullPath = Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
var subfolder = _diskProvider.GetParentFolder(series.Path).GetRelativePath(_diskProvider.GetParentFolder(fullPath));
|
||||
throw new NotImplementedException();
|
||||
//var episodeFile = _mediaFileService.Get(id);
|
||||
//var series = _seriesService.GetSeries(episodeFile.SeriesId);
|
||||
//var fullPath = Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
//var subfolder = _diskProvider.GetParentFolder(series.Path).GetRelativePath(_diskProvider.GetParentFolder(fullPath));
|
||||
|
||||
_logger.Info("Deleting episode file: {0}", fullPath);
|
||||
_recycleBinProvider.DeleteFile(fullPath, subfolder);
|
||||
_mediaFileService.Delete(episodeFile, DeleteMediaFileReason.Manual);
|
||||
//_logger.Info("Deleting episode file: {0}", fullPath);
|
||||
//_recycleBinProvider.DeleteFile(fullPath, subfolder);
|
||||
//_mediaFileService.Delete(episodeFile, DeleteMediaFileReason.Manual);
|
||||
}
|
||||
|
||||
public void Handle(EpisodeFileAddedEvent message)
|
||||
|
|
|
@ -144,14 +144,14 @@ namespace NzbDrone.Api.Music
|
|||
|
||||
public void Handle(TrackImportedEvent message)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Updated, message.ImportedTrack.ItunesTrackId);
|
||||
BroadcastResourceChange(ModelAction.Updated, message.ImportedTrack.Id); // TODO: Ensure we can pass DB ID instead of Metadata ID (SpotifyID)
|
||||
}
|
||||
|
||||
public void Handle(TrackFileDeletedEvent message)
|
||||
{
|
||||
if (message.Reason == DeleteMediaFileReason.Upgrade) return;
|
||||
|
||||
BroadcastResourceChange(ModelAction.Updated, message.TrackFile.ItunesTrackId);
|
||||
BroadcastResourceChange(ModelAction.Updated, message.TrackFile.Id); // TODO: Ensure we can pass DB ID instead of Metadata ID (SpotifyID)
|
||||
}
|
||||
|
||||
public void Handle(ArtistUpdatedEvent message)
|
||||
|
|
|
@ -13,6 +13,7 @@ using NzbDrone.Core.MediaFiles.EpisodeImport;
|
|||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||
|
||||
namespace NzbDrone.Core.Download
|
||||
{
|
||||
|
@ -130,7 +131,7 @@ namespace NzbDrone.Core.Download
|
|||
{
|
||||
var statusMessages = importResults
|
||||
.Where(v => v.Result != ImportResultType.Imported)
|
||||
.Select(v => new TrackedDownloadStatusMessage(Path.GetFileName(v.ImportDecision.LocalEpisode.Path), v.Errors))
|
||||
.Select(v => new TrackedDownloadStatusMessage(Path.GetFileName(v.ImportDecision.LocalTrack.Path), v.Errors))
|
||||
.ToArray();
|
||||
|
||||
trackedDownload.Warn(statusMessages);
|
||||
|
|
|
@ -16,6 +16,7 @@ using NzbDrone.Core.Tv;
|
|||
|
||||
namespace NzbDrone.Core.Extras
|
||||
{
|
||||
// NOTE: Majora: ExtraService can be reserved for Music Videos, lyric files, etc for Plex. TODO: Implement Extras for Music
|
||||
public interface IExtraService
|
||||
{
|
||||
void ImportExtraFiles(LocalEpisode localEpisode, EpisodeFile episodeFile, bool isReadOnly);
|
||||
|
@ -136,16 +137,17 @@ namespace NzbDrone.Core.Extras
|
|||
|
||||
private List<EpisodeFile> GetEpisodeFiles(int seriesId)
|
||||
{
|
||||
var episodeFiles = _mediaFileService.GetFilesBySeries(seriesId);
|
||||
var episodes = _episodeService.GetEpisodeBySeries(seriesId);
|
||||
//var episodeFiles = _mediaFileService.GetFilesBySeries(seriesId);
|
||||
//var episodes = _episodeService.GetEpisodeBySeries(seriesId);
|
||||
|
||||
foreach (var episodeFile in episodeFiles)
|
||||
{
|
||||
var localEpisodeFile = episodeFile;
|
||||
episodeFile.Episodes = new LazyList<Episode>(episodes.Where(e => e.EpisodeFileId == localEpisodeFile.Id));
|
||||
}
|
||||
//foreach (var episodeFile in episodeFiles)
|
||||
//{
|
||||
// var localEpisodeFile = episodeFile;
|
||||
// episodeFile.Episodes = new LazyList<Episode>(episodes.Where(e => e.EpisodeFileId == localEpisodeFile.Id));
|
||||
//}
|
||||
|
||||
return episodeFiles;
|
||||
//return episodeFiles;
|
||||
return new List<EpisodeFile>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.Commands
|
||||
|
|
|
@ -18,12 +18,12 @@ using NzbDrone.Core.Tv;
|
|||
using NzbDrone.Core.Tv.Events;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Core.Music.Events;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
public interface IDiskScanService
|
||||
{
|
||||
void Scan(Series series);
|
||||
void Scan(Artist artist);
|
||||
string[] GetVideoFiles(string path, bool allDirectories = true);
|
||||
string[] GetNonVideoFiles(string path, bool allDirectories = true);
|
||||
|
@ -32,14 +32,12 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
public class DiskScanService :
|
||||
IDiskScanService,
|
||||
IHandle<SeriesUpdatedEvent>,
|
||||
IExecute<RescanSeriesCommand>,
|
||||
IHandle<ArtistUpdatedEvent>,
|
||||
IExecute<RescanArtistCommand>
|
||||
{
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IMakeImportDecision _importDecisionMaker;
|
||||
private readonly IImportApprovedEpisodes _importApprovedEpisodes;
|
||||
private readonly IImportApprovedTracks _importApprovedTracks;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly ISeriesService _seriesService;
|
||||
private readonly IArtistService _artistService;
|
||||
|
@ -49,7 +47,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
public DiskScanService(IDiskProvider diskProvider,
|
||||
IMakeImportDecision importDecisionMaker,
|
||||
IImportApprovedEpisodes importApprovedEpisodes,
|
||||
IImportApprovedTracks importApprovedTracks,
|
||||
IConfigService configService,
|
||||
ISeriesService seriesService,
|
||||
IArtistService artistService,
|
||||
|
@ -59,7 +57,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
{
|
||||
_diskProvider = diskProvider;
|
||||
_importDecisionMaker = importDecisionMaker;
|
||||
_importApprovedEpisodes = importApprovedEpisodes;
|
||||
_importApprovedTracks = importApprovedTracks;
|
||||
_configService = configService;
|
||||
_seriesService = seriesService;
|
||||
_artistService = artistService;
|
||||
|
@ -123,76 +121,18 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
CompletedScanning(artist);
|
||||
}
|
||||
public void Scan(Series series)
|
||||
{
|
||||
var rootFolder = _diskProvider.GetParentFolder(series.Path);
|
||||
|
||||
if (!_diskProvider.FolderExists(rootFolder))
|
||||
{
|
||||
_logger.Warn("Series' root folder ({0}) doesn't exist.", rootFolder);
|
||||
_eventAggregator.PublishEvent(new SeriesScanSkippedEvent(series, SeriesScanSkippedReason.RootFolderDoesNotExist));
|
||||
return;
|
||||
}
|
||||
|
||||
if (_diskProvider.GetDirectories(rootFolder).Empty())
|
||||
{
|
||||
_logger.Warn("Series' root folder ({0}) is empty.", rootFolder);
|
||||
_eventAggregator.PublishEvent(new SeriesScanSkippedEvent(series, SeriesScanSkippedReason.RootFolderIsEmpty));
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.ProgressInfo("Scanning disk for {0}", series.Title);
|
||||
|
||||
if (!_diskProvider.FolderExists(series.Path))
|
||||
{
|
||||
if (_configService.CreateEmptySeriesFolders)
|
||||
{
|
||||
_logger.Debug("Creating missing series folder: {0}", series.Path);
|
||||
_diskProvider.CreateFolder(series.Path);
|
||||
SetPermissions(series.Path);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("Series folder doesn't exist: {0}", series.Path);
|
||||
}
|
||||
CleanMediaFiles(series, new List<string>());
|
||||
CompletedScanning(series);
|
||||
return;
|
||||
}
|
||||
|
||||
var videoFilesStopwatch = Stopwatch.StartNew();
|
||||
var mediaFileList = FilterFiles(series, GetVideoFiles(series.Path)).ToList();
|
||||
videoFilesStopwatch.Stop();
|
||||
_logger.Trace("Finished getting episode files for: {0} [{1}]", series, videoFilesStopwatch.Elapsed);
|
||||
|
||||
CleanMediaFiles(series, mediaFileList);
|
||||
|
||||
var decisionsStopwatch = Stopwatch.StartNew();
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, series);
|
||||
decisionsStopwatch.Stop();
|
||||
_logger.Trace("Import decisions complete for: {0} [{1}]", series, decisionsStopwatch.Elapsed);
|
||||
_importApprovedEpisodes.Import(decisions, false);
|
||||
|
||||
CompletedScanning(series);
|
||||
}
|
||||
|
||||
private void CleanMediaFiles(Series series, List<string> mediaFileList)
|
||||
{
|
||||
_logger.Debug("{0} Cleaning up media files in DB", series);
|
||||
_mediaFileTableCleanupService.Clean(series, mediaFileList);
|
||||
}
|
||||
|
||||
|
||||
private void CleanMediaFiles(Artist artist, List<string> mediaFileList)
|
||||
{
|
||||
_logger.Debug("{0} Cleaning up media files in DB", artist);
|
||||
_mediaFileTableCleanupService.Clean(artist, mediaFileList);
|
||||
}
|
||||
|
||||
private void CompletedScanning(Series series)
|
||||
{
|
||||
_logger.Info("Completed scanning disk for {0}", series.Title);
|
||||
_eventAggregator.PublishEvent(new SeriesScannedEvent(series));
|
||||
}
|
||||
//private void CompletedScanning(Series series)
|
||||
//{
|
||||
// _logger.Info("Completed scanning disk for {0}", series.Title);
|
||||
// _eventAggregator.PublishEvent(new SeriesScannedEvent(series));
|
||||
//}
|
||||
|
||||
private void CompletedScanning(Artist artist)
|
||||
{
|
||||
|
@ -280,35 +220,11 @@ namespace NzbDrone.Core.MediaFiles
|
|||
}
|
||||
}
|
||||
|
||||
public void Handle(SeriesUpdatedEvent message)
|
||||
{
|
||||
Scan(message.Series);
|
||||
}
|
||||
|
||||
public void Handle(ArtistUpdatedEvent message)
|
||||
{
|
||||
Scan(message.Artist);
|
||||
}
|
||||
|
||||
public void Execute(RescanSeriesCommand message)
|
||||
{
|
||||
if (message.SeriesId.HasValue)
|
||||
{
|
||||
var series = _seriesService.GetSeries(message.SeriesId.Value);
|
||||
Scan(series);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
var allSeries = _seriesService.GetAllSeries();
|
||||
|
||||
foreach (var series in allSeries)
|
||||
{
|
||||
Scan(series);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Execute(RescanArtistCommand message)
|
||||
{
|
||||
if (message.ArtistId.IsNotNullOrWhiteSpace())
|
||||
|
|
|
@ -9,6 +9,7 @@ using NzbDrone.Core.Download.TrackedDownloads;
|
|||
using NzbDrone.Core.MediaFiles.Commands;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
|
|
|
@ -9,6 +9,7 @@ using NzbDrone.Core.Parser;
|
|||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
|
@ -59,7 +60,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
results.AddRange(folderResults);
|
||||
}
|
||||
|
||||
foreach (var videoFile in _diskScanService.GetVideoFiles(directoryInfo.FullName, false))
|
||||
foreach (var videoFile in _diskScanService.GetNonVideoFiles(directoryInfo.FullName, false))
|
||||
{
|
||||
var fileResults = ProcessFile(new FileInfo(videoFile), ImportMode.Auto, null);
|
||||
results.AddRange(fileResults);
|
||||
|
@ -100,7 +101,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
public bool ShouldDeleteFolder(DirectoryInfo directoryInfo, Series series)
|
||||
{
|
||||
var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);
|
||||
var videoFiles = _diskScanService.GetNonVideoFiles(directoryInfo.FullName);
|
||||
var rarFiles = _diskProvider.GetFiles(directoryInfo.FullName, SearchOption.AllDirectories).Where(f => Path.GetExtension(f) == ".rar");
|
||||
|
||||
foreach (var videoFile in videoFiles)
|
||||
|
@ -152,48 +153,50 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
private List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, ImportMode importMode, Series series, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
if (_seriesService.SeriesPathExists(directoryInfo.FullName))
|
||||
{
|
||||
_logger.Warn("Unable to process folder that is mapped to an existing show");
|
||||
return new List<ImportResult>();
|
||||
}
|
||||
throw new System.NotImplementedException("Will be removed");
|
||||
|
||||
var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
|
||||
var folderInfo = Parser.Parser.ParseTitle(directoryInfo.Name);
|
||||
//if (_seriesService.SeriesPathExists(directoryInfo.FullName))
|
||||
//{
|
||||
// _logger.Warn("Unable to process folder that is mapped to an existing show");
|
||||
// return new List<ImportResult>();
|
||||
//}
|
||||
|
||||
if (folderInfo != null)
|
||||
{
|
||||
_logger.Debug("{0} folder quality: {1}", cleanedUpName, folderInfo.Quality);
|
||||
}
|
||||
//var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
|
||||
//var folderInfo = Parser.Parser.ParseTitle(directoryInfo.Name);
|
||||
|
||||
var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);
|
||||
//if (folderInfo != null)
|
||||
//{
|
||||
// _logger.Debug("{0} folder quality: {1}", cleanedUpName, folderInfo.Quality);
|
||||
//}
|
||||
|
||||
if (downloadClientItem == null)
|
||||
{
|
||||
foreach (var videoFile in videoFiles)
|
||||
{
|
||||
if (_diskProvider.IsFileLocked(videoFile))
|
||||
{
|
||||
return new List<ImportResult>
|
||||
{
|
||||
FileIsLockedResult(videoFile)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
//var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);
|
||||
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, folderInfo, true);
|
||||
var importResults = _importApprovedEpisodes.Import(decisions, true, downloadClientItem, importMode);
|
||||
//if (downloadClientItem == null)
|
||||
//{
|
||||
// foreach (var videoFile in videoFiles)
|
||||
// {
|
||||
// if (_diskProvider.IsFileLocked(videoFile))
|
||||
// {
|
||||
// return new List<ImportResult>
|
||||
// {
|
||||
// FileIsLockedResult(videoFile)
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
if ((downloadClientItem == null || !downloadClientItem.IsReadOnly) &&
|
||||
importResults.Any(i => i.Result == ImportResultType.Imported) &&
|
||||
ShouldDeleteFolder(directoryInfo, series))
|
||||
{
|
||||
_logger.Debug("Deleting folder after importing valid files");
|
||||
_diskProvider.DeleteFolder(directoryInfo.FullName, true);
|
||||
}
|
||||
//var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, folderInfo, true);
|
||||
//var importResults = _importApprovedEpisodes.Import(decisions, true, downloadClientItem, importMode);
|
||||
|
||||
return importResults;
|
||||
//if ((downloadClientItem == null || !downloadClientItem.IsReadOnly) &&
|
||||
// importResults.Any(i => i.Result == ImportResultType.Imported) &&
|
||||
// ShouldDeleteFolder(directoryInfo, series))
|
||||
//{
|
||||
// _logger.Debug("Deleting folder after importing valid files");
|
||||
// _diskProvider.DeleteFolder(directoryInfo.FullName, true);
|
||||
//}
|
||||
|
||||
//return importResults;
|
||||
}
|
||||
|
||||
private List<ImportResult> ProcessFile(FileInfo fileInfo, ImportMode importMode, DownloadClientItem downloadClientItem)
|
||||
|
@ -215,30 +218,31 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
private List<ImportResult> ProcessFile(FileInfo fileInfo, ImportMode importMode, Series series, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
if (Path.GetFileNameWithoutExtension(fileInfo.Name).StartsWith("._"))
|
||||
{
|
||||
_logger.Debug("[{0}] starts with '._', skipping", fileInfo.FullName);
|
||||
throw new System.NotImplementedException("Will be removed");
|
||||
//if (Path.GetFileNameWithoutExtension(fileInfo.Name).StartsWith("._"))
|
||||
//{
|
||||
// _logger.Debug("[{0}] starts with '._', skipping", fileInfo.FullName);
|
||||
|
||||
return new List<ImportResult>
|
||||
{
|
||||
new ImportResult(new ImportDecision(new LocalEpisode { Path = fileInfo.FullName }, new Rejection("Invalid video file, filename starts with '._'")), "Invalid video file, filename starts with '._'")
|
||||
};
|
||||
}
|
||||
// return new List<ImportResult>
|
||||
// {
|
||||
// new ImportResult(new ImportDecision(new LocalTrack { Path = fileInfo.FullName }, new Rejection("Invalid music file, filename starts with '._'")), "Invalid music file, filename starts with '._'")
|
||||
// };
|
||||
//}
|
||||
|
||||
if (downloadClientItem == null)
|
||||
{
|
||||
if (_diskProvider.IsFileLocked(fileInfo.FullName))
|
||||
{
|
||||
return new List<ImportResult>
|
||||
{
|
||||
FileIsLockedResult(fileInfo.FullName)
|
||||
};
|
||||
}
|
||||
}
|
||||
//if (downloadClientItem == null)
|
||||
//{
|
||||
// if (_diskProvider.IsFileLocked(fileInfo.FullName))
|
||||
// {
|
||||
// return new List<ImportResult>
|
||||
// {
|
||||
// FileIsLockedResult(fileInfo.FullName)
|
||||
// };
|
||||
// }
|
||||
//}
|
||||
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(new List<string>() { fileInfo.FullName }, series, null, true);
|
||||
//var decisions = _importDecisionMaker.GetImportDecisions(new List<string>() { fileInfo.FullName }, series, null, true);
|
||||
|
||||
return _importApprovedEpisodes.Import(decisions, true, downloadClientItem, importMode);
|
||||
//return _importApprovedEpisodes.Import(decisions, true, downloadClientItem, importMode);
|
||||
}
|
||||
|
||||
private string GetCleanedUpFolderName(string folder)
|
||||
|
@ -251,15 +255,17 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
private ImportResult FileIsLockedResult(string videoFile)
|
||||
{
|
||||
_logger.Debug("[{0}] is currently locked by another process, skipping", videoFile);
|
||||
return new ImportResult(new ImportDecision(new LocalEpisode { Path = videoFile }, new Rejection("Locked file, try again later")), "Locked file, try again later");
|
||||
throw new System.NotImplementedException("Will be removed");
|
||||
//_logger.Debug("[{0}] is currently locked by another process, skipping", videoFile);
|
||||
//return new ImportResult(new ImportDecision(new LocalEpisode { Path = videoFile }, new Rejection("Locked file, try again later")), "Locked file, try again later");
|
||||
}
|
||||
|
||||
private ImportResult UnknownSeriesResult(string message, string videoFile = null)
|
||||
{
|
||||
var localEpisode = videoFile == null ? null : new LocalEpisode { Path = videoFile };
|
||||
throw new System.NotImplementedException("Will be removed");
|
||||
//var localEpisode = videoFile == null ? null : new LocalEpisode { Path = videoFile };
|
||||
|
||||
return new ImportResult(new ImportDecision(localEpisode, new Rejection("Unknown Series")), message);
|
||||
//return new ImportResult(new ImportDecision(localEpisode, new Rejection("Unknown Series")), message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,5 +6,6 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
public interface IImportDecisionEngineSpecification
|
||||
{
|
||||
Decision IsSatisfiedBy(LocalEpisode localEpisode);
|
||||
Decision IsSatisfiedBy(LocalTrack localTrack);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ using NzbDrone.Core.Parser.Model;
|
|||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Extras;
|
||||
|
||||
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
{
|
||||
|
@ -47,105 +47,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
|
||||
public List<ImportResult> Import(List<ImportDecision> decisions, bool newDownload, DownloadClientItem downloadClientItem = null, ImportMode importMode = ImportMode.Auto)
|
||||
{
|
||||
var qualifiedImports = decisions.Where(c => c.Approved)
|
||||
.GroupBy(c => c.LocalEpisode.Series.Id, (i, s) => s
|
||||
.OrderByDescending(c => c.LocalEpisode.Quality, new QualityModelComparer(s.First().LocalEpisode.Series.Profile))
|
||||
.ThenByDescending(c => c.LocalEpisode.Size))
|
||||
.SelectMany(c => c)
|
||||
.ToList();
|
||||
|
||||
var importResults = new List<ImportResult>();
|
||||
|
||||
foreach (var importDecision in qualifiedImports.OrderBy(e => e.LocalEpisode.Episodes.Select(episode => episode.EpisodeNumber).MinOrDefault())
|
||||
.ThenByDescending(e => e.LocalEpisode.Size))
|
||||
{
|
||||
var localEpisode = importDecision.LocalEpisode;
|
||||
var oldFiles = new List<EpisodeFile>();
|
||||
|
||||
try
|
||||
{
|
||||
//check if already imported
|
||||
if (importResults.SelectMany(r => r.ImportDecision.LocalEpisode.Episodes)
|
||||
.Select(e => e.Id)
|
||||
.Intersect(localEpisode.Episodes.Select(e => e.Id))
|
||||
.Any())
|
||||
{
|
||||
importResults.Add(new ImportResult(importDecision, "Episode has already been imported"));
|
||||
continue;
|
||||
}
|
||||
|
||||
var episodeFile = new EpisodeFile();
|
||||
episodeFile.DateAdded = DateTime.UtcNow;
|
||||
episodeFile.SeriesId = localEpisode.Series.Id;
|
||||
episodeFile.Path = localEpisode.Path.CleanFilePath();
|
||||
episodeFile.Size = _diskProvider.GetFileSize(localEpisode.Path);
|
||||
episodeFile.Quality = localEpisode.Quality;
|
||||
episodeFile.MediaInfo = localEpisode.MediaInfo;
|
||||
episodeFile.SeasonNumber = localEpisode.SeasonNumber;
|
||||
episodeFile.Episodes = localEpisode.Episodes;
|
||||
episodeFile.ReleaseGroup = localEpisode.ParsedEpisodeInfo.ReleaseGroup;
|
||||
|
||||
bool copyOnly;
|
||||
switch (importMode)
|
||||
{
|
||||
default:
|
||||
case ImportMode.Auto:
|
||||
copyOnly = downloadClientItem != null && downloadClientItem.IsReadOnly;
|
||||
break;
|
||||
case ImportMode.Move:
|
||||
copyOnly = false;
|
||||
break;
|
||||
case ImportMode.Copy:
|
||||
copyOnly = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (newDownload)
|
||||
{
|
||||
episodeFile.SceneName = GetSceneName(downloadClientItem, localEpisode);
|
||||
|
||||
var moveResult = _episodeFileUpgrader.UpgradeEpisodeFile(episodeFile, localEpisode, copyOnly);
|
||||
oldFiles = moveResult.OldFiles;
|
||||
}
|
||||
else
|
||||
{
|
||||
episodeFile.RelativePath = localEpisode.Series.Path.GetRelativePath(episodeFile.Path);
|
||||
}
|
||||
|
||||
_mediaFileService.Add(episodeFile);
|
||||
importResults.Add(new ImportResult(importDecision));
|
||||
|
||||
if (newDownload)
|
||||
{
|
||||
_extraService.ImportExtraFiles(localEpisode, episodeFile, copyOnly);
|
||||
}
|
||||
|
||||
if (downloadClientItem != null)
|
||||
{
|
||||
_eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile, newDownload, downloadClientItem.DownloadClient, downloadClientItem.DownloadId, downloadClientItem.IsReadOnly));
|
||||
}
|
||||
else
|
||||
{
|
||||
_eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile, newDownload));
|
||||
}
|
||||
|
||||
if (newDownload)
|
||||
{
|
||||
_eventAggregator.PublishEvent(new EpisodeDownloadedEvent(localEpisode, episodeFile, oldFiles));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Warn(e, "Couldn't import episode " + localEpisode);
|
||||
importResults.Add(new ImportResult(importDecision, "Failed to import episode"));
|
||||
}
|
||||
}
|
||||
|
||||
//Adding all the rejected decisions
|
||||
importResults.AddRange(decisions.Where(c => !c.Approved)
|
||||
.Select(d => new ImportResult(d, d.Rejections.Select(r => r.Reason).ToArray())));
|
||||
|
||||
return importResults;
|
||||
throw new NotImplementedException("This will be removed");
|
||||
}
|
||||
|
||||
private string GetSceneName(DownloadClientItem downloadClientItem, LocalEpisode localEpisode)
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
{
|
||||
public class ImportDecision
|
||||
{
|
||||
public LocalEpisode LocalEpisode { get; private set; }
|
||||
public IEnumerable<Rejection> Rejections { get; private set; }
|
||||
|
||||
public bool Approved => Rejections.Empty();
|
||||
|
||||
public ImportDecision(LocalEpisode localEpisode, params Rejection[] rejections)
|
||||
{
|
||||
LocalEpisode = localEpisode;
|
||||
Rejections = rejections.ToList();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ using NzbDrone.Core.Qualities;
|
|||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
{
|
||||
|
@ -94,7 +95,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
return decisions;
|
||||
}
|
||||
|
||||
private ImportDecision GetDecision(string file, Artist artist, ParsedTrackInfo folderInfo, bool sceneSource, bool shouldUseFolderName)
|
||||
private ImportDecision GetDecision(string file, Artist artist, ParsedTrackInfo folderInfo, bool shouldUseFolderName)
|
||||
{
|
||||
ImportDecision decision = null;
|
||||
|
||||
|
@ -109,11 +110,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
|
||||
_logger.Debug("Size: {0}", localTrack.Size);
|
||||
|
||||
//TODO: make it so media info doesn't ruin the import process of a new series
|
||||
if (sceneSource)
|
||||
{
|
||||
localTrack.MediaInfo = _videoFileInfoReader.GetMediaInfo(file);
|
||||
}
|
||||
//TODO: make it so media info doesn't ruin the import process of a new artist
|
||||
|
||||
if (localTrack.Tracks.Empty())
|
||||
{
|
||||
|
@ -137,19 +134,41 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
{
|
||||
_logger.Error(e, "Couldn't import file. {0}", file);
|
||||
|
||||
var localEpisode = new LocalEpisode { Path = file };
|
||||
decision = new ImportDecision(localEpisode, new Rejection("Unexpected error processing file"));
|
||||
var localTrack = new LocalTrack { Path = file };
|
||||
decision = new ImportDecision(localTrack, new Rejection("Unexpected error processing file"));
|
||||
}
|
||||
|
||||
return decision;
|
||||
}
|
||||
|
||||
private ImportDecision GetDecision(LocalEpisode localEpisode)
|
||||
private ImportDecision GetDecision(LocalTrack localTrack)
|
||||
{
|
||||
var reasons = _specifications.Select(c => EvaluateSpec(c, localEpisode))
|
||||
var reasons = _specifications.Select(c => EvaluateSpec(c, localTrack))
|
||||
.Where(c => c != null);
|
||||
|
||||
return new ImportDecision(localEpisode, reasons.ToArray());
|
||||
return new ImportDecision(localTrack, reasons.ToArray());
|
||||
}
|
||||
|
||||
private Rejection EvaluateSpec(IImportDecisionEngineSpecification spec, LocalTrack localTrack)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = spec.IsSatisfiedBy(localTrack);
|
||||
|
||||
if (!result.Accepted)
|
||||
{
|
||||
return new Rejection(result.Reason);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
//e.Data.Add("report", remoteEpisode.Report.ToJson());
|
||||
//e.Data.Add("parsed", remoteEpisode.ParsedEpisodeInfo.ToJson());
|
||||
_logger.Error(e, "Couldn't evaluate decision on {0}", localTrack.Path);
|
||||
return new Rejection($"{spec.GetType().Name}: {e.Message}");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Rejection EvaluateSpec(IImportDecisionEngineSpecification spec, LocalEpisode localEpisode)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
||||
{
|
||||
|
|
|
@ -15,6 +15,7 @@ using NzbDrone.Core.Messaging.Events;
|
|||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
||||
{
|
||||
|
@ -94,65 +95,67 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
|||
|
||||
private List<ManualImportItem> ProcessFolder(string folder, string downloadId)
|
||||
{
|
||||
var directoryInfo = new DirectoryInfo(folder);
|
||||
var series = _parsingService.GetSeries(directoryInfo.Name);
|
||||
throw new System.NotImplementedException("TODO: This will be rewritten for Music");
|
||||
//var directoryInfo = new DirectoryInfo(folder);
|
||||
//var series = _parsingService.GetSeries(directoryInfo.Name);
|
||||
|
||||
if (series == null && downloadId.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var trackedDownload = _trackedDownloadService.Find(downloadId);
|
||||
series = trackedDownload.RemoteEpisode.Series;
|
||||
}
|
||||
//if (series == null && downloadId.IsNotNullOrWhiteSpace())
|
||||
//{
|
||||
// var trackedDownload = _trackedDownloadService.Find(downloadId);
|
||||
// series = trackedDownload.RemoteEpisode.Series;
|
||||
//}
|
||||
|
||||
if (series == null)
|
||||
{
|
||||
var files = _diskScanService.GetVideoFiles(folder);
|
||||
//if (series == null)
|
||||
//{
|
||||
// var files = _diskScanService.GetVideoFiles(folder);
|
||||
|
||||
return files.Select(file => ProcessFile(file, downloadId, folder)).Where(i => i != null).ToList();
|
||||
}
|
||||
// return files.Select(file => ProcessFile(file, downloadId, folder)).Where(i => i != null).ToList();
|
||||
//}
|
||||
|
||||
var folderInfo = Parser.Parser.ParseTitle(directoryInfo.Name);
|
||||
var seriesFiles = _diskScanService.GetVideoFiles(folder).ToList();
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(seriesFiles, series, folderInfo, SceneSource(series, folder));
|
||||
//var folderInfo = Parser.Parser.ParseTitle(directoryInfo.Name);
|
||||
//var seriesFiles = _diskScanService.GetVideoFiles(folder).ToList();
|
||||
//var decisions = _importDecisionMaker.GetImportDecisions(seriesFiles, series, folderInfo, SceneSource(series, folder));
|
||||
|
||||
return decisions.Select(decision => MapItem(decision, folder, downloadId)).ToList();
|
||||
//return decisions.Select(decision => MapItem(decision, folder, downloadId)).ToList();
|
||||
}
|
||||
|
||||
private ManualImportItem ProcessFile(string file, string downloadId, string folder = null)
|
||||
{
|
||||
if (folder.IsNullOrWhiteSpace())
|
||||
{
|
||||
folder = new FileInfo(file).Directory.FullName;
|
||||
}
|
||||
throw new System.NotImplementedException("TODO: This will be rewritten for Music");
|
||||
//if (folder.IsNullOrWhiteSpace())
|
||||
//{
|
||||
// folder = new FileInfo(file).Directory.FullName;
|
||||
//}
|
||||
|
||||
var relativeFile = folder.GetRelativePath(file);
|
||||
//var relativeFile = folder.GetRelativePath(file);
|
||||
|
||||
var series = _parsingService.GetSeries(relativeFile.Split('\\', '/')[0]);
|
||||
//var series = _parsingService.GetSeries(relativeFile.Split('\\', '/')[0]);
|
||||
|
||||
if (series == null)
|
||||
{
|
||||
series = _parsingService.GetSeries(relativeFile);
|
||||
}
|
||||
//if (series == null)
|
||||
//{
|
||||
// series = _parsingService.GetSeries(relativeFile);
|
||||
//}
|
||||
|
||||
if (series == null && downloadId.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var trackedDownload = _trackedDownloadService.Find(downloadId);
|
||||
series = trackedDownload.RemoteEpisode.Series;
|
||||
}
|
||||
//if (series == null && downloadId.IsNotNullOrWhiteSpace())
|
||||
//{
|
||||
// var trackedDownload = _trackedDownloadService.Find(downloadId);
|
||||
// series = trackedDownload.RemoteEpisode.Series;
|
||||
//}
|
||||
|
||||
if (series == null)
|
||||
{
|
||||
var localEpisode = new LocalEpisode();
|
||||
localEpisode.Path = file;
|
||||
localEpisode.Quality = QualityParser.ParseQuality(file);
|
||||
localEpisode.Size = _diskProvider.GetFileSize(file);
|
||||
//if (series == null)
|
||||
//{
|
||||
// var localEpisode = new LocalEpisode();
|
||||
// localEpisode.Path = file;
|
||||
// localEpisode.Quality = QualityParser.ParseQuality(file);
|
||||
// localEpisode.Size = _diskProvider.GetFileSize(file);
|
||||
|
||||
return MapItem(new ImportDecision(localEpisode, new Rejection("Unknown Series")), folder, downloadId);
|
||||
}
|
||||
// return MapItem(new ImportDecision(localEpisode, new Rejection("Unknown Series")), folder, downloadId);
|
||||
//}
|
||||
|
||||
var importDecisions = _importDecisionMaker.GetImportDecisions(new List<string> {file},
|
||||
series, null, SceneSource(series, folder));
|
||||
//var importDecisions = _importDecisionMaker.GetImportDecisions(new List<string> {file},
|
||||
// series, null, SceneSource(series, folder));
|
||||
|
||||
return importDecisions.Any() ? MapItem(importDecisions.First(), folder, downloadId) : null;
|
||||
//return importDecisions.Any() ? MapItem(importDecisions.First(), folder, downloadId) : null;
|
||||
}
|
||||
|
||||
private bool SceneSource(Series series, string folder)
|
||||
|
@ -162,107 +165,109 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
|||
|
||||
private ManualImportItem MapItem(ImportDecision decision, string folder, string downloadId)
|
||||
{
|
||||
var item = new ManualImportItem();
|
||||
throw new System.NotImplementedException("TODO: This will be rewritten for Music");
|
||||
//var item = new ManualImportItem();
|
||||
|
||||
item.Path = decision.LocalEpisode.Path;
|
||||
item.RelativePath = folder.GetRelativePath(decision.LocalEpisode.Path);
|
||||
item.Name = Path.GetFileNameWithoutExtension(decision.LocalEpisode.Path);
|
||||
item.DownloadId = downloadId;
|
||||
//item.Path = decision.LocalEpisode.Path;
|
||||
//item.RelativePath = folder.GetRelativePath(decision.LocalEpisode.Path);
|
||||
//item.Name = Path.GetFileNameWithoutExtension(decision.LocalEpisode.Path);
|
||||
//item.DownloadId = downloadId;
|
||||
|
||||
if (decision.LocalEpisode.Series != null)
|
||||
{
|
||||
item.Series = decision.LocalEpisode.Series;
|
||||
}
|
||||
//if (decision.LocalEpisode.Series != null)
|
||||
//{
|
||||
// item.Series = decision.LocalEpisode.Series;
|
||||
//}
|
||||
|
||||
if (decision.LocalEpisode.Episodes.Any())
|
||||
{
|
||||
item.SeasonNumber = decision.LocalEpisode.SeasonNumber;
|
||||
item.Episodes = decision.LocalEpisode.Episodes;
|
||||
}
|
||||
//if (decision.LocalEpisode.Episodes.Any())
|
||||
//{
|
||||
// item.SeasonNumber = decision.LocalEpisode.SeasonNumber;
|
||||
// item.Episodes = decision.LocalEpisode.Episodes;
|
||||
//}
|
||||
|
||||
item.Quality = decision.LocalEpisode.Quality;
|
||||
item.Size = _diskProvider.GetFileSize(decision.LocalEpisode.Path);
|
||||
item.Rejections = decision.Rejections;
|
||||
//item.Quality = decision.LocalEpisode.Quality;
|
||||
//item.Size = _diskProvider.GetFileSize(decision.LocalEpisode.Path);
|
||||
//item.Rejections = decision.Rejections;
|
||||
|
||||
return item;
|
||||
//return item;
|
||||
}
|
||||
|
||||
public void Execute(ManualImportCommand message)
|
||||
{
|
||||
_logger.ProgressTrace("Manually importing {0} files using mode {1}", message.Files.Count, message.ImportMode);
|
||||
throw new System.NotImplementedException("TODO: This will be rewritten for Music");
|
||||
|
||||
var imported = new List<ImportResult>();
|
||||
var importedTrackedDownload = new List<ManuallyImportedFile>();
|
||||
//var imported = new List<ImportResult>();
|
||||
//var importedTrackedDownload = new List<ManuallyImportedFile>();
|
||||
|
||||
for (int i = 0; i < message.Files.Count; i++)
|
||||
{
|
||||
_logger.ProgressTrace("Processing file {0} of {1}", i + 1, message.Files.Count);
|
||||
//for (int i = 0; i < message.Files.Count; i++)
|
||||
//{
|
||||
// _logger.ProgressTrace("Processing file {0} of {1}", i + 1, message.Files.Count);
|
||||
|
||||
var file = message.Files[i];
|
||||
var series = _seriesService.GetSeries(file.SeriesId);
|
||||
var episodes = _episodeService.GetEpisodes(file.EpisodeIds);
|
||||
var parsedEpisodeInfo = Parser.Parser.ParsePath(file.Path) ?? new ParsedEpisodeInfo();
|
||||
var mediaInfo = _videoFileInfoReader.GetMediaInfo(file.Path);
|
||||
var existingFile = series.Path.IsParentPath(file.Path);
|
||||
// var file = message.Files[i];
|
||||
// var series = _seriesService.GetSeries(file.SeriesId);
|
||||
// var episodes = _episodeService.GetEpisodes(file.EpisodeIds);
|
||||
// var parsedEpisodeInfo = Parser.Parser.ParsePath(file.Path) ?? new ParsedEpisodeInfo();
|
||||
// var mediaInfo = _videoFileInfoReader.GetMediaInfo(file.Path);
|
||||
// var existingFile = series.Path.IsParentPath(file.Path);
|
||||
|
||||
var localEpisode = new LocalEpisode
|
||||
{
|
||||
ExistingFile = false,
|
||||
Episodes = episodes,
|
||||
MediaInfo = mediaInfo,
|
||||
ParsedEpisodeInfo = parsedEpisodeInfo,
|
||||
Path = file.Path,
|
||||
Quality = file.Quality,
|
||||
Series = series,
|
||||
Size = 0
|
||||
};
|
||||
// var localEpisode = new LocalEpisode
|
||||
// {
|
||||
// ExistingFile = false,
|
||||
// Episodes = episodes,
|
||||
// MediaInfo = mediaInfo,
|
||||
// ParsedEpisodeInfo = parsedEpisodeInfo,
|
||||
// Path = file.Path,
|
||||
// Quality = file.Quality,
|
||||
// Series = series,
|
||||
// Size = 0
|
||||
// };
|
||||
|
||||
//TODO: Cleanup non-tracked downloads
|
||||
// //TODO: Cleanup non-tracked downloads
|
||||
|
||||
var importDecision = new ImportDecision(localEpisode);
|
||||
// var importDecision = new ImportDecision(localEpisode);
|
||||
|
||||
if (file.DownloadId.IsNullOrWhiteSpace())
|
||||
{
|
||||
imported.AddRange(_importApprovedEpisodes.Import(new List<ImportDecision> { importDecision }, !existingFile, null, message.ImportMode));
|
||||
}
|
||||
// if (file.DownloadId.IsNullOrWhiteSpace())
|
||||
// {
|
||||
// imported.AddRange(_importApprovedEpisodes.Import(new List<ImportDecision> { importDecision }, !existingFile, null, message.ImportMode));
|
||||
// }
|
||||
|
||||
else
|
||||
{
|
||||
var trackedDownload = _trackedDownloadService.Find(file.DownloadId);
|
||||
var importResult = _importApprovedEpisodes.Import(new List<ImportDecision> { importDecision }, true, trackedDownload.DownloadItem, message.ImportMode).First();
|
||||
// else
|
||||
// {
|
||||
// var trackedDownload = _trackedDownloadService.Find(file.DownloadId);
|
||||
// var importResult = _importApprovedEpisodes.Import(new List<ImportDecision> { importDecision }, true, trackedDownload.DownloadItem, message.ImportMode).First();
|
||||
|
||||
imported.Add(importResult);
|
||||
// imported.Add(importResult);
|
||||
|
||||
importedTrackedDownload.Add(new ManuallyImportedFile
|
||||
{
|
||||
TrackedDownload = trackedDownload,
|
||||
ImportResult = importResult
|
||||
});
|
||||
}
|
||||
}
|
||||
// importedTrackedDownload.Add(new ManuallyImportedFile
|
||||
// {
|
||||
// TrackedDownload = trackedDownload,
|
||||
// ImportResult = importResult
|
||||
// });
|
||||
// }
|
||||
//}
|
||||
|
||||
_logger.ProgressTrace("Manually imported {0} files", imported.Count);
|
||||
//_logger.ProgressTrace("Manually imported {0} files", imported.Count);
|
||||
|
||||
foreach (var groupedTrackedDownload in importedTrackedDownload.GroupBy(i => i.TrackedDownload.DownloadItem.DownloadId).ToList())
|
||||
{
|
||||
var trackedDownload = groupedTrackedDownload.First().TrackedDownload;
|
||||
//foreach (var groupedTrackedDownload in importedTrackedDownload.GroupBy(i => i.TrackedDownload.DownloadItem.DownloadId).ToList())
|
||||
//{
|
||||
// var trackedDownload = groupedTrackedDownload.First().TrackedDownload;
|
||||
|
||||
if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath.FullPath))
|
||||
{
|
||||
if (_downloadedEpisodesImportService.ShouldDeleteFolder(
|
||||
new DirectoryInfo(trackedDownload.DownloadItem.OutputPath.FullPath),
|
||||
trackedDownload.RemoteEpisode.Series) && !trackedDownload.DownloadItem.IsReadOnly)
|
||||
{
|
||||
_diskProvider.DeleteFolder(trackedDownload.DownloadItem.OutputPath.FullPath, true);
|
||||
}
|
||||
}
|
||||
// if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath.FullPath))
|
||||
// {
|
||||
// if (_downloadedEpisodesImportService.ShouldDeleteFolder(
|
||||
// new DirectoryInfo(trackedDownload.DownloadItem.OutputPath.FullPath),
|
||||
// trackedDownload.RemoteEpisode.Series) && !trackedDownload.DownloadItem.IsReadOnly)
|
||||
// {
|
||||
// _diskProvider.DeleteFolder(trackedDownload.DownloadItem.OutputPath.FullPath, true);
|
||||
// }
|
||||
// }
|
||||
|
||||
if (groupedTrackedDownload.Select(c => c.ImportResult).Count(c => c.Result == ImportResultType.Imported) >= Math.Max(1, trackedDownload.RemoteEpisode.Episodes.Count))
|
||||
{
|
||||
trackedDownload.State = TrackedDownloadStage.Imported;
|
||||
_eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload));
|
||||
}
|
||||
}
|
||||
// if (groupedTrackedDownload.Select(c => c.ImportResult).Count(c => c.Result == ImportResultType.Imported) >= Math.Max(1, trackedDownload.RemoteEpisode.Episodes.Count))
|
||||
// {
|
||||
// trackedDownload.State = TrackedDownloadStage.Imported;
|
||||
// _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload));
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using NzbDrone.Core.Download.TrackedDownloads;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
|
||||
{
|
||||
|
|
|
@ -63,5 +63,48 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
|||
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalTrack localTrack)
|
||||
{
|
||||
if (_configService.SkipFreeSpaceCheckWhenImporting)
|
||||
{
|
||||
_logger.Debug("Skipping free space check when importing");
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (localTrack.ExistingFile)
|
||||
{
|
||||
_logger.Debug("Skipping free space check for existing episode");
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var path = Directory.GetParent(localTrack.Artist.Path);
|
||||
var freeSpace = _diskProvider.GetAvailableSpace(path.FullName);
|
||||
|
||||
if (!freeSpace.HasValue)
|
||||
{
|
||||
_logger.Debug("Free space check returned an invalid result for: {0}", path);
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
if (freeSpace < localTrack.Size + 100.Megabytes())
|
||||
{
|
||||
_logger.Warn("Not enough free space ({0}) to import: {1} ({2})", freeSpace, localTrack, localTrack.Size);
|
||||
return Decision.Reject("Not enough free space");
|
||||
}
|
||||
}
|
||||
catch (DirectoryNotFoundException ex)
|
||||
{
|
||||
_logger.Error(ex, "Unable to check free disk space while importing.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, "Unable to check free disk space while importing. {0}", localTrack.Path);
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using NLog;
|
||||
using System;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
|
@ -13,6 +14,11 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalTrack localTrack)
|
||||
{
|
||||
throw new NotImplementedException("Interface will be removed");
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalEpisode localEpisode)
|
||||
{
|
||||
if (localEpisode.ParsedEpisodeInfo.FullSeason)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.IO;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
|
@ -14,6 +15,53 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
|||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalTrack localTrack)
|
||||
{
|
||||
if (localTrack.ExistingFile)
|
||||
{
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var dirInfo = new FileInfo(localTrack.Path).Directory;
|
||||
|
||||
if (dirInfo == null)
|
||||
{
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
throw new System.NotImplementedException("Needs to be implemented");
|
||||
|
||||
//var folderInfo = Parser.Parser.ParseTitle(dirInfo.Name);
|
||||
|
||||
//if (folderInfo == null)
|
||||
//{
|
||||
// return Decision.Accept();
|
||||
//}
|
||||
|
||||
//if (!folderInfo.TrackNumbers.Any())
|
||||
//{
|
||||
// return Decision.Accept();
|
||||
//}
|
||||
|
||||
|
||||
//var unexpected = localTrack.ParsedTrackInfo.TrackNumbers.Where(f => !folderInfo.TrackNumbers.Contains(f)).ToList();
|
||||
//// TODO: Implement MatchesFolderSpecification
|
||||
//if (unexpected.Any())
|
||||
//{
|
||||
// _logger.Debug("Unexpected track number(s) in file: {0}", string.Join(", ", unexpected));
|
||||
|
||||
// if (unexpected.Count == 1)
|
||||
// {
|
||||
// return Decision.Reject("Track Number {0} was unexpected considering the {1} folder name", unexpected.First(), dirInfo.Name);
|
||||
// }
|
||||
|
||||
// return Decision.Reject("Episode Numbers {0} were unexpected considering the {1} folder name", string.Join(", ", unexpected), dirInfo.Name);
|
||||
//}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalEpisode localEpisode)
|
||||
{
|
||||
if (localEpisode.ExistingFile)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using NLog;
|
||||
using System;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
|
@ -16,6 +17,11 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalTrack localTrack)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalEpisode localEpisode)
|
||||
{
|
||||
if (localEpisode.ExistingFile)
|
||||
|
|
|
@ -56,5 +56,10 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
|||
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalTrack localTrack)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
@ -27,5 +28,10 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
|||
_logger.Debug("Episode file on disk contains more episodes than this file contains");
|
||||
return Decision.Reject("Episode file on disk contains more episodes than this file contains");
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalTrack localTrack)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
@ -13,6 +14,11 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalTrack localTrack)
|
||||
{
|
||||
throw new NotImplementedException("This is not needed, Interface will be removed");
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalEpisode localEpisode)
|
||||
{
|
||||
if (localEpisode.ExistingFile)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Linq;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
@ -15,6 +16,18 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalTrack localTrack)
|
||||
{
|
||||
var qualityComparer = new QualityModelComparer(localTrack.Artist.Profile);
|
||||
if (localTrack.Tracks.Any(e => e.TrackFileId != 0 && qualityComparer.Compare(e.TrackFile.Value.Quality, localTrack.Quality) > 0))
|
||||
{
|
||||
_logger.Debug("This file isn't an upgrade for all tracks. Skipping {0}", localTrack.Path);
|
||||
return Decision.Reject("Not an upgrade for existing track file(s)");
|
||||
}
|
||||
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
public Decision IsSatisfiedBy(LocalEpisode localEpisode)
|
||||
{
|
||||
var qualityComparer = new QualityModelComparer(localEpisode.Series.Profile);
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
using NzbDrone.Common.Messaging;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.Events
|
||||
{
|
||||
public class TrackDownloadedEvent : IEvent
|
||||
{
|
||||
public LocalTrack Track { get; private set; }
|
||||
public TrackFile TrackFile { get; private set; }
|
||||
public List<TrackFile> OldFiles { get; private set; }
|
||||
|
||||
public TrackDownloadedEvent(LocalTrack track, TrackFile trackFile, List<TrackFile> oldFiles)
|
||||
{
|
||||
Track = track;
|
||||
TrackFile = trackFile;
|
||||
OldFiles = oldFiles;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,81 +5,73 @@ using NLog;
|
|||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
public interface IMediaFileTableCleanupService
|
||||
{
|
||||
void Clean(Series series, List<string> filesOnDisk);
|
||||
void Clean(Artist artist, List<string> filesOnDisk);
|
||||
}
|
||||
|
||||
public class MediaFileTableCleanupService : IMediaFileTableCleanupService
|
||||
{
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly IEpisodeService _episodeService;
|
||||
private readonly ITrackService _trackService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public MediaFileTableCleanupService(IMediaFileService mediaFileService,
|
||||
IEpisodeService episodeService,
|
||||
ITrackService trackService,
|
||||
Logger logger)
|
||||
{
|
||||
_mediaFileService = mediaFileService;
|
||||
_episodeService = episodeService;
|
||||
_trackService = trackService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Clean(Series series, List<string> filesOnDisk)
|
||||
public void Clean(Artist artist, List<string> filesOnDisk)
|
||||
{
|
||||
var seriesFiles = _mediaFileService.GetFilesBySeries(series.Id);
|
||||
var episodes = _episodeService.GetEpisodeBySeries(series.Id);
|
||||
var artistFiles = _mediaFileService.GetFilesByArtist(artist.SpotifyId);
|
||||
var tracks = _trackService.GetTracksByArtist(artist.SpotifyId);
|
||||
|
||||
var filesOnDiskKeys = new HashSet<string>(filesOnDisk, PathEqualityComparer.Instance);
|
||||
|
||||
foreach (var seriesFile in seriesFiles)
|
||||
foreach (var artistFile in artistFiles)
|
||||
{
|
||||
var episodeFile = seriesFile;
|
||||
var episodeFilePath = Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
var trackFile = artistFile;
|
||||
var trackFilePath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
|
||||
try
|
||||
{
|
||||
if (!filesOnDiskKeys.Contains(episodeFilePath))
|
||||
if (!filesOnDiskKeys.Contains(trackFilePath))
|
||||
{
|
||||
_logger.Debug("File [{0}] no longer exists on disk, removing from db", episodeFilePath);
|
||||
_mediaFileService.Delete(seriesFile, DeleteMediaFileReason.MissingFromDisk);
|
||||
_logger.Debug("File [{0}] no longer exists on disk, removing from db", trackFilePath);
|
||||
_mediaFileService.Delete(artistFile, DeleteMediaFileReason.MissingFromDisk);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (episodes.None(e => e.EpisodeFileId == episodeFile.Id))
|
||||
if (tracks.None(e => e.TrackFileId == trackFile.Id))
|
||||
{
|
||||
_logger.Debug("File [{0}] is not assigned to any episodes, removing from db", episodeFilePath);
|
||||
_mediaFileService.Delete(episodeFile, DeleteMediaFileReason.NoLinkedEpisodes);
|
||||
_logger.Debug("File [{0}] is not assigned to any artist, removing from db", trackFilePath);
|
||||
_mediaFileService.Delete(trackFile, DeleteMediaFileReason.NoLinkedEpisodes);
|
||||
continue;
|
||||
}
|
||||
|
||||
// var localEpsiode = _parsingService.GetLocalEpisode(episodeFile.Path, series);
|
||||
//
|
||||
// if (localEpsiode == null || episodes.Count != localEpsiode.Episodes.Count)
|
||||
// {
|
||||
// _logger.Debug("File [{0}] parsed episodes has changed, removing from db", episodeFile.Path);
|
||||
// _mediaFileService.Delete(episodeFile);
|
||||
// continue;
|
||||
// }
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, "Unable to cleanup EpisodeFile in DB: {0}", episodeFile.Id);
|
||||
_logger.Error(ex, "Unable to cleanup EpisodeFile in DB: {0}", trackFile.Id);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var e in episodes)
|
||||
foreach (var t in tracks)
|
||||
{
|
||||
var episode = e;
|
||||
var track = t;
|
||||
|
||||
if (episode.EpisodeFileId > 0 && seriesFiles.None(f => f.Id == episode.EpisodeFileId))
|
||||
if (track.TrackFileId > 0 && artistFiles.None(f => f.Id == track.TrackFileId))
|
||||
{
|
||||
episode.EpisodeFileId = 0;
|
||||
_episodeService.UpdateEpisode(episode);
|
||||
track.TrackFileId = 0;
|
||||
_trackService.UpdateTrack(track);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,11 @@ using NzbDrone.Core.Tv;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.MediaInfo
|
||||
{
|
||||
public class UpdateMediaInfoService : IHandle<SeriesScannedEvent>
|
||||
public class UpdateMediaInfoService : IHandle<ArtistScannedEvent>
|
||||
{
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
|
@ -33,11 +34,11 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
private void UpdateMediaInfo(Series series, List<EpisodeFile> mediaFiles)
|
||||
private void UpdateMediaInfo(Artist artist, List<TrackFile> mediaFiles)
|
||||
{
|
||||
foreach (var mediaFile in mediaFiles)
|
||||
{
|
||||
var path = Path.Combine(series.Path, mediaFile.RelativePath);
|
||||
var path = Path.Combine(artist.Path, mediaFile.RelativePath);
|
||||
|
||||
if (!_diskProvider.FileExists(path))
|
||||
{
|
||||
|
@ -56,7 +57,7 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
|||
}
|
||||
}
|
||||
|
||||
public void Handle(SeriesScannedEvent message)
|
||||
public void Handle(ArtistScannedEvent message)
|
||||
{
|
||||
if (!_configService.EnableMediaInfo)
|
||||
{
|
||||
|
@ -64,10 +65,10 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
|||
return;
|
||||
}
|
||||
|
||||
var allMediaFiles = _mediaFileService.GetFilesBySeries(message.Series.Id);
|
||||
var allMediaFiles = _mediaFileService.GetFilesByArtist(message.Artist.SpotifyId);
|
||||
var filteredMediaFiles = allMediaFiles.Where(c => c.MediaInfo == null || c.MediaInfo.SchemaRevision < CURRENT_MEDIA_INFO_SCHEMA_REVISION).ToList();
|
||||
|
||||
UpdateMediaInfo(message.Series, filteredMediaFiles);
|
||||
UpdateMediaInfo(message.Artist, filteredMediaFiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,24 +55,28 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
public List<RenameEpisodeFilePreview> GetRenamePreviews(int seriesId)
|
||||
{
|
||||
var series = _seriesService.GetSeries(seriesId);
|
||||
var episodes = _episodeService.GetEpisodeBySeries(seriesId);
|
||||
var files = _mediaFileService.GetFilesBySeries(seriesId);
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
//var series = _seriesService.GetSeries(seriesId);
|
||||
//var episodes = _episodeService.GetEpisodeBySeries(seriesId);
|
||||
//var files = _mediaFileService.GetFilesBySeries(seriesId);
|
||||
|
||||
return GetPreviews(series, episodes, files)
|
||||
.OrderByDescending(e => e.SeasonNumber)
|
||||
.ThenByDescending(e => e.EpisodeNumbers.First())
|
||||
.ToList();
|
||||
//return GetPreviews(series, episodes, files)
|
||||
// .OrderByDescending(e => e.SeasonNumber)
|
||||
// .ThenByDescending(e => e.EpisodeNumbers.First())
|
||||
// .ToList();
|
||||
}
|
||||
|
||||
public List<RenameEpisodeFilePreview> GetRenamePreviews(int seriesId, int seasonNumber)
|
||||
{
|
||||
var series = _seriesService.GetSeries(seriesId);
|
||||
var episodes = _episodeService.GetEpisodesBySeason(seriesId, seasonNumber);
|
||||
var files = _mediaFileService.GetFilesBySeason(seriesId, seasonNumber);
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
//var series = _seriesService.GetSeries(seriesId);
|
||||
//var episodes = _episodeService.GetEpisodesBySeason(seriesId, seasonNumber);
|
||||
//var files = _mediaFileService.GetFilesBySeason(seriesId, seasonNumber);
|
||||
|
||||
return GetPreviews(series, episodes, files)
|
||||
.OrderByDescending(e => e.EpisodeNumbers.First()).ToList();
|
||||
//return GetPreviews(series, episodes, files)
|
||||
// .OrderByDescending(e => e.EpisodeNumbers.First()).ToList();
|
||||
}
|
||||
|
||||
private IEnumerable<RenameEpisodeFilePreview> GetPreviews(Series series, List<Episode> episodes, List<EpisodeFile> files)
|
||||
|
@ -110,62 +114,68 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
private void RenameFiles(List<EpisodeFile> episodeFiles, Series series)
|
||||
{
|
||||
var renamed = new List<EpisodeFile>();
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
//var renamed = new List<EpisodeFile>();
|
||||
|
||||
foreach (var episodeFile in episodeFiles)
|
||||
{
|
||||
var episodeFilePath = Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
//foreach (var episodeFile in episodeFiles)
|
||||
//{
|
||||
// var episodeFilePath = Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
|
||||
try
|
||||
{
|
||||
_logger.Debug("Renaming episode file: {0}", episodeFile);
|
||||
_episodeFileMover.MoveEpisodeFile(episodeFile, series);
|
||||
// try
|
||||
// {
|
||||
// _logger.Debug("Renaming episode file: {0}", episodeFile);
|
||||
// _episodeFileMover.MoveEpisodeFile(episodeFile, series);
|
||||
|
||||
_mediaFileService.Update(episodeFile);
|
||||
renamed.Add(episodeFile);
|
||||
// _mediaFileService.Update(episodeFile);
|
||||
// renamed.Add(episodeFile);
|
||||
|
||||
_logger.Debug("Renamed episode file: {0}", episodeFile);
|
||||
}
|
||||
catch (SameFilenameException ex)
|
||||
{
|
||||
_logger.Debug("File not renamed, source and destination are the same: {0}", ex.Filename);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, "Failed to rename file {0}", episodeFilePath);
|
||||
}
|
||||
}
|
||||
// _logger.Debug("Renamed episode file: {0}", episodeFile);
|
||||
// }
|
||||
// catch (SameFilenameException ex)
|
||||
// {
|
||||
// _logger.Debug("File not renamed, source and destination are the same: {0}", ex.Filename);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// _logger.Error(ex, "Failed to rename file {0}", episodeFilePath);
|
||||
// }
|
||||
//}
|
||||
|
||||
if (renamed.Any())
|
||||
{
|
||||
_diskProvider.RemoveEmptySubfolders(series.Path);
|
||||
//if (renamed.Any())
|
||||
//{
|
||||
// _diskProvider.RemoveEmptySubfolders(series.Path);
|
||||
|
||||
_eventAggregator.PublishEvent(new SeriesRenamedEvent(series));
|
||||
}
|
||||
// _eventAggregator.PublishEvent(new SeriesRenamedEvent(series));
|
||||
//}
|
||||
}
|
||||
|
||||
public void Execute(RenameFilesCommand message)
|
||||
{
|
||||
var series = _seriesService.GetSeries(message.SeriesId);
|
||||
var episodeFiles = _mediaFileService.Get(message.Files);
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
//var series = _seriesService.GetSeries(message.SeriesId);
|
||||
//var episodeFiles = _mediaFileService.Get(message.Files);
|
||||
|
||||
_logger.ProgressInfo("Renaming {0} files for {1}", episodeFiles.Count, series.Title);
|
||||
RenameFiles(episodeFiles, series);
|
||||
_logger.ProgressInfo("Selected episode files renamed for {0}", series.Title);
|
||||
//_logger.ProgressInfo("Renaming {0} files for {1}", episodeFiles.Count, series.Title);
|
||||
//RenameFiles(episodeFiles, series);
|
||||
//_logger.ProgressInfo("Selected episode files renamed for {0}", series.Title);
|
||||
}
|
||||
|
||||
public void Execute(RenameSeriesCommand message)
|
||||
{
|
||||
_logger.Debug("Renaming all files for selected series");
|
||||
var seriesToRename = _seriesService.GetSeries(message.SeriesIds);
|
||||
// TODO
|
||||
throw new NotImplementedException();
|
||||
//_logger.Debug("Renaming all files for selected series");
|
||||
//var seriesToRename = _seriesService.GetSeries(message.SeriesIds);
|
||||
|
||||
foreach (var series in seriesToRename)
|
||||
{
|
||||
var episodeFiles = _mediaFileService.GetFilesBySeries(series.Id);
|
||||
_logger.ProgressInfo("Renaming all files in series: {0}", series.Title);
|
||||
RenameFiles(episodeFiles, series);
|
||||
_logger.ProgressInfo("All episode files renamed for {0}", series.Title);
|
||||
}
|
||||
//foreach (var series in seriesToRename)
|
||||
//{
|
||||
// var episodeFiles = _mediaFileService.GetFilesBySeries(series.Id);
|
||||
// _logger.ProgressInfo("Renaming all files in series: {0}", series.Title);
|
||||
// RenameFiles(episodeFiles, series);
|
||||
// _logger.ProgressInfo("All episode files renamed for {0}", series.Title);
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
public class TrackFileMoveResult
|
||||
{
|
||||
public TrackFileMoveResult()
|
||||
{
|
||||
OldFiles = new List<TrackFile>();
|
||||
}
|
||||
|
||||
public TrackFile TrackFile { get; set; }
|
||||
public List<TrackFile> OldFiles { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Tv;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
public interface IMoveTrackFiles
|
||||
{
|
||||
TrackFile MoveTrackFile(TrackFile trackFile, Artist artist);
|
||||
TrackFile MoveTrackFile(TrackFile trackFile, LocalTrack localTrack);
|
||||
TrackFile CopyTrackFile(TrackFile trackFile, LocalTrack localTrack);
|
||||
}
|
||||
|
||||
public class TrackFileMovingService : IMoveTrackFiles
|
||||
{
|
||||
private readonly ITrackService _trackService;
|
||||
//private readonly IUpdateTrackFileService _updateTrackFileService;
|
||||
private readonly IBuildFileNames _buildFileNames;
|
||||
private readonly IDiskTransferService _diskTransferService;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IMediaFileAttributeService _mediaFileAttributeService;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly IConfigService _configService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public TrackFileMovingService(ITrackService episodeService,
|
||||
//IUpdateEpisodeFileService updateEpisodeFileService,
|
||||
IBuildFileNames buildFileNames,
|
||||
IDiskTransferService diskTransferService,
|
||||
IDiskProvider diskProvider,
|
||||
IMediaFileAttributeService mediaFileAttributeService,
|
||||
IEventAggregator eventAggregator,
|
||||
IConfigService configService,
|
||||
Logger logger)
|
||||
{
|
||||
_trackService = episodeService;
|
||||
//_updateTrackFileService = updateEpisodeFileService;
|
||||
_buildFileNames = buildFileNames;
|
||||
_diskTransferService = diskTransferService;
|
||||
_diskProvider = diskProvider;
|
||||
_mediaFileAttributeService = mediaFileAttributeService;
|
||||
_eventAggregator = eventAggregator;
|
||||
_configService = configService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public TrackFile MoveTrackFile(TrackFile trackFile, Artist artist)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
// TODO
|
||||
//var tracks = _trackService.GetTracksByFileId(trackFile.Id);
|
||||
//var newFileName = _buildFileNames.BuildFileName(tracks, artist, trackFile);
|
||||
//var filePath = _buildFileNames.BuildFilePath(artist, tracks.First(), trackFile.AlbumId, newFileName, Path.GetExtension(trackFile.RelativePath));
|
||||
|
||||
//EnsureAlbumFolder(trackFile, artist, tracks.Select(v => v.Album).First(), filePath);
|
||||
|
||||
//_logger.Debug("Renaming track file: {0} to {1}", trackFile, filePath);
|
||||
|
||||
//return TransferFile(trackFile, artist, tracks, filePath, TransferMode.Move);
|
||||
}
|
||||
|
||||
public TrackFile MoveTrackFile(TrackFile trackFile, LocalTrack localTrack)
|
||||
{
|
||||
// TODO
|
||||
throw new System.NotImplementedException();
|
||||
//var newFileName = _buildFileNames.BuildFileName(localEpisode.Episodes, localEpisode.Series, episodeFile);
|
||||
//var filePath = _buildFileNames.BuildFilePath(localEpisode.Series, localEpisode.SeasonNumber, newFileName, Path.GetExtension(localEpisode.Path));
|
||||
|
||||
//EnsureEpisodeFolder(episodeFile, localEpisode, filePath);
|
||||
|
||||
//_logger.Debug("Moving episode file: {0} to {1}", episodeFile.Path, filePath);
|
||||
|
||||
//return TransferFile(episodeFile, localEpisode.Series, localEpisode.Episodes, filePath, TransferMode.Move);
|
||||
}
|
||||
|
||||
public TrackFile CopyTrackFile(TrackFile trackFile, LocalTrack localTrack)
|
||||
{
|
||||
// TODO
|
||||
throw new System.NotImplementedException();
|
||||
//var newFileName = _buildFileNames.BuildFileName(localEpisode.Episodes, localEpisode.Series, episodeFile);
|
||||
//var filePath = _buildFileNames.BuildFilePath(localEpisode.Series, localEpisode.SeasonNumber, newFileName, Path.GetExtension(localEpisode.Path));
|
||||
|
||||
//EnsureEpisodeFolder(episodeFile, localEpisode, filePath);
|
||||
|
||||
//if (_configService.CopyUsingHardlinks)
|
||||
//{
|
||||
// _logger.Debug("Hardlinking episode file: {0} to {1}", episodeFile.Path, filePath);
|
||||
// return TransferFile(episodeFile, localEpisode.Series, localEpisode.Episodes, filePath, TransferMode.HardLinkOrCopy);
|
||||
//}
|
||||
|
||||
//_logger.Debug("Copying episode file: {0} to {1}", episodeFile.Path, filePath);
|
||||
//return TransferFile(episodeFile, localEpisode.Series, localEpisode.Episodes, filePath, TransferMode.Copy);
|
||||
}
|
||||
|
||||
private EpisodeFile TransferFile(EpisodeFile episodeFile, Series series, List<Episode> episodes, string destinationFilePath, TransferMode mode)
|
||||
{
|
||||
// TODO
|
||||
throw new System.NotImplementedException();
|
||||
|
||||
//Ensure.That(episodeFile, () => episodeFile).IsNotNull();
|
||||
//Ensure.That(series, () => series).IsNotNull();
|
||||
//Ensure.That(destinationFilePath, () => destinationFilePath).IsValidPath();
|
||||
|
||||
//var episodeFilePath = episodeFile.Path ?? Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
|
||||
//if (!_diskProvider.FileExists(episodeFilePath))
|
||||
//{
|
||||
// throw new FileNotFoundException("Episode file path does not exist", episodeFilePath);
|
||||
//}
|
||||
|
||||
//if (episodeFilePath == destinationFilePath)
|
||||
//{
|
||||
// throw new SameFilenameException("File not moved, source and destination are the same", episodeFilePath);
|
||||
//}
|
||||
|
||||
//_diskTransferService.TransferFile(episodeFilePath, destinationFilePath, mode);
|
||||
|
||||
//episodeFile.RelativePath = series.Path.GetRelativePath(destinationFilePath);
|
||||
|
||||
//_updateTrackFileService.ChangeFileDateForFile(episodeFile, series, episodes);
|
||||
|
||||
//try
|
||||
//{
|
||||
// _mediaFileAttributeService.SetFolderLastWriteTime(series.Path, episodeFile.DateAdded);
|
||||
|
||||
// if (series.SeasonFolder)
|
||||
// {
|
||||
// var seasonFolder = Path.GetDirectoryName(destinationFilePath);
|
||||
|
||||
// _mediaFileAttributeService.SetFolderLastWriteTime(seasonFolder, episodeFile.DateAdded);
|
||||
// }
|
||||
//}
|
||||
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// _logger.Warn(ex, "Unable to set last write time");
|
||||
//}
|
||||
|
||||
//_mediaFileAttributeService.SetFilePermissions(destinationFilePath);
|
||||
|
||||
//return episodeFile;
|
||||
}
|
||||
|
||||
private void EnsureEpisodeFolder(EpisodeFile episodeFile, LocalEpisode localEpisode, string filePath)
|
||||
{
|
||||
EnsureEpisodeFolder(episodeFile, localEpisode.Series, localEpisode.SeasonNumber, filePath);
|
||||
}
|
||||
|
||||
private void EnsureEpisodeFolder(EpisodeFile episodeFile, Series series, int seasonNumber, string filePath)
|
||||
{
|
||||
var episodeFolder = Path.GetDirectoryName(filePath);
|
||||
var seasonFolder = _buildFileNames.BuildSeasonPath(series, seasonNumber);
|
||||
var seriesFolder = series.Path;
|
||||
var rootFolder = new OsPath(seriesFolder).Directory.FullPath;
|
||||
|
||||
if (!_diskProvider.FolderExists(rootFolder))
|
||||
{
|
||||
throw new DirectoryNotFoundException(string.Format("Root folder '{0}' was not found.", rootFolder));
|
||||
}
|
||||
|
||||
var changed = false;
|
||||
var newEvent = new EpisodeFolderCreatedEvent(series, episodeFile);
|
||||
|
||||
if (!_diskProvider.FolderExists(seriesFolder))
|
||||
{
|
||||
CreateFolder(seriesFolder);
|
||||
newEvent.SeriesFolder = seriesFolder;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (seriesFolder != seasonFolder && !_diskProvider.FolderExists(seasonFolder))
|
||||
{
|
||||
CreateFolder(seasonFolder);
|
||||
newEvent.SeasonFolder = seasonFolder;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (seasonFolder != episodeFolder && !_diskProvider.FolderExists(episodeFolder))
|
||||
{
|
||||
CreateFolder(episodeFolder);
|
||||
newEvent.EpisodeFolder = episodeFolder;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
_eventAggregator.PublishEvent(newEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateFolder(string directoryName)
|
||||
{
|
||||
Ensure.That(directoryName, () => directoryName).IsNotNullOrWhiteSpace();
|
||||
|
||||
var parentFolder = new OsPath(directoryName).Directory.FullPath;
|
||||
if (!_diskProvider.FolderExists(parentFolder))
|
||||
{
|
||||
CreateFolder(parentFolder);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_diskProvider.CreateFolder(directoryName);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
_logger.Error(ex, "Unable to create directory: {0}", directoryName);
|
||||
}
|
||||
|
||||
_mediaFileAttributeService.SetFolderPermissions(directoryName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.TrackImport
|
||||
{
|
||||
public interface IImportApprovedTracks
|
||||
{
|
||||
List<ImportResult> Import(List<ImportDecision> decisions, bool newDownload, DownloadClientItem downloadClientItem = null, ImportMode importMode = ImportMode.Auto);
|
||||
}
|
||||
|
||||
public class ImportApprovedTracks : IImportApprovedTracks
|
||||
{
|
||||
private readonly IUpgradeMediaFiles _trackFileUpgrader;
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
//private readonly IExtraService _extraService;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public ImportApprovedTracks(IUpgradeMediaFiles episodeFileUpgrader,
|
||||
IMediaFileService mediaFileService,
|
||||
//IExtraService extraService,
|
||||
IDiskProvider diskProvider,
|
||||
IEventAggregator eventAggregator,
|
||||
Logger logger)
|
||||
{
|
||||
_trackFileUpgrader = episodeFileUpgrader;
|
||||
_mediaFileService = mediaFileService;
|
||||
// _extraService = extraService;
|
||||
_diskProvider = diskProvider;
|
||||
_eventAggregator = eventAggregator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public List<ImportResult> Import(List<ImportDecision> decisions, bool newDownload, DownloadClientItem downloadClientItem = null, ImportMode importMode = ImportMode.Auto)
|
||||
{
|
||||
var qualifiedImports = decisions.Where(c => c.Approved)
|
||||
.GroupBy(c => c.LocalTrack.Artist.Id, (i, s) => s
|
||||
.OrderByDescending(c => c.LocalTrack.Quality, new QualityModelComparer(s.First().LocalTrack.Artist.Profile))
|
||||
.ThenByDescending(c => c.LocalTrack.Size))
|
||||
.SelectMany(c => c)
|
||||
.ToList();
|
||||
|
||||
var importResults = new List<ImportResult>();
|
||||
|
||||
foreach (var importDecision in qualifiedImports.OrderBy(e => e.LocalTrack.Tracks.Select(track => track.TrackNumber).MinOrDefault())
|
||||
.ThenByDescending(e => e.LocalTrack.Size))
|
||||
{
|
||||
var localTrack = importDecision.LocalTrack;
|
||||
var oldFiles = new List<TrackFile>();
|
||||
|
||||
try
|
||||
{
|
||||
//check if already imported
|
||||
if (importResults.SelectMany(r => r.ImportDecision.LocalTrack.Tracks)
|
||||
.Select(e => e.Id)
|
||||
.Intersect(localTrack.Tracks.Select(e => e.Id))
|
||||
.Any())
|
||||
{
|
||||
importResults.Add(new ImportResult(importDecision, "Episode has already been imported"));
|
||||
continue;
|
||||
}
|
||||
|
||||
var trackFile = new TrackFile();
|
||||
trackFile.DateAdded = DateTime.UtcNow;
|
||||
trackFile.SpotifyTrackId = localTrack.Artist.SpotifyId;
|
||||
trackFile.Path = localTrack.Path.CleanFilePath();
|
||||
trackFile.Size = _diskProvider.GetFileSize(localTrack.Path);
|
||||
trackFile.Quality = localTrack.Quality;
|
||||
trackFile.MediaInfo = localTrack.MediaInfo;
|
||||
//trackFile.AlbumId = localTrack.Album.ElementAt(0); // TODO: Implement ImportApprovedTracks Album Id
|
||||
trackFile.Tracks = localTrack.Tracks;
|
||||
trackFile.ReleaseGroup = localTrack.ParsedTrackInfo.ReleaseGroup;
|
||||
|
||||
bool copyOnly;
|
||||
switch (importMode)
|
||||
{
|
||||
default:
|
||||
case ImportMode.Auto:
|
||||
copyOnly = downloadClientItem != null && downloadClientItem.IsReadOnly;
|
||||
break;
|
||||
case ImportMode.Move:
|
||||
copyOnly = false;
|
||||
break;
|
||||
case ImportMode.Copy:
|
||||
copyOnly = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (newDownload)
|
||||
{
|
||||
//trackFile.SceneName = GetSceneName(downloadClientItem, localTrack);
|
||||
|
||||
var moveResult = _trackFileUpgrader.UpgradeTrackFile(trackFile, localTrack, copyOnly);
|
||||
oldFiles = moveResult.OldFiles;
|
||||
}
|
||||
else
|
||||
{
|
||||
trackFile.RelativePath = localTrack.Artist.Path.GetRelativePath(trackFile.Path);
|
||||
}
|
||||
|
||||
_mediaFileService.Add(trackFile);
|
||||
importResults.Add(new ImportResult(importDecision));
|
||||
|
||||
//if (newDownload)
|
||||
//{
|
||||
// _extraService.ImportExtraFiles(localTrack, trackFile, copyOnly); // TODO: Import Music Extras
|
||||
//}
|
||||
|
||||
if (downloadClientItem != null)
|
||||
{
|
||||
_eventAggregator.PublishEvent(new TrackImportedEvent(localTrack, trackFile, newDownload, downloadClientItem.DownloadClient, downloadClientItem.DownloadId, downloadClientItem.IsReadOnly));
|
||||
}
|
||||
else
|
||||
{
|
||||
_eventAggregator.PublishEvent(new TrackImportedEvent(localTrack, trackFile, newDownload));
|
||||
}
|
||||
|
||||
if (newDownload)
|
||||
{
|
||||
_eventAggregator.PublishEvent(new TrackDownloadedEvent(localTrack, trackFile, oldFiles));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Warn(e, "Couldn't import track " + localTrack);
|
||||
importResults.Add(new ImportResult(importDecision, "Failed to import episode"));
|
||||
}
|
||||
}
|
||||
|
||||
//Adding all the rejected decisions
|
||||
importResults.AddRange(decisions.Where(c => !c.Approved)
|
||||
.Select(d => new ImportResult(d, d.Rejections.Select(r => r.Reason).ToArray())));
|
||||
|
||||
return importResults;
|
||||
}
|
||||
|
||||
//private string GetSceneName(DownloadClientItem downloadClientItem, LocalEpisode localEpisode)
|
||||
//{
|
||||
// if (downloadClientItem != null)
|
||||
// {
|
||||
// var title = Parser.Parser.RemoveFileExtension(downloadClientItem.Title);
|
||||
|
||||
// var parsedTitle = Parser.Parser.ParseTitle(title);
|
||||
|
||||
// if (parsedTitle != null && !parsedTitle.FullSeason)
|
||||
// {
|
||||
// return title;
|
||||
// }
|
||||
// }
|
||||
|
||||
// var fileName = Path.GetFileNameWithoutExtension(localEpisode.Path.CleanFilePath());
|
||||
|
||||
// if (SceneChecker.IsSceneTitle(fileName))
|
||||
// {
|
||||
// return fileName;
|
||||
// }
|
||||
|
||||
// return null;
|
||||
//}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.TrackImport
|
||||
{
|
||||
public class ImportDecision
|
||||
{
|
||||
public LocalTrack LocalTrack { get; private set; }
|
||||
public IEnumerable<Rejection> Rejections { get; private set; }
|
||||
|
||||
public bool Approved => Rejections.Empty();
|
||||
|
||||
public object LocalEpisode { get; internal set; }
|
||||
|
||||
public ImportDecision(LocalTrack localTrack, params Rejection[] rejections)
|
||||
{
|
||||
LocalTrack = localTrack;
|
||||
Rejections = rejections.ToList();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
namespace NzbDrone.Core.MediaFiles.TrackImport
|
||||
{
|
||||
public enum ImportMode
|
||||
{
|
|
@ -1,8 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
namespace NzbDrone.Core.MediaFiles.TrackImport
|
||||
{
|
||||
public class ImportResult
|
||||
{
|
|
@ -1,4 +1,4 @@
|
|||
namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||
namespace NzbDrone.Core.MediaFiles.TrackImport
|
||||
{
|
||||
public enum ImportResultType
|
||||
{
|
|
@ -9,7 +9,8 @@ namespace NzbDrone.Core.MediaFiles
|
|||
{
|
||||
public interface IUpgradeMediaFiles
|
||||
{
|
||||
EpisodeFileMoveResult UpgradeEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode, bool copyOnly = false);
|
||||
//EpisodeFileMoveResult UpgradeEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode, bool copyOnly = false);
|
||||
TrackFileMoveResult UpgradeTrackFile(TrackFile trackFile, LocalTrack localTrack, bool copyOnly = false);
|
||||
}
|
||||
|
||||
public class UpgradeMediaFileService : IUpgradeMediaFiles
|
||||
|
@ -17,35 +18,36 @@ namespace NzbDrone.Core.MediaFiles
|
|||
private readonly IRecycleBinProvider _recycleBinProvider;
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly IMoveEpisodeFiles _episodeFileMover;
|
||||
private readonly IMoveTrackFiles _trackFileMover;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public UpgradeMediaFileService(IRecycleBinProvider recycleBinProvider,
|
||||
IMediaFileService mediaFileService,
|
||||
IMoveEpisodeFiles episodeFileMover,
|
||||
IMoveTrackFiles trackFileMover,
|
||||
IDiskProvider diskProvider,
|
||||
Logger logger)
|
||||
{
|
||||
_recycleBinProvider = recycleBinProvider;
|
||||
_mediaFileService = mediaFileService;
|
||||
_episodeFileMover = episodeFileMover;
|
||||
_trackFileMover = trackFileMover;
|
||||
_diskProvider = diskProvider;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public EpisodeFileMoveResult UpgradeEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode, bool copyOnly = false)
|
||||
public TrackFileMoveResult UpgradeTrackFile(TrackFile trackFile, LocalTrack localTrack, bool copyOnly = false)
|
||||
{
|
||||
var moveFileResult = new EpisodeFileMoveResult();
|
||||
var existingFiles = localEpisode.Episodes
|
||||
.Where(e => e.EpisodeFileId > 0)
|
||||
.Select(e => e.EpisodeFile.Value)
|
||||
var moveFileResult = new TrackFileMoveResult();
|
||||
var existingFiles = localTrack.Tracks
|
||||
.Where(e => e.TrackFileId > 0)
|
||||
.Select(e => e.TrackFile.Value)
|
||||
.GroupBy(e => e.Id);
|
||||
|
||||
foreach (var existingFile in existingFiles)
|
||||
{
|
||||
var file = existingFile.First();
|
||||
var episodeFilePath = Path.Combine(localEpisode.Series.Path, file.RelativePath);
|
||||
var subfolder = _diskProvider.GetParentFolder(localEpisode.Series.Path).GetRelativePath(_diskProvider.GetParentFolder(episodeFilePath));
|
||||
var episodeFilePath = Path.Combine(localTrack.Artist.Path, file.RelativePath);
|
||||
var subfolder = _diskProvider.GetParentFolder(localTrack.Artist.Path).GetRelativePath(_diskProvider.GetParentFolder(episodeFilePath));
|
||||
|
||||
if (_diskProvider.FileExists(episodeFilePath))
|
||||
{
|
||||
|
@ -59,11 +61,11 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
if (copyOnly)
|
||||
{
|
||||
moveFileResult.EpisodeFile = _episodeFileMover.CopyEpisodeFile(episodeFile, localEpisode);
|
||||
moveFileResult.TrackFile = _trackFileMover.CopyTrackFile(trackFile, localTrack);
|
||||
}
|
||||
else
|
||||
{
|
||||
moveFileResult.EpisodeFile = _episodeFileMover.MoveEpisodeFile(episodeFile, localEpisode);
|
||||
moveFileResult.TrackFile = _trackFileMover.MoveTrackFile(trackFile, localTrack);
|
||||
}
|
||||
|
||||
return moveFileResult;
|
||||
|
|
|
@ -205,7 +205,7 @@ namespace NzbDrone.Core.MetadataSource.SkyHook
|
|||
var lowerTitle = title.ToLowerInvariant();
|
||||
Console.WriteLine("Searching for " + lowerTitle);
|
||||
|
||||
if (lowerTitle.StartsWith("itunes:") || lowerTitle.StartsWith("itunesid:"))
|
||||
if (lowerTitle.StartsWith("spotify:") || lowerTitle.StartsWith("spotifyid:"))
|
||||
{
|
||||
var slug = lowerTitle.Split(':')[1].Trim();
|
||||
|
||||
|
|
|
@ -55,11 +55,16 @@ namespace NzbDrone.Core.Music
|
|||
return _trackRepository.Get(ids).ToList();
|
||||
}
|
||||
|
||||
public Track FindTrack(string artistId, string albumId, int episodeNumber)
|
||||
public Track FindTrack(string artistId, string albumId, int trackNumber)
|
||||
{
|
||||
return _trackRepository.Find(artistId, albumId, episodeNumber);
|
||||
return _trackRepository.Find(artistId, albumId, trackNumber);
|
||||
}
|
||||
|
||||
//public Track FindTrack(string artistId, int trackNumber)
|
||||
//{
|
||||
// return _trackRepository.Find(artistId, trackNumber);
|
||||
//}
|
||||
|
||||
public List<Track> GetTracksByArtist(string artistId)
|
||||
{
|
||||
return _trackRepository.GetTracks(artistId).ToList();
|
||||
|
@ -132,7 +137,7 @@ namespace NzbDrone.Core.Music
|
|||
_trackRepository.SetMonitoredByAlbum(artistId, albumId, monitored);
|
||||
}
|
||||
|
||||
public void UpdateEpisodes(List<Track> tracks)
|
||||
public void UpdateTracks(List<Track> tracks)
|
||||
{
|
||||
_trackRepository.UpdateMany(tracks);
|
||||
}
|
||||
|
@ -182,10 +187,5 @@ namespace NzbDrone.Core.Music
|
|||
_logger.Debug("Linking [{0}] > [{1}]", message.TrackFile.RelativePath, track);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateTracks(List<Track> tracks)
|
||||
{
|
||||
_trackRepository.UpdateMany(tracks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -725,7 +725,10 @@
|
|||
<Compile Include="MediaFiles\Commands\BackendCommandAttribute.cs" />
|
||||
<Compile Include="MediaFiles\Commands\CleanUpRecycleBinCommand.cs" />
|
||||
<Compile Include="MediaFiles\Commands\DownloadedEpisodesScanCommand.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\ImportMode.cs" />
|
||||
<Compile Include="MediaFiles\Events\TrackDownloadedEvent.cs" />
|
||||
<Compile Include="MediaFiles\TrackFileMovingService.cs" />
|
||||
<Compile Include="MediaFiles\TrackFileMoveResult.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\ImportMode.cs" />
|
||||
<Compile Include="MediaFiles\Commands\RenameFilesCommand.cs" />
|
||||
<Compile Include="MediaFiles\Commands\RenameSeriesCommand.cs" />
|
||||
<Compile Include="MediaFiles\Commands\RescanSeriesCommand.cs" />
|
||||
|
@ -740,12 +743,10 @@
|
|||
<Compile Include="MediaFiles\EpisodeFile.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeFileMoveResult.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeFileMovingService.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\ImportResult.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\IImportDecisionEngineSpecification.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\ImportApprovedEpisodes.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\ImportDecision.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\ImportDecisionMaker.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\ImportResultType.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\ImportResultType.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Manual\ManualImportFile.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Manual\ManualImportCommand.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Manual\ManualImportItem.cs" />
|
||||
|
@ -761,11 +762,14 @@
|
|||
<Compile Include="MediaFiles\EpisodeImport\Specifications\UnverifiedSceneNumberingSpecification.cs" />
|
||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\UpgradeSpecification.cs" />
|
||||
<Compile Include="MediaFiles\Events\ArtistRenamedEvent.cs" />
|
||||
<Compile Include="MediaFiles\Events\ArtistScannedEvent.cs" />
|
||||
<Compile Include="MediaFiles\Events\ArtistScanSkippedEvent.cs" />
|
||||
<Compile Include="MediaFiles\Events\EpisodeDownloadedEvent.cs" />
|
||||
<Compile Include="MediaFiles\Events\EpisodeFileAddedEvent.cs" />
|
||||
<Compile Include="MediaFiles\Events\EpisodeFileDeletedEvent.cs" />
|
||||
<Compile Include="MediaFiles\Events\EpisodeFolderCreatedEvent.cs" />
|
||||
<Compile Include="MediaFiles\Events\EpisodeImportedEvent.cs" />
|
||||
<Compile Include="MediaFiles\Commands\RescanArtistCommand.cs" />
|
||||
<Compile Include="MediaFiles\Events\SeriesRenamedEvent.cs" />
|
||||
<Compile Include="MediaFiles\Events\SeriesScanSkippedEvent.cs" />
|
||||
<Compile Include="MediaFiles\Events\SeriesScannedEvent.cs" />
|
||||
|
@ -789,6 +793,9 @@
|
|||
<Compile Include="MediaFiles\RenameEpisodeFileService.cs" />
|
||||
<Compile Include="MediaFiles\SameFilenameException.cs" />
|
||||
<Compile Include="MediaFiles\TrackFile.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\ImportApprovedTracks.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\ImportDecision.cs" />
|
||||
<Compile Include="MediaFiles\TrackImport\ImportResult.cs" />
|
||||
<Compile Include="MediaFiles\UpdateEpisodeFileService.cs" />
|
||||
<Compile Include="MediaFiles\UpgradeMediaFileService.cs" />
|
||||
<Compile Include="Messaging\Commands\BackendCommandAttribute.cs" />
|
||||
|
@ -928,6 +935,7 @@
|
|||
<Compile Include="Parser\IsoLanguage.cs" />
|
||||
<Compile Include="Parser\IsoLanguages.cs" />
|
||||
<Compile Include="Parser\LanguageParser.cs" />
|
||||
<Compile Include="Parser\Model\ArtistTitleInfo.cs" />
|
||||
<Compile Include="Parser\Model\LocalTrack.cs" />
|
||||
<Compile Include="Parser\Model\ParsedTrackInfo.cs" />
|
||||
<Compile Include="Profiles\Delay\DelayProfile.cs" />
|
||||
|
|
|
@ -380,33 +380,34 @@ namespace NzbDrone.Core.Parser
|
|||
|
||||
if (result != null)
|
||||
{
|
||||
if (result.FullSeason && title.ContainsIgnoreCase("Special"))
|
||||
{
|
||||
result.FullSeason = false;
|
||||
result.Special = true;
|
||||
}
|
||||
//if (result.FullSeason && title.ContainsIgnoreCase("Special"))
|
||||
//{
|
||||
// result.FullSeason = false;
|
||||
// result.Special = true;
|
||||
//}
|
||||
|
||||
result.Language = LanguageParser.ParseLanguage(title);
|
||||
Logger.Debug("Language parsed: {0}", result.Language);
|
||||
//result.Language = LanguageParser.ParseLanguage(title);
|
||||
//Logger.Debug("Language parsed: {0}", result.Language);
|
||||
|
||||
result.Quality = QualityParser.ParseQuality(title);
|
||||
Logger.Debug("Quality parsed: {0}", result.Quality);
|
||||
|
||||
result.ReleaseGroup = ParseReleaseGroup(title);
|
||||
// Majora: We don't currently need Release Group for Music.
|
||||
//result.ReleaseGroup = ParseReleaseGroup(title);
|
||||
|
||||
var subGroup = GetSubGroup(match);
|
||||
if (!subGroup.IsNullOrWhiteSpace())
|
||||
{
|
||||
result.ReleaseGroup = subGroup;
|
||||
}
|
||||
//var subGroup = GetSubGroup(match);
|
||||
//if (!subGroup.IsNullOrWhiteSpace())
|
||||
//{
|
||||
// result.ReleaseGroup = subGroup;
|
||||
//}
|
||||
|
||||
Logger.Debug("Release Group parsed: {0}", result.ReleaseGroup);
|
||||
//Logger.Debug("Release Group parsed: {0}", result.ReleaseGroup);
|
||||
|
||||
result.ReleaseHash = GetReleaseHash(match);
|
||||
if (!result.ReleaseHash.IsNullOrWhiteSpace())
|
||||
{
|
||||
Logger.Debug("Release Hash parsed: {0}", result.ReleaseHash);
|
||||
}
|
||||
//result.ReleaseHash = GetReleaseHash(match);
|
||||
//if (!result.ReleaseHash.IsNullOrWhiteSpace())
|
||||
//{
|
||||
// Logger.Debug("Release Hash parsed: {0}", result.ReleaseHash);
|
||||
//}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -457,7 +457,9 @@ namespace NzbDrone.Core.Parser
|
|||
|
||||
if (trackInfo == null)
|
||||
{
|
||||
trackInfo = _trackService.FindTrack(artist.SpotifyId, trackNumber);
|
||||
// TODO: [ParsingService]: FindTrack by artistID and trackNumber (or albumID and trackNumber if we change db schema to album as base)
|
||||
_logger.Debug("TrackInfo is null, we will not add as FindTrack(artistId, trackNumber) is not implemented");
|
||||
//trackInfo = _trackService.FindTrack(artist.SpotifyId, trackNumber);
|
||||
}
|
||||
|
||||
if (trackInfo != null)
|
||||
|
@ -467,7 +469,7 @@ namespace NzbDrone.Core.Parser
|
|||
|
||||
else
|
||||
{
|
||||
_logger.Debug("Unable to find {0}", parsedEpisodeInfo);
|
||||
_logger.Debug("Unable to find {0}", parsedTrackInfo);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -553,6 +555,7 @@ namespace NzbDrone.Core.Parser
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
public LocalTrack GetLocalTrack(string filename, Artist artist)
|
||||
{
|
||||
return GetLocalTrack(filename, artist, null);
|
||||
|
@ -635,7 +638,60 @@ namespace NzbDrone.Core.Parser
|
|||
}
|
||||
|
||||
return GetStandardEpisodes(artist, parsedTrackInfo, sceneSource, searchCriteria);*/
|
||||
return GetStandardTracks(artist, parsedTrackInfo, searchCriteria);
|
||||
return GetStandardTracks(artist, parsedTrackInfo);
|
||||
}
|
||||
|
||||
private List<Track> GetStandardTracks(Artist artist, ParsedTrackInfo parsedTrackInfo)
|
||||
{
|
||||
var result = new List<Track>();
|
||||
//var seasonNumber = parsedEpisodeInfo.SeasonNumber;
|
||||
|
||||
//if (sceneSource)
|
||||
//{
|
||||
// var sceneMapping = _sceneMappingService.FindSceneMapping(parsedEpisodeInfo.SeriesTitle);
|
||||
|
||||
// if (sceneMapping != null && sceneMapping.SeasonNumber.HasValue && sceneMapping.SeasonNumber.Value >= 0 &&
|
||||
// sceneMapping.SceneSeasonNumber == seasonNumber)
|
||||
// {
|
||||
// seasonNumber = sceneMapping.SeasonNumber.Value;
|
||||
// }
|
||||
//}
|
||||
|
||||
if (parsedTrackInfo.TrackNumbers == null)
|
||||
{
|
||||
return new List<Track>();
|
||||
}
|
||||
|
||||
foreach (var trackNumber in parsedTrackInfo.TrackNumbers)
|
||||
{
|
||||
|
||||
|
||||
Track trackInfo = null;
|
||||
|
||||
//if (searchCriteria != null)
|
||||
//{
|
||||
// trackInfo = searchCriteria.Episodes.SingleOrDefault(e => e.SeasonNumber == seasonNumber && e.EpisodeNumber == trackNumber);
|
||||
//}
|
||||
|
||||
if (trackInfo == null)
|
||||
{
|
||||
// TODO: [ParsingService]: FindTrack by artistID and trackNumber (or albumID and trackNumber if we change db schema to album as base)
|
||||
_logger.Debug("TrackInfo is null, we will not add as FindTrack(artistId, trackNumber) is not implemented");
|
||||
//trackInfo = _trackService.FindTrack(artist.SpotifyId, trackNumber); //series.Id, seasonNumber, trackNumber
|
||||
}
|
||||
|
||||
if (trackInfo != null)
|
||||
{
|
||||
result.Add(trackInfo);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
_logger.Debug("Unable to find {0}", parsedTrackInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -176,7 +176,7 @@ namespace NzbDrone.Core.Tv
|
|||
try
|
||||
{
|
||||
_logger.Info("Skipping refresh of series: {0}", series.Title);
|
||||
_diskScanService.Scan(series);
|
||||
//_diskScanService.Scan(series);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue