コード例 #1
0
        public void Import(TrackedDownload trackedDownload)
        {
            trackedDownload.State = TrackedDownloadState.Importing;

            var outputPath    = trackedDownload.DownloadItem.OutputPath.FullPath;
            var importResults = _downloadedEpisodesImportService.ProcessPath(outputPath, ImportMode.Auto,
                                                                             trackedDownload.RemoteEpisode.Series, trackedDownload.DownloadItem);

            var allEpisodesImported = importResults.Where(c => c.Result == ImportResultType.Imported)
                                      .SelectMany(c => c.ImportDecision.LocalEpisode.Episodes)
                                      .Count() >= Math.Max(1,
                                                           trackedDownload.RemoteEpisode.Episodes.Count);

            if (allEpisodesImported)
            {
                trackedDownload.State = TrackedDownloadState.Imported;
                _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload));
                return;
            }

            // Double check if all episodes were imported by checking the history if at least one
            // file was imported. This will allow the decision engine to reject already imported
            // episode files and still mark the download complete when all files are imported.

            if (importResults.Any(c => c.Result == ImportResultType.Imported))
            {
                var historyItems = _historyService.FindByDownloadId(trackedDownload.DownloadItem.DownloadId)
                                   .OrderByDescending(h => h.Date)
                                   .ToList();

                var allEpisodesImportedInHistory = _trackedDownloadAlreadyImported.IsImported(trackedDownload, historyItems);

                if (allEpisodesImportedInHistory)
                {
                    trackedDownload.State = TrackedDownloadState.Imported;
                    _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload));
                    return;
                }
            }

            trackedDownload.State = TrackedDownloadState.ImportPending;

            if (importResults.Empty())
            {
                trackedDownload.Warn("No files found are eligible for import in {0}", outputPath);
            }

            if (importResults.Any(c => c.Result != ImportResultType.Imported))
            {
                var statusMessages = importResults
                                     .Where(v => v.Result != ImportResultType.Imported)
                                     .Select(v => new TrackedDownloadStatusMessage(Path.GetFileName(v.ImportDecision.LocalEpisode.Path), v.Errors))
                                     .ToArray();

                trackedDownload.Warn(statusMessages);
            }
        }
コード例 #2
0
        public bool VerifyImport(TrackedDownload trackedDownload, List <ImportResult> importResults)
        {
            var allEpisodesImported = importResults.Where(c => c.Result == ImportResultType.Imported)
                                      .SelectMany(c => c.ImportDecision.LocalEpisode.Episodes)
                                      .Count() >= Math.Max(1,
                                                           trackedDownload.RemoteEpisode.Episodes.Count);

            if (allEpisodesImported)
            {
                _logger.Debug("All episodes were imported for {0}", trackedDownload.DownloadItem.Title);
                trackedDownload.State = TrackedDownloadState.Imported;
                _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, trackedDownload.RemoteEpisode.Series.Id));
                return(true);
            }

            // Double check if all episodes were imported by checking the history if at least one
            // file was imported. This will allow the decision engine to reject already imported
            // episode files and still mark the download complete when all files are imported.

            // EDGE CASE: This process relies on EpisodeIds being consistent between executions, if a series is updated
            // and an episode is removed, but later comes back with a different ID then Sonarr will treat it as incomplete.
            // Since imports should be relatively fast and these types of data changes are infrequent this should be quite
            // safe, but commenting for future benefit.

            var atLeastOneEpisodeImported = importResults.Any(c => c.Result == ImportResultType.Imported);

            var historyItems = _historyService.FindByDownloadId(trackedDownload.DownloadItem.DownloadId)
                               .OrderByDescending(h => h.Date)
                               .ToList();

            var allEpisodesImportedInHistory = _trackedDownloadAlreadyImported.IsImported(trackedDownload, historyItems);

            if (allEpisodesImportedInHistory)
            {
                if (atLeastOneEpisodeImported)
                {
                    _logger.Debug("All episodes were imported in history for {0}", trackedDownload.DownloadItem.Title);
                    trackedDownload.State = TrackedDownloadState.Imported;
                    _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, trackedDownload.RemoteEpisode.Series.Id));

                    return(true);
                }

                _logger.Debug()
                .Message("No Episodes were just imported, but all episodes were previously imported, possible issue with download history.")
                .Property("SeriesId", trackedDownload.RemoteEpisode.Series.Id)
                .Property("DownloadId", trackedDownload.DownloadItem.DownloadId)
                .Property("Title", trackedDownload.DownloadItem.Title)
                .Property("Path", trackedDownload.DownloadItem.OutputPath.ToString())
                .WriteSentryWarn("DownloadHistoryIncomplete")
                .Write();
            }

            _logger.Debug("Not all episodes have been imported for {0}", trackedDownload.DownloadItem.Title);
            return(false);
        }
