Example #1
0
        public virtual Decision IsSatisfiedBy(RemoteBook subject, SearchCriteriaBase searchCriteria)
        {
            if (subject.Release.DownloadProtocol != Indexers.DownloadProtocol.Usenet)
            {
                _logger.Debug("Not checking minimum age requirement for non-usenet report");
                return(Decision.Accept());
            }

            var age        = subject.Release.AgeMinutes;
            var minimumAge = _configService.MinimumAge;
            var ageRounded = Math.Round(age, 1);

            if (minimumAge == 0)
            {
                _logger.Debug("Minimum age is not set.");
                return(Decision.Accept());
            }

            _logger.Debug("Checking if report meets minimum age requirements. {0}", ageRounded);

            if (age < minimumAge)
            {
                _logger.Debug("Only {0} minutes old, minimum age is {1} minutes", ageRounded, minimumAge);
                return(Decision.Reject("Only {0} minutes old, minimum age is {1} minutes", ageRounded, minimumAge));
            }

            _logger.Debug("Release is {0} minutes old, greater than minimum age of {1} minutes", ageRounded, minimumAge);

            return(Decision.Accept());
        }
        public virtual Decision IsSatisfiedBy(RemoteBook subject, SearchCriteriaBase searchCriteria)
        {
            var qualityProfile = subject.Author.QualityProfile.Value;

            foreach (var file in subject.Books.SelectMany(b => b.BookFiles.Value))
            {
                if (file == null)
                {
                    _logger.Debug("File is no longer available, skipping this file.");
                    continue;
                }

                _logger.Debug("Comparing file quality with report. Existing files contain {0}", file.Quality);

                if (!_upgradableSpecification.IsUpgradeAllowed(qualityProfile,
                                                               file.Quality,
                                                               subject.ParsedBookInfo.Quality))
                {
                    _logger.Debug("Upgrading is not allowed by the quality profile");

                    return(Decision.Reject("Existing files and the Quality profile does not allow upgrades"));
                }
            }

            return(Decision.Accept());
        }
Example #3
0
        protected override string AddFromTorrentFile(RemoteBook remoteBook, string hash, string filename, byte[] fileContent)
        {
            var actualHash = _proxy.AddTorrentFromFile(filename, fileContent, Settings);

            if (actualHash.IsNullOrWhiteSpace())
            {
                throw new DownloadClientException("Deluge failed to add torrent " + filename);
            }

            _proxy.SetTorrentSeedingConfiguration(actualHash, remoteBook.SeedConfiguration, Settings);

            if (Settings.MusicCategory.IsNotNullOrWhiteSpace())
            {
                _proxy.SetTorrentLabel(actualHash, Settings.MusicCategory, Settings);
            }

            var isRecentBook = remoteBook.IsRecentBook();

            if ((isRecentBook && Settings.RecentTvPriority == (int)DelugePriority.First) ||
                (!isRecentBook && Settings.OlderTvPriority == (int)DelugePriority.First))
            {
                _proxy.MoveTorrentToTopInQueue(actualHash, Settings);
            }

            return(actualHash.ToUpper());
        }
 public void Setup()
 {
     _remoteBook = new RemoteBook()
     {
         Release = new ReleaseInfo()
     };
 }
Example #5
0
        public void Setup()
        {
            var completed = Builder <DownloadClientItem> .CreateNew()
                            .With(h => h.Status     = DownloadItemStatus.Completed)
                            .With(h => h.OutputPath = new OsPath(@"C:\DropFolder\MyDownload".AsOsAgnostic()))
                            .With(h => h.Title      = "Drone.DroneTheBook.FLAC")
                            .Build();

            _grabHistory = Builder <EntityHistory> .CreateListOfSize(2).BuildList();

            var remoteBook = new RemoteBook
            {
                Author = new Author(),
                Books  = new List <Book> {
                    new Book {
                        Id = 1
                    }
                }
            };

            _trackedDownload = Builder <TrackedDownload> .CreateNew()
                               .With(c => c.State        = TrackedDownloadState.Downloading)
                               .With(c => c.DownloadItem = completed)
                               .With(c => c.RemoteBook   = remoteBook)
                               .Build();

            Mocker.GetMock <IHistoryService>()
            .Setup(s => s.Find(_trackedDownload.DownloadItem.DownloadId, EntityHistoryEventType.Grabbed))
            .Returns(_grabHistory);
        }
