public List<ImportResult> ProcessPath(string path, Series series = null, DownloadClientItem downloadClientItem = null) { if (_diskProvider.FolderExists(path)) { var directoryInfo = new DirectoryInfo(path); if (series == null) { return ProcessFolder(directoryInfo, downloadClientItem); } return ProcessFolder(directoryInfo, series, downloadClientItem); } if (_diskProvider.FileExists(path)) { var fileInfo = new FileInfo(path); if (series == null) { return ProcessFile(fileInfo, downloadClientItem); } return ProcessFile(fileInfo, series, downloadClientItem); } _logger.Error("Import failed, path does not exist or is not accessible by Sonarr: {0}", path); return new List<ImportResult>(); }
public List<ImportResult> Import(List<ImportDecision> decisions, bool newDownload, DownloadClientItem downloadClientItem = null) { 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.OrderByDescending(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; if (newDownload) { bool copyOnly = downloadClientItem != null && downloadClientItem.IsReadOnly; 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 (downloadClientItem != null) { _eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile, newDownload, downloadClientItem.DownloadClient, downloadClientItem.DownloadId)); } else { _eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile, newDownload)); } if (newDownload) { _eventAggregator.PublishEvent(new EpisodeDownloadedEvent(localEpisode, episodeFile, oldFiles)); } } catch (Exception e) { _logger.WarnException("Couldn't import episode " + localEpisode, e); 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; }
private List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, Series series, DownloadClientItem downloadClientItem = null) { if (_seriesService.SeriesPathExists(directoryInfo.FullName)) { _logger.Warn("Unable to process folder that is mapped to an existing show"); return new List<ImportResult>(); } var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name); var folderInfo = Parser.Parser.ParseTitle(directoryInfo.Name); if (folderInfo != null) { _logger.Debug("{0} folder quality: {1}", cleanedUpName, folderInfo.Quality); } var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName); if (downloadClientItem == null) { foreach (var videoFile in videoFiles) { if (_diskProvider.IsFileLocked(videoFile)) { return new List<ImportResult> { FileIsLockedResult(videoFile) }; } } } var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, folderInfo, true); var importResults = _importApprovedEpisodes.Import(decisions, true, downloadClientItem); 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, Series series, DownloadClientItem downloadClientItem = null) { 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 '._'") }; } 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); return _importApprovedEpisodes.Import(decisions, true, downloadClientItem); }
private List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, DownloadClientItem downloadClientItem = null) { var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name); var series = _parsingService.GetSeries(cleanedUpName); if (series == null) { _logger.Debug("Unknown Series {0}", cleanedUpName); return new List<ImportResult> { UnknownSeriesResult("Unknown Series") }; } return ProcessFolder(directoryInfo, series, downloadClientItem); }
public abstract void RemoveItem(DownloadClientItem item, bool deleteData);
private List<ImportResult> ProcessFile(FileInfo fileInfo, DownloadClientItem downloadClientItem = null) { var series = _parsingService.GetSeries(Path.GetFileNameWithoutExtension(fileInfo.Name)); if (series == null) { _logger.Debug("Unknown Series for file: {0}", fileInfo.Name); return new List<ImportResult> { UnknownSeriesResult(string.Format("Unknown Series for file: {0}", fileInfo.Name), fileInfo.FullName) }; } return ProcessFile(fileInfo, series, downloadClientItem); }
public virtual DownloadClientItem GetImportItem(DownloadClientItem item, DownloadClientItem previousImportAttempt) { return(item); }
public virtual void MarkItemAsImported(DownloadClientItem downloadClientItem) { throw new NotSupportedException(Name + " does not support marking items as imported"); }
private List<ImportResult> ProcessFile(FileInfo fileInfo, Series series, DownloadClientItem downloadClientItem = null) { 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); return _importApprovedEpisodes.Import(decisions, true, downloadClientItem); }
public List<ImportDecision> Import(List<ImportDecision> decisions, bool newDownload, DownloadClientItem historyItem = null) { 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.QualityProfile)) .ThenByDescending(c => c.LocalEpisode.Size)) .SelectMany(c => c) .ToList(); var imported = new List<ImportDecision>(); foreach (var importDecision in qualifiedImports.OrderByDescending(e => e.LocalEpisode.Size)) { var localEpisode = importDecision.LocalEpisode; var oldFiles = new List<EpisodeFile>(); try { //check if already imported if (imported.SelectMany(r => r.LocalEpisode.Episodes) .Select(e => e.Id) .Intersect(localEpisode.Episodes.Select(e => e.Id)) .Any()) { 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.SeasonNumber = localEpisode.SeasonNumber; episodeFile.Episodes = localEpisode.Episodes; episodeFile.ReleaseGroup = localEpisode.ParsedEpisodeInfo.ReleaseGroup; if (newDownload) { bool copyOnly = historyItem != null && historyItem.IsReadOnly; episodeFile.SceneName = Path.GetFileNameWithoutExtension(localEpisode.Path.CleanFilePath()); var moveResult = _episodeFileUpgrader.UpgradeEpisodeFile(episodeFile, localEpisode, copyOnly); oldFiles = moveResult.OldFiles; } _mediaFileService.Add(episodeFile); imported.Add(importDecision); if (historyItem != null) { _eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile, newDownload, historyItem.DownloadClient, historyItem.DownloadClientId)); } else { _eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile, newDownload)); } if (newDownload) { _eventAggregator.PublishEvent(new EpisodeDownloadedEvent(localEpisode, episodeFile, oldFiles)); } } catch (Exception e) { _logger.WarnException("Couldn't import episode " + localEpisode, e); } } return imported; }
private TrackedDownload GetTrackedDownload(String trackingId, Int32 downloadClient, DownloadClientItem downloadItem, List <History.History> grabbedHistory) { var trackedDownload = new TrackedDownload { TrackingId = trackingId, DownloadClient = downloadClient, DownloadItem = downloadItem, StartedTracking = DateTime.UtcNow, State = TrackedDownloadState.Unknown, Status = TrackedDownloadStatus.Ok, }; try { var historyItems = grabbedHistory.Where(h => { var downloadClientId = h.Data.GetValueOrDefault(DOWNLOAD_CLIENT_ID); if (downloadClientId == null) { return(false); } return(downloadClientId.Equals(trackedDownload.DownloadItem.DownloadClientId)); }).ToList(); var parsedEpisodeInfo = Parser.Parser.ParseTitle(trackedDownload.DownloadItem.Title); if (parsedEpisodeInfo == null) { return(null); } var remoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0); if (remoteEpisode.Series == null) { if (historyItems.Empty()) { return(null); } trackedDownload.Status = TrackedDownloadStatus.Warning; trackedDownload.StatusMessages.Add(new TrackedDownloadStatusMessage( trackedDownload.DownloadItem.Title, "Series title mismatch, automatic import is not possible") ); remoteEpisode = _parsingService.Map(parsedEpisodeInfo, historyItems.First().SeriesId, historyItems.Select(h => h.EpisodeId)); } trackedDownload.RemoteEpisode = remoteEpisode; } catch (Exception e) { _logger.DebugException("Failed to find episode for " + downloadItem.Title, e); return(null); } return(trackedDownload); }