コード例 #3
0
        public bool VerifyImport(TrackedDownload trackedDownload, List <ImportResult> importResults)
        {
            var allMoviesImported = importResults.Where(c => c.Result == ImportResultType.Imported)
                                    .Select(c => c.ImportDecision.LocalMovie.Movie)
                                    .Any();

            if (allMoviesImported)
            {
                _logger.Debug("All movies were imported for {0}", trackedDownload.DownloadItem.Title);
                trackedDownload.State = TrackedDownloadState.Imported;
                _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, trackedDownload.RemoteMovie.Movie.Id));
                return(true);
            }

            // Double check if all movies were imported by checking the history if at least one
            // file was imported. This will allow the decision engine to reject already imported
            // episode files and still mark the download complete when all files are imported.
            var atLeastOneMovieImported = importResults.Any(c => c.Result == ImportResultType.Imported);

            var historyItems = _historyService.FindByDownloadId(trackedDownload.DownloadItem.DownloadId)
                               .OrderByDescending(h => h.Date)
                               .ToList();

            var allMoviesImportedInHistory = _trackedDownloadAlreadyImported.IsImported(trackedDownload, historyItems);

            if (allMoviesImportedInHistory)
            {
                // Log different error messages depending on the circumstances, but treat both as fully imported, because that's the reality.
                // The second message shouldn't be logged in most cases, but continued reporting would indicate an ongoing issue.
                if (atLeastOneMovieImported)
                {
                    _logger.Debug("All movies were imported in history for {0}", trackedDownload.DownloadItem.Title);
                }
                else
                {
                    _logger.Debug()
                    .Message("No Movies were just imported, but all movies were previously imported, possible issue with download history.")
                    .Property("MovieId", trackedDownload.RemoteMovie.Movie.Id)
                    .Property("DownloadId", trackedDownload.DownloadItem.DownloadId)
                    .Property("Title", trackedDownload.DownloadItem.Title)
                    .Property("Path", trackedDownload.ImportItem.OutputPath.ToString())
                    .WriteSentryWarn("DownloadHistoryIncomplete")
                    .Write();
                }

                trackedDownload.State = TrackedDownloadState.Imported;
                _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, trackedDownload.RemoteMovie.Movie.Id));

                return(true);
            }

            _logger.Debug("Not all movies have been imported for {0}", trackedDownload.DownloadItem.Title);
            return(false);
        }