Example #6
0
        public virtual Decision IsSatisfiedBy(RemoteBook subject, SearchCriteriaBase searchCriteria)
        {
            var qualityProfile = subject.Author.QualityProfile.Value;

            foreach (var file in subject.Books.SelectMany(b => b.BookFiles.Value))
            {
                // Get a distinct list of all current track qualities for a given book
                var currentQualities = new List <QualityModel> {
                    file.Quality
                };

                _logger.Debug("Comparing file quality with report. Existing files contain {0}", currentQualities.ConcatToString());

                if (!_upgradableSpecification.CutoffNotMet(qualityProfile,
                                                           currentQualities,
                                                           _preferredWordServiceCalculator.Calculate(subject.Author, file.GetSceneOrFileName()),
                                                           subject.ParsedBookInfo.Quality,
                                                           subject.PreferredWordScore))
                {
                    _logger.Debug("Cutoff already met by existing files, rejecting.");

                    var qualityCutoffIndex = qualityProfile.GetIndex(qualityProfile.Cutoff);
                    var qualityCutoff      = qualityProfile.Items[qualityCutoffIndex.Index];

                    return(Decision.Reject("Existing files meets cutoff: {0}", qualityCutoff));
                }
            }

            return(Decision.Accept());
        }
Example #7
0
        protected override string AddFromMagnetLink(RemoteBook remoteBook, string hash, string magnetLink)
        {
            if (!Proxy.GetConfig(Settings).DhtEnabled&& !magnetLink.Contains("&tr="))
            {
                throw new NotSupportedException("Magnet Links without trackers not supported if DHT is disabled");
            }

            Proxy.AddTorrentFromUrl(magnetLink, Settings);

            var isRecentBook = remoteBook.IsRecentBook();

            if ((isRecentBook && Settings.RecentTvPriority == (int)QBittorrentPriority.First) ||
                (!isRecentBook && Settings.OlderTvPriority == (int)QBittorrentPriority.First))
            {
                Proxy.MoveTorrentToTopInQueue(hash.ToLower(), Settings);
            }

            SetInitialState(hash.ToLower());

            if (remoteBook.SeedConfiguration != null && (remoteBook.SeedConfiguration.Ratio.HasValue || remoteBook.SeedConfiguration.SeedTime.HasValue))
            {
                Proxy.SetTorrentSeedingConfiguration(hash.ToLower(), remoteBook.SeedConfiguration, Settings);
            }

            return(hash);
        }
        private Rejection EvaluateSpec(IDecisionEngineSpecification spec, RemoteBook remoteBook, SearchCriteriaBase searchCriteriaBase = null)
        {
            try
            {
                var result = spec.IsSatisfiedBy(remoteBook, searchCriteriaBase);

                if (!result.Accepted)
                {
                    return(new Rejection(result.Reason, spec.Type));
                }
            }
            catch (NotImplementedException)
            {
                _logger.Trace("Spec " + spec.GetType().Name + " not implemented.");
            }
            catch (Exception e)
            {
                e.Data.Add("report", remoteBook.Release.ToJson());
                e.Data.Add("parsed", remoteBook.ParsedBookInfo.ToJson());
                _logger.Error(e, "Couldn't evaluate decision on {0}", remoteBook.Release.Title);
                return(new Rejection($"{spec.GetType().Name}: {e.Message}"));
            }

            return(null);
        }
        public virtual Decision IsSatisfiedBy(RemoteBook subject, SearchCriteriaBase searchCriteria)
        {
            if (!_configService.AutoUnmonitorPreviouslyDownloadedBooks)
            {
                return(Decision.Accept());
            }

            if (searchCriteria != null)
            {
                _logger.Debug("Skipping deleted bookfile check during search");
                return(Decision.Accept());
            }

            var missingTrackFiles = subject.Books
                                    .SelectMany(v => _bookService.GetFilesByBook(v.Id))
                                    .DistinctBy(v => v.Id)
                                    .Where(v => IsTrackFileMissing(subject.Author, v))
                                    .ToArray();

            if (missingTrackFiles.Any())
            {
                foreach (var missingTrackFile in missingTrackFiles)
                {
                    _logger.Trace("Book file {0} is missing from disk.", missingTrackFile.Path);
                }

                _logger.Debug("Files for this book exist in the database but not on disk, will be unmonitored on next diskscan. skipping.");
                return(Decision.Reject("Author is not monitored"));
            }

            return(Decision.Accept());
        }