コード例 #4
0
        public bool VerifyImport(TrackedDownload trackedDownload, List<ImportResult> importResults)
        {
            var allItemsImported = importResults.Where(c => c.Result == ImportResultType.Imported)
                                                   .Select(c => c.ImportDecision.Item.Book)
                                                   .Count() >= Math.Max(1, trackedDownload.RemoteBook.Books.Count);

            if (allItemsImported)
            {
                trackedDownload.State = TrackedDownloadState.Imported;
                _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload));
                return true;
            }

            // Double check if all episodes were imported by checking the history if at least one
            // file was imported. This will allow the decision engine to reject already imported
            // episode files and still mark the download complete when all files are imported.

            // EDGE CASE: This process relies on EpisodeIds being consistent between executions, if a series is updated
            // and an episode is removed, but later comes back with a different ID then Sonarr will treat it as incomplete.
            // Since imports should be relatively fast and these types of data changes are infrequent this should be quite
            // safe, but commenting for future benefit.
            if (importResults.Any(c => c.Result == ImportResultType.Imported))
            {
                var historyItems = _historyService.FindByDownloadId(trackedDownload.DownloadItem.DownloadId)
                                                  .OrderByDescending(h => h.Date)
                                                  .ToList();

                var allEpisodesImportedInHistory = _trackedDownloadAlreadyImported.IsImported(trackedDownload, historyItems);

                if (allEpisodesImportedInHistory)
                {
                    trackedDownload.State = TrackedDownloadState.Imported;
                    _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload));
                    return true;
                }
            }

            return false;
        }
コード例 #5
0
        public TrackedDownload TrackDownload(DownloadClientDefinition downloadClient, DownloadClientItem downloadItem)
        {
            var existingItem = Find(downloadItem.DownloadId);

            if (existingItem != null && existingItem.State != TrackedDownloadState.Downloading)
            {
                LogItemChange(existingItem, existingItem.DownloadItem, downloadItem);

                existingItem.DownloadItem = downloadItem;
                existingItem.IsTrackable  = true;

                return(existingItem);
            }

            var trackedDownload = new TrackedDownload
            {
                DownloadClient = downloadClient.Id,
                DownloadItem   = downloadItem,
                Protocol       = downloadClient.Protocol,
                IsTrackable    = true
            };

            try
            {
                var parsedAlbumInfo = Parser.Parser.ParseAlbumTitle(trackedDownload.DownloadItem.Title);
                var historyItems    = _historyService.FindByDownloadId(downloadItem.DownloadId)
                                      .OrderByDescending(h => h.Date)
                                      .ToList();

                if (parsedAlbumInfo != null)
                {
                    trackedDownload.RemoteAlbum = _parsingService.Map(parsedAlbumInfo);
                }

                if (historyItems.Any())
                {
                    var firstHistoryItem = historyItems.First();
                    var state            = GetStateFromHistory(firstHistoryItem);

                    // One potential issue here is if the latest is imported, but other episodes are ignored or never imported.
                    // It's unlikely that will happen, but could happen if additional episodes are added to season after it's already imported.
                    if (state == TrackedDownloadState.Imported)
                    {
                        var allImported = _trackedDownloadAlreadyImported.IsImported(trackedDownload, historyItems);

                        trackedDownload.State = allImported ? TrackedDownloadState.Imported : TrackedDownloadState.Downloading;
                    }
                    else
                    {
                        trackedDownload.State = state;
                    }

                    if (firstHistoryItem.EventType == HistoryEventType.AlbumImportIncomplete)
                    {
                        var messages = Json.Deserialize <List <TrackedDownloadStatusMessage> >(firstHistoryItem?.Data["statusMessages"]).ToArray();
                        trackedDownload.Warn(messages);
                    }

                    var grabbedEvent = historyItems.FirstOrDefault(v => v.EventType == HistoryEventType.Grabbed);
                    trackedDownload.Indexer = grabbedEvent?.Data["indexer"];

                    if (parsedAlbumInfo == null ||
                        trackedDownload.RemoteAlbum == null ||
                        trackedDownload.RemoteAlbum.Artist == null ||
                        trackedDownload.RemoteAlbum.Albums.Empty())
                    {
                        // Try parsing the original source title and if that fails, try parsing it as a special
                        // TODO: Pass the TVDB ID and TVRage IDs in as well so we have a better chance for finding the item
                        var historyArtist = firstHistoryItem.Artist;
                        var historyAlbums = new List <Album> {
                            firstHistoryItem.Album
                        };

                        parsedAlbumInfo = Parser.Parser.ParseAlbumTitle(firstHistoryItem.SourceTitle);

                        if (parsedAlbumInfo != null)
                        {
                            trackedDownload.RemoteAlbum = _parsingService.Map(parsedAlbumInfo,
                                                                              firstHistoryItem.ArtistId,
                                                                              historyItems.Where(v => v.EventType == HistoryEventType.Grabbed).Select(h => h.AlbumId)
                                                                              .Distinct());
                        }
                        else
                        {
                            parsedAlbumInfo =
                                Parser.Parser.ParseAlbumTitleWithSearchCriteria(firstHistoryItem.SourceTitle,
                                                                                historyArtist,
                                                                                historyAlbums);

                            if (parsedAlbumInfo != null)
                            {
                                trackedDownload.RemoteAlbum = _parsingService.Map(parsedAlbumInfo,
                                                                                  firstHistoryItem.ArtistId,
                                                                                  historyItems.Where(v => v.EventType == HistoryEventType.Grabbed).Select(h => h.AlbumId)
                                                                                  .Distinct());
                            }
                        }
                    }
                }

                // Track it so it can be displayed in the queue even though we can't determine which artist it is for
                if (trackedDownload.RemoteAlbum == null)
                {
                    _logger.Trace("No Album found for download '{0}'", trackedDownload.DownloadItem.Title);
                    trackedDownload.Warn("No Album found for download '{0}'", trackedDownload.DownloadItem.Title);
                }
            }
            catch (Exception e)
            {
                _logger.Debug(e, "Failed to find album for " + downloadItem.Title);
                return(null);
            }

            LogItemChange(trackedDownload, existingItem?.DownloadItem, trackedDownload.DownloadItem);

            _cache.Set(trackedDownload.DownloadItem.DownloadId, trackedDownload);
            return(trackedDownload);
        }