Example #10
0
        public void Setup()
        {
            var author = Builder <Author> .CreateNew().With(s => s.Id = 1234).Build();

            _remoteBook = new RemoteBook
            {
                ParsedBookInfo = new ParsedBookInfo
                {
                    Discography = true
                },
                Books = Builder <Book> .CreateListOfSize(3)
                        .All()
                        .With(e => e.ReleaseDate = DateTime.UtcNow.AddDays(-8))
                        .With(s => s.AuthorId    = author.Id)
                        .BuildList(),
                Author  = author,
                Release = new ReleaseInfo
                {
                    Title = "Author.Discography.1978.2005.FLAC-RlsGrp"
                }
            };

            Mocker.GetMock <IBookService>().Setup(s => s.BooksBetweenDates(It.IsAny <DateTime>(), It.IsAny <DateTime>(), false))
            .Returns(new List <Book>());
        }
Example #11
0
        private RemoteBook GivenRemoteAlbum(List <Book> albums, QualityModel quality, int age = 0, long size = 0, DownloadProtocol downloadProtocol = DownloadProtocol.Usenet, int indexerPriority = 25)
        {
            var remoteBook = new RemoteBook();

            remoteBook.ParsedBookInfo         = new ParsedBookInfo();
            remoteBook.ParsedBookInfo.Quality = quality;

            remoteBook.Books = new List <Book>();
            remoteBook.Books.AddRange(albums);

            remoteBook.Release                  = new ReleaseInfo();
            remoteBook.Release.PublishDate      = DateTime.Now.AddDays(-age);
            remoteBook.Release.Size             = size;
            remoteBook.Release.DownloadProtocol = downloadProtocol;
            remoteBook.Release.IndexerPriority  = indexerPriority;

            remoteBook.Author = Builder <Author> .CreateNew()
                                .With(e => e.QualityProfile = new QualityProfile
            {
                Items = Qualities.QualityFixture.GetDefaultQualities()
            }).Build();

            remoteBook.DownloadAllowed = true;

            return(remoteBook);
        }
Example #12
0
        public void Setup()
        {
            _author = Builder <Author> .CreateNew().With(s => s.Id = 1).Build();

            _book1 = Builder <Book> .CreateNew().With(s => s.ReleaseDate = DateTime.Today).Build();

            _book2 = Builder <Book> .CreateNew().With(s => s.ReleaseDate = DateTime.Today).Build();

            _remoteBook = new RemoteBook
            {
                Author = _author,
                Books  = new List <Book> {
                    _book1
                },
                Release = new TorrentInfo
                {
                    IndexerId   = 1,
                    Title       = "Author - Book [FLAC-RlsGrp]",
                    PublishDate = DateTime.Today
                }
            };

            _indexerDefinition = new IndexerDefinition
            {
                Settings = new TorrentRssIndexerSettings {
                    EarlyReleaseLimit = 5
                }
            };

            Mocker.GetMock <IIndexerFactory>()
            .Setup(v => v.Get(1))
            .Returns(_indexerDefinition);
        }
Example #13
0
        private void RemoveGrabbed(RemoteBook remoteBook)
        {
            var pendingReleases = GetPendingReleases(remoteBook.Author.Id);
            var bookIds         = remoteBook.Books.Select(e => e.Id);

            var existingReports = pendingReleases.Where(r => r.RemoteBook.Books.Select(e => e.Id)
                                                        .Intersect(bookIds)
                                                        .Any())
                                  .ToList();

            if (existingReports.Empty())
            {
                return;
            }

            var profile = remoteBook.Author.QualityProfile.Value;

            foreach (var existingReport in existingReports)
            {
                var compare = new QualityModelComparer(profile).Compare(remoteBook.ParsedBookInfo.Quality,
                                                                        existingReport.RemoteBook.ParsedBookInfo.Quality);

                //Only remove lower/equal quality pending releases
                //It is safer to retry these releases on the next round than remove it and try to re-add it (if its still in the feed)
                if (compare >= 0)
                {
                    _logger.Debug("Removing previously pending release, as it was grabbed.");
                    Delete(existingReport);
                }
            }
        }
        public void Setup()
        {
            _artist = Builder <Author> .CreateNew().With(s => s.Id = 1).Build();

            _remoteBook = new RemoteBook
            {
                Author  = _artist,
                Release = new TorrentInfo
                {
                    IndexerId = 1,
                    Title     = "Artist - Album [FLAC-RlsGrp]",
                    Seeders   = 0
                }
            };

            _indexerDefinition = new IndexerDefinition
            {
                Settings = new TorrentRssIndexerSettings {
                    MinimumSeeders = 5
                }
            };

            Mocker.GetMock <IIndexerFactory>()
            .Setup(v => v.Get(1))
            .Returns(_indexerDefinition);
        }
        public virtual Decision IsSatisfiedBy(RemoteBook remoteBook, SearchCriteriaBase searchCriteria)
        {
            if (searchCriteria == null)
            {
                return(Decision.Accept());
            }

            var singleBookSpec = searchCriteria as BookSearchCriteria;

            if (singleBookSpec == null)
            {
                return(Decision.Accept());
            }

            if (Parser.Parser.CleanAuthorName(singleBookSpec.BookTitle) != Parser.Parser.CleanAuthorName(remoteBook.ParsedBookInfo.BookTitle))
            {
                _logger.Debug("Book does not match searched book title, skipping.");
                return(Decision.Reject("Wrong book"));
            }

            if (!remoteBook.ParsedBookInfo.BookTitle.Any())
            {
                _logger.Debug("Full discography result during single book search, skipping.");
                return(Decision.Reject("Full author pack"));
            }

            return(Decision.Accept());
        }
Example #16
0
        protected override string AddFromTorrentFile(RemoteBook remoteBook, string hash, string filename, byte[] fileContent)
        {
            Proxy.AddTorrentFromFile(filename, fileContent, Settings);

            try
            {
                var isRecentBook = remoteBook.IsRecentBook();

                if ((isRecentBook && Settings.RecentTvPriority == (int)QBittorrentPriority.First) ||
                    (!isRecentBook && Settings.OlderTvPriority == (int)QBittorrentPriority.First))
                {
                    Proxy.MoveTorrentToTopInQueue(hash.ToLower(), Settings);
                }
            }
            catch (Exception ex)
            {
                _logger.Warn(ex, "Failed to set the torrent priority for {0}.", filename);
            }

            SetInitialState(hash.ToLower());

            if (remoteBook.SeedConfiguration != null && (remoteBook.SeedConfiguration.Ratio.HasValue || remoteBook.SeedConfiguration.SeedTime.HasValue))
            {
                Proxy.SetTorrentSeedingConfiguration(hash.ToLower(), remoteBook.SeedConfiguration, Settings);
            }

            return(hash);
        }
Example #17
0
        private string DownloadFromMagnetUrl(RemoteBook remoteBook, string magnetUrl)
        {
            string hash       = null;
            string actualHash = null;

            try
            {
                hash = MagnetLink.Parse(magnetUrl).InfoHash.ToHex();
            }
            catch (FormatException ex)
            {
                _logger.Error(ex, "Failed to parse magnetlink for release '{0}': '{1}'", remoteBook.Release.Title, magnetUrl);

                return(null);
            }

            if (hash != null)
            {
                actualHash = AddFromMagnetLink(remoteBook, hash, magnetUrl);
            }

            if (actualHash.IsNotNullOrWhiteSpace() && hash != actualHash)
            {
                _logger.Debug(
                    "{0} did not return the expected InfoHash for '{1}', Readarr could potentially lose track of the download in progress.",
                    Definition.Implementation,
                    remoteBook.Release.DownloadUrl);
            }

            return(actualHash);
        }
        public virtual Decision IsSatisfiedBy(RemoteBook subject, SearchCriteriaBase searchCriteria)
        {
            foreach (var file in subject.Books.SelectMany(c => c.BookFiles.Value))
            {
                if (file == null)
                {
                    _logger.Debug("File is no longer available, skipping this file.");
                    continue;
                }

                _logger.Debug("Comparing file quality and language with report. Existing file is {0}", file.Quality);

                if (!_upgradableSpecification.IsUpgradable(subject.Author.QualityProfile,
                                                           new List <QualityModel> {
                    file.Quality
                },
                                                           _preferredWordServiceCalculator.Calculate(subject.Author, file.GetSceneOrFileName()),
                                                           subject.ParsedBookInfo.Quality,
                                                           subject.PreferredWordScore))
                {
                    return(Decision.Reject("Existing file on disk is of equal or higher preference: {0}", file.Quality));
                }
            }

            return(Decision.Accept());
        }