コード例 #6
0
        public void Import(TrackedDownload trackedDownload)
        {
            SetImportItem(trackedDownload);

            if (!ValidatePath(trackedDownload))
            {
                return;
            }

            trackedDownload.State = TrackedDownloadState.Importing;

            var outputPath    = trackedDownload.ImportItem.OutputPath.FullPath;
            var importResults = _downloadedTracksImportService.ProcessPath(outputPath, ImportMode.Auto, trackedDownload.RemoteAlbum.Artist, trackedDownload.DownloadItem);

            if (importResults.Empty())
            {
                trackedDownload.Warn("No files found are eligible for import in {0}", outputPath);
                return;
            }

            var allTracksImported = importResults.All(c => c.Result == ImportResultType.Imported) ||
                                    importResults.Count(c => c.Result == ImportResultType.Imported) >=
                                    Math.Max(1, trackedDownload.RemoteAlbum.Albums.Sum(x => x.AlbumReleases.Value.Where(y => y.Monitored).Sum(z => z.TrackCount)));

            Console.WriteLine($"allimported: {allTracksImported}");
            Console.WriteLine($"count: {importResults.Count(c => c.Result == ImportResultType.Imported)}");
            Console.WriteLine($"max: {Math.Max(1, trackedDownload.RemoteAlbum.Albums.Sum(x => x.AlbumReleases.Value.Where(y => y.Monitored).Sum(z => z.TrackCount)))}");

            if (allTracksImported)
            {
                trackedDownload.State = TrackedDownloadState.Imported;
                _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, trackedDownload.RemoteAlbum.Artist.Id));
                return;
            }

            // Double check if all albums were imported by checking the history if at least one
            // file was imported. This will allow the decision engine to reject already imported
            // albums and still mark the download complete when all files are imported.
            if (importResults.Any(c => c.Result == ImportResultType.Imported))
            {
                var historyItems = _historyService.FindByDownloadId(trackedDownload.DownloadItem.DownloadId)
                                   .OrderByDescending(h => h.Date)
                                   .ToList();

                var allTracksImportedInHistory = _trackedDownloadAlreadyImported.IsImported(trackedDownload, historyItems);

                if (allTracksImportedInHistory)
                {
                    trackedDownload.State = TrackedDownloadState.Imported;
                    _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, trackedDownload.RemoteAlbum.Artist.Id));
                    return;
                }
            }

            trackedDownload.State = TrackedDownloadState.ImportPending;

            if (importResults.Empty())
            {
                trackedDownload.Warn("No files found are eligible for import in {0}", outputPath);
            }

            if (importResults.Any(c => c.Result != ImportResultType.Imported))
            {
                trackedDownload.State = TrackedDownloadState.ImportFailed;
                var statusMessages = importResults
                                     .Where(v => v.Result != ImportResultType.Imported)
                                     .Select(v => new TrackedDownloadStatusMessage(Path.GetFileName(v.ImportDecision.Item.Path), v.Errors))
                                     .ToArray();

                trackedDownload.Warn(statusMessages);
                _eventAggregator.PublishEvent(new AlbumImportIncompleteEvent(trackedDownload));
                return;
            }
        }