Example #19
0
        public void Setup()
        {
            _downloadClients = new List <IDownloadClient>();

            Mocker.GetMock <IProvideDownloadClient>()
            .Setup(v => v.GetDownloadClients())
            .Returns(_downloadClients);

            Mocker.GetMock <IProvideDownloadClient>()
            .Setup(v => v.GetDownloadClient(It.IsAny <DownloadProtocol>()))
            .Returns <DownloadProtocol>(v => _downloadClients.FirstOrDefault(d => d.Protocol == v));

            var episodes = Builder <Book> .CreateListOfSize(2)
                           .TheFirst(1).With(s => s.Id = 12)
                           .TheNext(1).With(s => s.Id  = 99)
                           .All().With(s => s.AuthorId = 5)
                           .Build().ToList();

            var releaseInfo = Builder <ReleaseInfo> .CreateNew()
                              .With(v => v.DownloadProtocol = DownloadProtocol.Usenet)
                              .With(v => v.DownloadUrl      = "http://test.site/download1.ext")
                              .Build();

            _parseResult = Builder <RemoteBook> .CreateNew()
                           .With(c => c.Author  = Builder <Author> .CreateNew().Build())
                           .With(c => c.Release = releaseInfo)
                           .With(c => c.Books   = episodes)
                           .Build();
        }
Example #20
0
        public Decision IsSatisfiedBy(RemoteBook subject, SearchCriteriaBase searchCriteria)
        {
            var size        = subject.Release.Size;
            var maximumSize = _configService.MaximumSize.Megabytes();

            if (maximumSize == 0)
            {
                _logger.Debug("Maximum size is not set.");
                return(Decision.Accept());
            }

            if (subject.Release.Size == 0)
            {
                _logger.Debug("Release has unknown size, skipping size check.");
                return(Decision.Accept());
            }

            _logger.Debug("Checking if release meets maximum size requirements. {0}", size.SizeSuffix());

            if (size > maximumSize)
            {
                var message = $"{size.SizeSuffix()} is too big, maximum size is {maximumSize.SizeSuffix()} (Settings->Indexers->Maximum Size)";

                _logger.Debug(message);
                return(Decision.Reject(message));
            }

            return(Decision.Accept());
        }
Example #21
0
        public void Setup()
        {
            _monitoredAlbumSpecification = Mocker.Resolve <MonitoredBookSpecification>();

            _fakeArtist = Builder <Author> .CreateNew()
                          .With(c => c.Monitored = true)
                          .Build();

            _firstAlbum = new Book {
                Monitored = true
            };
            _secondAlbum = new Book {
                Monitored = true
            };

            var singleAlbumList = new List <Book> {
                _firstAlbum
            };
            var doubleAlbumList = new List <Book> {
                _firstAlbum, _secondAlbum
            };

            _parseResultMulti = new RemoteBook
            {
                Author = _fakeArtist,
                Books  = doubleAlbumList
            };

            _parseResultSingle = new RemoteBook
            {
                Author = _fakeArtist,
                Books  = singleAlbumList
            };
        }
        public void Setup()
        {
            _pneumaticFolder = @"d:\nzb\pneumatic\".AsOsAgnostic();

            _nzbPath    = Path.Combine(_pneumaticFolder, _title + ".nzb").AsOsAgnostic();
            _strmFolder = @"d:\unsorted tv\".AsOsAgnostic();

            _remoteBook                     = new RemoteBook();
            _remoteBook.Release             = new ReleaseInfo();
            _remoteBook.Release.Title       = _title;
            _remoteBook.Release.DownloadUrl = _nzbUrl;

            _remoteBook.ParsedBookInfo = new ParsedBookInfo();

            _downloadClientItem = Builder <DownloadClientItem>
                                  .CreateNew().With(d => d.DownloadId = "_Droned.S01E01.Pilot.1080p.WEB-DL-DRONE_0")
                                  .Build();

            Subject.Definition          = new DownloadClientDefinition();
            Subject.Definition.Settings = new PneumaticSettings
            {
                NzbFolder  = _pneumaticFolder,
                StrmFolder = _strmFolder
            };
        }
        public virtual Decision IsSatisfiedBy(RemoteBook subject, SearchCriteriaBase searchCriteria)
        {
            var qualityProfile = subject.Author.QualityProfile.Value;

            foreach (var file in subject.Books.SelectMany(b => b.BookFiles.Value))
            {
                if (file == null)
                {
                    _logger.Debug("File is no longer available, skipping this file.");
                    continue;
                }

                // Get a distinct list of all current track qualities for a given book
                var currentQualities = new List <QualityModel> {
                    file.Quality
                };

                _logger.Debug("Comparing file quality with report. Existing files contain {0}", currentQualities.ConcatToString());

                if (!_upgradableSpecification.IsUpgradeAllowed(qualityProfile,
                                                               currentQualities,
                                                               subject.ParsedBookInfo.Quality))
                {
                    _logger.Debug("Upgrading is not allowed by the quality profile");

                    return(Decision.Reject("Existing files and the Quality profile does not allow upgrades"));
                }
            }

            return(Decision.Accept());
        }
        public void Setup()
        {
            Mocker.Resolve <UpgradableSpecification>();

            _firstFile = new BookFile {
                Quality = new QualityModel(Quality.FLAC, new Revision(version: 2)), DateAdded = DateTime.Now
            };
            _secondFile = new BookFile {
                Quality = new QualityModel(Quality.FLAC, new Revision(version: 2)), DateAdded = DateTime.Now
            };

            var singleBookList = new List <Book> {
                new Book {
                    BookFiles = new List <BookFile>()
                }
            };
            var doubleBookList = new List <Book> {
                new Book {
                    BookFiles = new List <BookFile>()
                }, new Book {
                    BookFiles = new List <BookFile>()
                }, new Book {
                    BookFiles = new List <BookFile>()
                }
            };

            var fakeAuthor = Builder <Author> .CreateNew()
                             .With(c => c.QualityProfile = new QualityProfile
            {
                UpgradeAllowed = true,
                Cutoff         = Quality.MP3_320.Id,
                Items          = Qualities.QualityFixture.GetDefaultQualities()
            })
                             .Build();

            Mocker.GetMock <IMediaFileService>()
            .Setup(c => c.GetFilesByBook(It.IsAny <int>()))
            .Returns(new List <BookFile> {
                _firstFile, _secondFile
            });

            _parseResultMulti = new RemoteBook
            {
                Author         = fakeAuthor,
                ParsedBookInfo = new ParsedBookInfo {
                    Quality = new QualityModel(Quality.MP3_320, new Revision(version: 2))
                },
                Books = doubleBookList
            };

            _parseResultSingle = new RemoteBook
            {
                Author         = fakeAuthor,
                ParsedBookInfo = new ParsedBookInfo {
                    Quality = new QualityModel(Quality.MP3_320, new Revision(version: 2))
                },
                Books = singleBookList
            };
        }