コード例 #7
0
        public bool VerifyImport(TrackedDownload trackedDownload, List <ImportResult> importResults)
        {
            var allItemsImported = importResults.Where(c => c.Result == ImportResultType.Imported)
                                   .Select(c => c.ImportDecision.Item.Book)
                                   .Count() >= Math.Max(1, trackedDownload.RemoteBook?.Books.Count ?? 1);

            if (allItemsImported)
            {
                _logger.Debug("All books were imported for {0}", trackedDownload.DownloadItem.Title);
                trackedDownload.State = TrackedDownloadState.Imported;

                var importedAuthorId = importResults.Where(x => x.Result == ImportResultType.Imported)
                                       .Select(c => c.ImportDecision.Item.Author.Id)
                                       .MostCommon();
                _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, trackedDownload.RemoteBook?.Author.Id ?? importedAuthorId));
                return(true);
            }

            // Double check if all episodes were imported by checking the history if at least one
            // file was imported. This will allow the decision engine to reject already imported
            // episode files and still mark the download complete when all files are imported.

            // EDGE CASE: This process relies on EpisodeIds being consistent between executions, if a series is updated
            // and an episode is removed, but later comes back with a different ID then Sonarr will treat it as incomplete.
            // Since imports should be relatively fast and these types of data changes are infrequent this should be quite
            // safe, but commenting for future benefit.
            var atLeastOneEpisodeImported = importResults.Any(c => c.Result == ImportResultType.Imported);

            var historyItems = _historyService.FindByDownloadId(trackedDownload.DownloadItem.DownloadId)
                               .OrderByDescending(h => h.Date)
                               .ToList();

            var allEpisodesImportedInHistory = _trackedDownloadAlreadyImported.IsImported(trackedDownload, historyItems);

            if (allEpisodesImportedInHistory)
            {
                // Log different error messages depending on the circumstances, but treat both as fully imported, because that's the reality.
                // The second message shouldn't be logged in most cases, but continued reporting would indicate an ongoing issue.
                if (atLeastOneEpisodeImported)
                {
                    _logger.Debug("All books were imported in history for {0}", trackedDownload.DownloadItem.Title);
                }
                else
                {
                    _logger.Debug()
                    .Message("No books were just imported, but all books were previously imported, possible issue with download history.")
                    .Property("AuthorId", trackedDownload.RemoteBook.Author.Id)
                    .Property("DownloadId", trackedDownload.DownloadItem.DownloadId)
                    .Property("Title", trackedDownload.DownloadItem.Title)
                    .Property("Path", trackedDownload.DownloadItem.OutputPath.ToString())
                    .WriteSentryWarn("DownloadHistoryIncomplete")
                    .Write();
                }

                trackedDownload.State = TrackedDownloadState.Imported;

                var importedAuthorId = historyItems.Where(x => x.EventType == EntityHistoryEventType.BookFileImported)
                                       .Select(x => x.AuthorId)
                                       .MostCommon();
                _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload, trackedDownload.RemoteBook?.Author.Id ?? importedAuthorId));

                return(true);
            }

            _logger.Debug("Not all books have been imported for {0}", trackedDownload.DownloadItem.Title);
            return(false);
        }