Example #25
0
        public Decision IsSatisfiedBy(RemoteBook subject, SearchCriteriaBase searchCriteria)
        {
            var queue        = _queueService.GetQueue();
            var matchingBook = queue.Where(q => q.RemoteBook?.Author != null &&
                                           q.RemoteBook.Author.Id == subject.Author.Id &&
                                           q.RemoteBook.Books.Select(e => e.Id).Intersect(subject.Books.Select(e => e.Id)).Any())
                               .ToList();

            foreach (var queueItem in matchingBook)
            {
                var remoteBook     = queueItem.RemoteBook;
                var qualityProfile = subject.Author.QualityProfile.Value;

                // To avoid a race make sure it's not FailedPending (failed awaiting removal/search).
                // Failed items (already searching for a replacement) won't be part of the queue since
                // it's a copy, of the tracked download, not a reference.
                if (queueItem.TrackedDownloadState == TrackedDownloadState.DownloadFailedPending)
                {
                    continue;
                }

                _logger.Debug("Checking if existing release in queue meets cutoff. Queued quality is: {0}", remoteBook.ParsedBookInfo.Quality);

                var queuedItemPreferredWordScore = _preferredWordServiceCalculator.Calculate(subject.Author, queueItem.Title, subject.Release?.IndexerId ?? 0);

                if (!_upgradableSpecification.CutoffNotMet(qualityProfile,
                                                           new List <QualityModel> {
                    remoteBook.ParsedBookInfo.Quality
                },
                                                           queuedItemPreferredWordScore,
                                                           subject.ParsedBookInfo.Quality,
                                                           subject.PreferredWordScore))
                {
                    return(Decision.Reject("Release in queue already meets cutoff: {0}", remoteBook.ParsedBookInfo.Quality));
                }

                _logger.Debug("Checking if release is higher quality than queued release. Queued: {0}", remoteBook.ParsedBookInfo.Quality);

                if (!_upgradableSpecification.IsUpgradable(qualityProfile,
                                                           remoteBook.ParsedBookInfo.Quality,
                                                           queuedItemPreferredWordScore,
                                                           subject.ParsedBookInfo.Quality,
                                                           subject.PreferredWordScore))
                {
                    return(Decision.Reject("Release in queue is of equal or higher preference: {0}", remoteBook.ParsedBookInfo.Quality));
                }

                _logger.Debug("Checking if profiles allow upgrading. Queued: {0}", remoteBook.ParsedBookInfo.Quality);

                if (!_upgradableSpecification.IsUpgradeAllowed(qualityProfile,
                                                               remoteBook.ParsedBookInfo.Quality,
                                                               subject.ParsedBookInfo.Quality))
                {
                    return(Decision.Reject("Another release is queued and the Quality profile does not allow upgrades"));
                }
            }

            return(Decision.Accept());
        }
Example #26
0
        private int GetDelay(RemoteBook remoteBook)
        {
            var delayProfile = _delayProfileService.AllForTags(remoteBook.Author.Tags).OrderBy(d => d.Order).First();
            var delay        = delayProfile.GetProtocolDelay(remoteBook.Release.DownloadProtocol);
            var minimumAge   = _configService.MinimumAge;

            return(new[] { delay, minimumAge }.Max());
        }
Example #27
0
 public WebhookRelease(QualityModel quality, RemoteBook remoteBook)
 {
     Quality        = quality.Quality.Name;
     QualityVersion = quality.Revision.Version;
     ReleaseGroup   = remoteBook.ParsedBookInfo.ReleaseGroup;
     ReleaseTitle   = remoteBook.Release.Title;
     Indexer        = remoteBook.Release.Indexer;
     Size           = remoteBook.Release.Size;
 }
Example #28
0
        public void should_unmap_tracked_download_if_album_deleted()
        {
            GivenDownloadHistory();

            var remoteBook = new RemoteBook
            {
                Author = new Author()
                {
                    Id = 5
                },
                Books = new List <Book> {
                    new Book {
                        Id = 4
                    }
                },
                ParsedBookInfo = new ParsedBookInfo()
                {
                    BookTitle  = "Audio Album",
                    AuthorName = "Audio Artist"
                }
            };

            Mocker.GetMock <IParsingService>()
            .Setup(s => s.Map(It.Is <ParsedBookInfo>(i => i.BookTitle == "Audio Album" && i.AuthorName == "Audio Artist"), It.IsAny <int>(), It.IsAny <IEnumerable <int> >()))
            .Returns(remoteBook);

            var client = new DownloadClientDefinition()
            {
                Id       = 1,
                Protocol = DownloadProtocol.Torrent
            };

            var item = new DownloadClientItem()
            {
                Title      = "Audio Artist - Audio Album [2018 - FLAC]",
                DownloadId = "35238",
            };

            // get a tracked download in place
            var trackedDownload = Subject.TrackDownload(client, item);

            Subject.GetTrackedDownloads().Should().HaveCount(1);

            // simulate deletion - album no longer maps
            Mocker.GetMock <IParsingService>()
            .Setup(s => s.Map(It.Is <ParsedBookInfo>(i => i.BookTitle == "Audio Album" && i.AuthorName == "Audio Artist"), It.IsAny <int>(), It.IsAny <IEnumerable <int> >()))
            .Returns(default(RemoteBook));

            // handle deletion event
            Subject.Handle(new BookDeletedEvent(remoteBook.Books.First(), false, false));

            // verify download has null remote album
            var trackedDownloads = Subject.GetTrackedDownloads();

            trackedDownloads.Should().HaveCount(1);
            trackedDownloads.First().RemoteBook.Should().BeNull();
        }
        public void Setup()
        {
            Mocker.Resolve <UpgradableSpecification>();
            _upgradeHistory = Mocker.Resolve <HistorySpecification>();

            var singleBookList = new List <Book> {
                new Book {
                    Id = FIRST_ALBUM_ID
                }
            };
            var doubleBookList = new List <Book>
            {
                new Book {
                    Id = FIRST_ALBUM_ID
                },
                new Book {
                    Id = SECOND_ALBUM_ID
                },
                new Book {
                    Id = 3
                }
            };

            _fakeAuthor = Builder <Author> .CreateNew()
                          .With(c => c.QualityProfile = new QualityProfile
            {
                UpgradeAllowed = true,
                Cutoff         = Quality.MP3.Id,
                Items          = Qualities.QualityFixture.GetDefaultQualities()
            })
                          .Build();

            _parseResultMulti = new RemoteBook
            {
                Author         = _fakeAuthor,
                ParsedBookInfo = new ParsedBookInfo {
                    Quality = new QualityModel(Quality.MP3, new Revision(version: 2))
                },
                Books = doubleBookList
            };

            _parseResultSingle = new RemoteBook
            {
                Author         = _fakeAuthor,
                ParsedBookInfo = new ParsedBookInfo {
                    Quality = new QualityModel(Quality.MP3, new Revision(version: 2))
                },
                Books = singleBookList
            };

            _upgradableQuality    = new QualityModel(Quality.MP3, new Revision(version: 1));
            _notupgradableQuality = new QualityModel(Quality.MP3, new Revision(version: 2));

            Mocker.GetMock <IConfigService>()
            .SetupGet(s => s.EnableCompletedDownloadHandling)
            .Returns(true);
        }
Example #30
0
        protected override string AddFromTorrentFile(RemoteBook remoteBook, string hash, string filename, byte[] fileContent)
        {
            var setShareLimits       = remoteBook.SeedConfiguration != null && (remoteBook.SeedConfiguration.Ratio.HasValue || remoteBook.SeedConfiguration.SeedTime.HasValue);
            var addHasSetShareLimits = setShareLimits && ProxyApiVersion >= new Version(2, 8, 1);
            var isRecentBook         = remoteBook.IsRecentBook();
            var moveToTop            = (isRecentBook && Settings.RecentTvPriority == (int)QBittorrentPriority.First) || (!isRecentBook && Settings.OlderTvPriority == (int)QBittorrentPriority.First);
            var forceStart           = (QBittorrentState)Settings.InitialState == QBittorrentState.ForceStart;

            Proxy.AddTorrentFromFile(filename, fileContent, addHasSetShareLimits ? remoteBook.SeedConfiguration : null, Settings);

            if ((!addHasSetShareLimits && setShareLimits) || moveToTop || forceStart)
            {
                if (!WaitForTorrent(hash))
                {
                    return(hash);
                }

                if (!addHasSetShareLimits && setShareLimits)
                {
                    try
                    {
                        Proxy.SetTorrentSeedingConfiguration(hash.ToLower(), remoteBook.SeedConfiguration, Settings);
                    }
                    catch (Exception ex)
                    {
                        _logger.Warn(ex, "Failed to set the torrent seed criteria for {0}.", hash);
                    }
                }

                if (moveToTop)
                {
                    try
                    {
                        Proxy.MoveTorrentToTopInQueue(hash.ToLower(), Settings);
                    }
                    catch (Exception ex)
                    {
                        _logger.Warn(ex, "Failed to set the torrent priority for {0}.", hash);
                    }
                }

                if (forceStart)
                {
                    try
                    {
                        Proxy.SetForceStart(hash.ToLower(), true, Settings);
                    }
                    catch (Exception ex)
                    {
                        _logger.Warn(ex, "Failed to set ForceStart for {0}.", hash);
                    }
                }
            }

            return(hash);
        }