public TrackedDownload TrackDownload(DownloadClientDefinition downloadClient, DownloadClientItem downloadItem) { var existingItem = Find(downloadItem.DownloadId); if (existingItem != null && existingItem.State != TrackedDownloadStage.Downloading) { existingItem.DownloadItem = downloadItem; return existingItem; } var trackedDownload = new TrackedDownload { DownloadClient = downloadClient.Id, DownloadItem = downloadItem, Protocol = downloadClient.Protocol }; try { var parsedEpisodeInfo = Parser.Parser.ParseTitle(trackedDownload.DownloadItem.Title); var historyItems = _historyService.FindByDownloadId(downloadItem.DownloadId); if (parsedEpisodeInfo != null) { trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0); } if (historyItems.Any()) { var firstHistoryItem = historyItems.OrderByDescending(h => h.Date).First(); trackedDownload.State = GetStateFromHistory(firstHistoryItem.EventType); if (parsedEpisodeInfo == null || trackedDownload.RemoteEpisode == null || trackedDownload.RemoteEpisode.Series == null || trackedDownload.RemoteEpisode.Episodes.Empty()) { parsedEpisodeInfo = Parser.Parser.ParseTitle(firstHistoryItem.SourceTitle); if (parsedEpisodeInfo != null) { trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, firstHistoryItem.SeriesId, historyItems.Where(v => v.EventType == HistoryEventType.Grabbed).Select(h => h.EpisodeId).Distinct()); } } } if (trackedDownload.RemoteEpisode == null) { return null; } } catch (Exception e) { _logger.DebugException("Failed to find episode for " + downloadItem.Title, e); return null; } _cache.Set(trackedDownload.DownloadItem.DownloadId, trackedDownload); return trackedDownload; }
public TrackedDownload TrackDownload(DownloadClientDefinition downloadClient, DownloadClientItem downloadItem) { var existingItem = Find(downloadItem.DownloadId); if (existingItem != null && existingItem.State != TrackedDownloadStage.Downloading) { existingItem.DownloadItem = downloadItem; return existingItem; } var trackedDownload = new TrackedDownload { DownloadClient = downloadClient.Id, DownloadItem = downloadItem, Protocol = downloadClient.Protocol }; try { var parsedEpisodeInfo = Parser.Parser.ParseTitle(trackedDownload.DownloadItem.Title); if (parsedEpisodeInfo == null) return null; var remoteEpisode = _parsingService.Map(parsedEpisodeInfo); if (remoteEpisode.Series == null || !remoteEpisode.Episodes.Any()) { var historyItems = _historyService.FindByDownloadId(downloadItem.DownloadId); if (historyItems.Empty()) { return null; } 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; } var historyItem = _historyService.MostRecentForDownloadId(downloadItem.DownloadId); if (historyItem != null) { trackedDownload.State = GetStateFromHistory(historyItem.EventType); } _cache.Set(trackedDownload.DownloadItem.DownloadId, trackedDownload); return trackedDownload; }
private List <ImportResult> ProcessFolder(IDirectoryInfo directoryInfo, ImportMode importMode, Author author, DownloadClientItem downloadClientItem) { if (_authorService.AuthorPathExists(directoryInfo.FullName)) { _logger.Warn("Unable to process folder that is mapped to an existing author"); return(new List <ImportResult>()); } var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name); var folderInfo = Parser.Parser.ParseBookTitle(directoryInfo.Name); var trackInfo = new ParsedTrackInfo { }; if (folderInfo != null) { _logger.Debug("{0} folder quality: {1}", cleanedUpName, folderInfo.Quality); trackInfo = new ParsedTrackInfo { BookTitle = folderInfo.BookTitle, Authors = new List <string> { folderInfo.AuthorName }, Quality = folderInfo.Quality, ReleaseGroup = folderInfo.ReleaseGroup, ReleaseHash = folderInfo.ReleaseHash, }; } else { trackInfo = null; } var audioFiles = _diskScanService.FilterFiles(directoryInfo.FullName, _diskScanService.GetBookFiles(directoryInfo.FullName)); if (downloadClientItem == null) { foreach (var audioFile in audioFiles) { if (_diskProvider.IsFileLocked(audioFile.FullName)) { return(new List <ImportResult> { FileIsLockedResult(audioFile.FullName) }); } } } var idOverrides = new IdentificationOverrides { Author = author }; var idInfo = new ImportDecisionMakerInfo { DownloadClientItem = downloadClientItem, ParsedTrackInfo = trackInfo }; var idConfig = new ImportDecisionMakerConfig { Filter = FilterFilesType.None, NewDownload = true, SingleRelease = false, IncludeExisting = false, AddNewAuthors = false }; var decisions = _importDecisionMaker.GetImportDecisions(audioFiles, idOverrides, idInfo, idConfig); var importResults = _importApprovedTracks.Import(decisions, true, downloadClientItem, importMode); if (importMode == ImportMode.Auto) { importMode = (downloadClientItem == null || downloadClientItem.CanMoveFiles) ? ImportMode.Move : ImportMode.Copy; } if (importMode == ImportMode.Move && importResults.Any(i => i.Result == ImportResultType.Imported) && ShouldDeleteFolder(directoryInfo)) { _logger.Debug("Deleting folder after importing valid files"); _diskProvider.DeleteFolder(directoryInfo.FullName, true); } return(importResults); }
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.CanMoveFiles; 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); } _eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile, oldFiles, newDownload, downloadClientItem)); } catch (RootFolderNotFoundException e) { _logger.Warn(e, "Couldn't import episode " + localEpisode); importResults.Add(new ImportResult(importDecision, "Failed to import episode, Root folder missing.")); } catch (DestinationAlreadyExistsException e) { _logger.Warn(e, "Couldn't import episode " + localEpisode); importResults.Add(new ImportResult(importDecision, "Failed to import episode, Destination already exists.")); } 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); }
public override IEnumerable <DownloadClientItem> GetItems() { var version = Proxy.GetApiVersion(Settings); var config = Proxy.GetConfig(Settings); var torrents = Proxy.GetTorrents(Settings); var queueItems = new List <DownloadClientItem>(); foreach (var torrent in torrents) { var item = new DownloadClientItem { DownloadId = torrent.Hash.ToUpper(), Category = torrent.Category.IsNotNullOrWhiteSpace() ? torrent.Category : torrent.Label, Title = torrent.Name, TotalSize = torrent.Size, DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this), RemainingSize = (long)(torrent.Size * (1.0 - torrent.Progress)), RemainingTime = GetRemainingTime(torrent), SeedRatio = torrent.Ratio }; // Avoid removing torrents that haven't reached the global max ratio. // Removal also requires the torrent to be paused, in case a higher max ratio was set on the torrent itself (which is not exposed by the api). item.CanMoveFiles = item.CanBeRemoved = torrent.State == "pausedUP" && HasReachedSeedLimit(torrent, config); switch (torrent.State) { case "error": // some error occurred, applies to paused torrents, warning so failed download handling isn't triggered item.Status = DownloadItemStatus.Warning; item.Message = "qBittorrent is reporting an error"; break; case "pausedDL": // torrent is paused and has NOT finished downloading item.Status = DownloadItemStatus.Paused; break; case "queuedDL": // queuing is enabled and torrent is queued for download case "checkingDL": // same as checkingUP, but torrent has NOT finished downloading case "checkingUP": // torrent has finished downloading and is being checked. Set when `recheck torrent on completion` is enabled. In the event the check fails we shouldn't treat it as completed. item.Status = DownloadItemStatus.Queued; break; case "pausedUP": // torrent is paused and has finished downloading case "uploading": // torrent is being seeded and data is being transferred case "stalledUP": // torrent is being seeded, but no connection were made case "queuedUP": // queuing is enabled and torrent is queued for upload case "forcedUP": // torrent has finished downloading and is being forcibly seeded item.Status = DownloadItemStatus.Completed; item.RemainingTime = TimeSpan.Zero; // qBittorrent sends eta=8640000 for completed torrents break; case "stalledDL": // torrent is being downloaded, but no connection were made item.Status = DownloadItemStatus.Warning; item.Message = "The download is stalled with no connections"; break; case "missingFiles": // torrent is being downloaded, but no connection were made item.Status = DownloadItemStatus.Warning; item.Message = "The download is missing files"; break; case "metaDL": // torrent magnet is being downloaded if (config.DhtEnabled) { item.Status = DownloadItemStatus.Queued; } else { item.Status = DownloadItemStatus.Warning; item.Message = "qBittorrent cannot resolve magnet link with DHT disabled"; } break; case "forcedDL": //torrent is being downloaded, and was forced started case "moving": // torrent is being moved from a folder case "downloading": // torrent is being downloaded and data is being transferred item.Status = DownloadItemStatus.Downloading; break; default: // new status in API? default to downloading item.Message = "Unknown download state: " + torrent.State; _logger.Info(item.Message); item.Status = DownloadItemStatus.Downloading; break; } if (version >= new Version("2.6.1")) { if (torrent.ContentPath != torrent.SavePath) { item.OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.ContentPath)); } else if (item.Status == DownloadItemStatus.Completed) { item.Status = DownloadItemStatus.Warning; item.Message = "Unable to import since content path is equal to root download directory, perhaps Keep top-level folder was disabled for this torrent?"; } } queueItems.Add(item); } return(queueItems); }
public override IEnumerable <DownloadClientItem> GetItems() { List <NzbVortexQueueItem> vortexQueue; try { vortexQueue = _proxy.GetQueue(30, Settings); } catch (DownloadClientException ex) { _logger.Warn("Couldn't get download queue. {0}", ex.Message); return(Enumerable.Empty <DownloadClientItem>()); } var queueItems = new List <DownloadClientItem>(); foreach (var vortexQueueItem in vortexQueue) { var queueItem = new DownloadClientItem(); queueItem.DownloadClient = Definition.Name; queueItem.DownloadId = vortexQueueItem.AddUUID ?? vortexQueueItem.Id.ToString(); queueItem.Category = vortexQueueItem.GroupName; queueItem.Title = vortexQueueItem.UiTitle; queueItem.TotalSize = vortexQueueItem.TotalDownloadSize; queueItem.RemainingSize = vortexQueueItem.TotalDownloadSize - vortexQueueItem.DownloadedSize; queueItem.RemainingTime = null; queueItem.CanBeRemoved = true; queueItem.CanMoveFiles = true; if (vortexQueueItem.IsPaused) { queueItem.Status = DownloadItemStatus.Paused; } else { switch (vortexQueueItem.State) { case NzbVortexStateType.Waiting: queueItem.Status = DownloadItemStatus.Queued; break; case NzbVortexStateType.Done: queueItem.Status = DownloadItemStatus.Completed; break; case NzbVortexStateType.UncompressFailed: case NzbVortexStateType.CheckFailedDataCorrupt: case NzbVortexStateType.BadlyEncoded: queueItem.Status = DownloadItemStatus.Failed; break; default: queueItem.Status = DownloadItemStatus.Downloading; break; } } queueItem.OutputPath = GetOutputPath(vortexQueueItem, queueItem); if (vortexQueueItem.State == NzbVortexStateType.PasswordRequest) { queueItem.IsEncrypted = true; } if (queueItem.Status == DownloadItemStatus.Completed) { queueItem.RemainingTime = TimeSpan.Zero; } queueItems.Add(queueItem); } return(queueItems); }
public MovieDownloadedEvent(LocalMovie movie, MovieFile movieFile, List <MovieFile> oldFiles, DownloadClientItem downloadClientItem) { Movie = movie; MovieFile = movieFile; OldFiles = oldFiles; if (downloadClientItem != null) { DownloadId = downloadClientItem.DownloadId; } }
public override IEnumerable <DownloadClientItem> GetItems() { foreach (var folder in _diskProvider.GetDirectories(Settings.WatchFolder)) { var title = FileNameBuilder.CleanFileName(Path.GetFileName(folder)); var files = _diskProvider.GetFiles(folder, SearchOption.AllDirectories); var historyItem = new DownloadClientItem { DownloadClient = Definition.Name, DownloadId = Definition.Name + "_" + Path.GetFileName(folder) + "_" + _diskProvider.FolderGetCreationTime(folder).Ticks, Category = "nzbdrone", Title = title, TotalSize = files.Select(_diskProvider.GetFileSize).Sum(), OutputPath = new OsPath(folder) }; if (files.Any(_diskProvider.IsFileLocked)) { historyItem.Status = DownloadItemStatus.Downloading; } else { historyItem.Status = DownloadItemStatus.Completed; historyItem.RemainingTime = TimeSpan.Zero; } yield return(historyItem); } foreach (var videoFile in _diskScanService.GetVideoFiles(Settings.WatchFolder, false)) { var title = FileNameBuilder.CleanFileName(Path.GetFileName(videoFile)); var historyItem = new DownloadClientItem { DownloadClient = Definition.Name, DownloadId = Definition.Name + "_" + Path.GetFileName(videoFile) + "_" + _diskProvider.FileGetLastWrite(videoFile).Ticks, Category = "nzbdrone", Title = title, TotalSize = _diskProvider.GetFileSize(videoFile), OutputPath = new OsPath(videoFile) }; if (_diskProvider.IsFileLocked(videoFile)) { historyItem.Status = DownloadItemStatus.Downloading; } else { historyItem.Status = DownloadItemStatus.Completed; historyItem.RemainingTime = TimeSpan.Zero; } yield return(historyItem); } }
private List <ImportResult> ProcessFile(FileInfo fileInfo, ImportMode importMode, DownloadClientItem downloadClientItem) { 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, importMode, series, downloadClientItem)); }
public override IEnumerable <DownloadClientItem> GetItems() { var configFunc = new Lazy <TransmissionConfig>(() => _proxy.GetConfig(Settings)); var torrents = _proxy.GetTorrents(Settings); var items = new List <DownloadClientItem>(); foreach (var torrent in torrents) { // If totalsize == 0 the torrent is a magnet downloading metadata if (torrent.TotalSize == 0) { continue; } var outputPath = new OsPath(torrent.DownloadDir); if (Settings.MovieDirectory.IsNotNullOrWhiteSpace()) { if (!new OsPath(Settings.MovieDirectory).Contains(outputPath)) { continue; } } else if (Settings.MovieCategory.IsNotNullOrWhiteSpace()) { var directories = outputPath.FullPath.Split('\\', '/'); if (!directories.Contains(Settings.MovieCategory)) { continue; } } outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, outputPath); var item = new DownloadClientItem(); item.DownloadId = torrent.HashString.ToUpper(); item.Category = Settings.MovieCategory; item.Title = torrent.Name; item.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this); item.OutputPath = GetOutputPath(outputPath, torrent); item.TotalSize = torrent.TotalSize; item.RemainingSize = torrent.LeftUntilDone; item.SeedRatio = torrent.DownloadedEver <= 0 ? 0 : (double)torrent.UploadedEver / torrent.DownloadedEver; if (torrent.Eta >= 0) { item.RemainingTime = TimeSpan.FromSeconds(torrent.Eta); } if (!torrent.ErrorString.IsNullOrWhiteSpace()) { item.Status = DownloadItemStatus.Warning; item.Message = torrent.ErrorString; } else if (torrent.LeftUntilDone == 0 && (torrent.Status == TransmissionTorrentStatus.Stopped || torrent.Status == TransmissionTorrentStatus.Seeding || torrent.Status == TransmissionTorrentStatus.SeedingWait)) { item.Status = DownloadItemStatus.Completed; } else if (torrent.IsFinished && torrent.Status != TransmissionTorrentStatus.Check && torrent.Status != TransmissionTorrentStatus.CheckWait) { item.Status = DownloadItemStatus.Completed; } else if (torrent.Status == TransmissionTorrentStatus.Queued) { item.Status = DownloadItemStatus.Queued; } else { item.Status = DownloadItemStatus.Downloading; } item.CanBeRemoved = HasReachedSeedLimit(torrent, item.SeedRatio, configFunc); item.CanMoveFiles = item.CanBeRemoved && torrent.Status == TransmissionTorrentStatus.Stopped; items.Add(item); } return(items); }
private List <ImportResult> ProcessFolder(DirectoryInfo directoryInfo, ImportMode importMode, DownloadClientItem downloadClientItem) { 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, importMode, series, downloadClientItem)); }
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>()); } 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, downloadClientItem, folderInfo, true); var importResults = _importApprovedEpisodes.Import(decisions, true, downloadClientItem, importMode); if ((downloadClientItem == null || downloadClientItem.CanMoveFiles) && 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); }
public override IEnumerable <DownloadClientItem> GetItems() { try { var torrents = _proxy.GetTorrents(Settings); _logger.Debug("Retrieved metadata of {0} torrents in client", torrents.Count); var items = new List <DownloadClientItem>(); foreach (RTorrentTorrent torrent in torrents) { // Don't concern ourselves with categories other than specified if (torrent.Category != Settings.TvCategory) { continue; } if (torrent.Path.StartsWith(".")) { throw new DownloadClientException("Download paths paths must be absolute. Please specify variable \"directory\" in rTorrent."); } var item = new DownloadClientItem(); item.DownloadClient = Definition.Name; item.Title = torrent.Name; item.DownloadId = torrent.Hash; item.OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.Path)); item.TotalSize = torrent.TotalSize; item.RemainingSize = torrent.RemainingSize; item.Category = torrent.Category; if (torrent.DownRate > 0) { var secondsLeft = torrent.RemainingSize / torrent.DownRate; item.RemainingTime = TimeSpan.FromSeconds(secondsLeft); } else { item.RemainingTime = TimeSpan.Zero; } if (torrent.IsFinished) { item.Status = DownloadItemStatus.Completed; } else if (torrent.IsActive) { item.Status = DownloadItemStatus.Downloading; } else if (!torrent.IsActive) { item.Status = DownloadItemStatus.Paused; } // Since we do not know the user's intent, do not let Sonarr to remove the torrent item.IsReadOnly = true; items.Add(item); } return(items); } catch (DownloadClientException ex) { _logger.ErrorException(ex.Message, ex); return(Enumerable.Empty <DownloadClientItem>()); } }
private IEnumerable <DownloadClientItem> GetQueue() { NzbgetGlobalStatus globalStatus; List <NzbgetQueueItem> queue; try { globalStatus = _proxy.GetGlobalStatus(Settings); queue = _proxy.GetQueue(Settings); } catch (DownloadClientException ex) { _logger.Error(ex, ex.Message); return(Enumerable.Empty <DownloadClientItem>()); } var queueItems = new List <DownloadClientItem>(); long totalRemainingSize = 0; foreach (var item in queue) { var totalSize = MakeInt64(item.FileSizeHi, item.FileSizeLo); var pausedSize = MakeInt64(item.PausedSizeHi, item.PausedSizeLo); var remainingSize = MakeInt64(item.RemainingSizeHi, item.RemainingSizeLo); var droneParameter = item.Parameters.SingleOrDefault(p => p.Name == "drone"); var queueItem = new DownloadClientItem(); queueItem.DownloadId = droneParameter == null?item.NzbId.ToString() : droneParameter.Value.ToString(); queueItem.Title = item.NzbName; queueItem.TotalSize = totalSize; queueItem.Category = item.Category; queueItem.DownloadClient = Definition.Name; queueItem.CanMoveFiles = true; queueItem.CanBeRemoved = true; if (globalStatus.DownloadPaused || remainingSize == pausedSize && remainingSize != 0) { queueItem.Status = DownloadItemStatus.Paused; queueItem.RemainingSize = remainingSize; } else { if (item.ActiveDownloads == 0 && remainingSize != 0) { queueItem.Status = DownloadItemStatus.Queued; } else { queueItem.Status = DownloadItemStatus.Downloading; } queueItem.RemainingSize = remainingSize - pausedSize; if (globalStatus.DownloadRate != 0) { queueItem.RemainingTime = TimeSpan.FromSeconds((totalRemainingSize + queueItem.RemainingSize) / globalStatus.DownloadRate); totalRemainingSize += queueItem.RemainingSize; } } queueItems.Add(queueItem); } return(queueItems); }
public List <ImportDecision <LocalTrack> > GetImportDecisions(List <IFileInfo> musicFiles, Artist artist, Album album, AlbumRelease albumRelease, DownloadClientItem downloadClientItem, ParsedTrackInfo folderInfo, FilterFilesType filter, bool newDownload, bool singleRelease, bool includeExisting) { var watch = new System.Diagnostics.Stopwatch(); watch.Start(); var files = filter != FilterFilesType.None && (artist != null) ? _mediaFileService.FilterUnchangedFiles(musicFiles, artist, filter) : musicFiles; var localTracks = new List <LocalTrack>(); var decisions = new List <ImportDecision <LocalTrack> >(); _logger.Debug("Analyzing {0}/{1} files.", files.Count, musicFiles.Count); if (!files.Any()) { return(decisions); } ParsedAlbumInfo downloadClientItemInfo = null; if (downloadClientItem != null) { downloadClientItemInfo = Parser.Parser.ParseAlbumTitle(downloadClientItem.Title); } foreach (var file in files) { var localTrack = new LocalTrack { Artist = artist, Album = album, DownloadClientAlbumInfo = downloadClientItemInfo, FolderTrackInfo = folderInfo, Path = file.FullName, Size = file.Length, Modified = file.LastWriteTimeUtc, FileTrackInfo = _audioTagService.ReadTags(file.FullName), ExistingFile = !newDownload, AdditionalFile = false }; try { // TODO fix otherfiles? _augmentingService.Augment(localTrack, true); localTracks.Add(localTrack); } catch (AugmentingFailedException) { decisions.Add(new ImportDecision <LocalTrack>(localTrack, new Rejection("Unable to parse file"))); } catch (Exception e) { _logger.Error(e, "Couldn't import file. {0}", localTrack.Path); decisions.Add(new ImportDecision <LocalTrack>(localTrack, new Rejection("Unexpected error processing file"))); } } _logger.Debug($"Tags parsed for {files.Count} files in {watch.ElapsedMilliseconds}ms"); var releases = _identificationService.Identify(localTracks, artist, album, albumRelease, newDownload, singleRelease, includeExisting); foreach (var release in releases) { release.NewDownload = newDownload; var releaseDecision = GetDecision(release); foreach (var localTrack in release.LocalTracks) { if (releaseDecision.Approved) { decisions.AddIfNotNull(GetDecision(localTrack)); } else { decisions.Add(new ImportDecision <LocalTrack>(localTrack, releaseDecision.Rejections.ToArray())); } } } return(decisions); }
public override IEnumerable <DownloadClientItem> GetItems() { var torrents = _proxy.GetTorrents(Settings); _logger.Debug("Retrieved metadata of {0} torrents in client", torrents.Count); var items = new List <DownloadClientItem>(); foreach (RTorrentTorrent torrent in torrents) { // Don't concern ourselves with categories other than specified if (torrent.Category != Settings.TvCategory) { continue; } if (torrent.Path.StartsWith(".")) { throw new DownloadClientException("Download paths paths must be absolute. Please specify variable \"directory\" in rTorrent."); } var item = new DownloadClientItem(); item.DownloadClient = Definition.Name; item.Title = torrent.Name; item.DownloadId = torrent.Hash; item.OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.Path)); item.TotalSize = torrent.TotalSize; item.RemainingSize = torrent.RemainingSize; item.Category = torrent.Category; item.SeedRatio = torrent.Ratio; if (torrent.DownRate > 0) { var secondsLeft = torrent.RemainingSize / torrent.DownRate; item.RemainingTime = TimeSpan.FromSeconds(secondsLeft); } else { item.RemainingTime = TimeSpan.Zero; } if (torrent.IsFinished) { item.Status = DownloadItemStatus.Completed; } else if (torrent.IsActive) { item.Status = DownloadItemStatus.Downloading; } else if (!torrent.IsActive) { item.Status = DownloadItemStatus.Paused; } // No stop ratio data is present, so do not delete item.CanMoveFiles = item.CanBeRemoved = false; items.Add(item); } return(items); }
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); 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, downloadClientItem, null, true); return(_importApprovedEpisodes.Import(decisions, true, downloadClientItem, importMode)); }
public override IEnumerable <DownloadClientItem> GetItems() { IEnumerable <DelugeTorrent> torrents; if (!Settings.TvCategory.IsNullOrWhiteSpace()) { torrents = _proxy.GetTorrentsByLabel(Settings.TvCategory, Settings); } else { torrents = _proxy.GetTorrents(Settings); } var items = new List <DownloadClientItem>(); foreach (var torrent in torrents) { var item = new DownloadClientItem(); item.DownloadId = torrent.Hash.ToUpper(); item.Title = torrent.Name; item.Category = Settings.TvCategory; item.DownloadClient = Definition.Name; var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.DownloadPath)); item.OutputPath = outputPath + torrent.Name; item.RemainingSize = torrent.Size - torrent.BytesDownloaded; try { item.RemainingTime = TimeSpan.FromSeconds(torrent.Eta); } catch (OverflowException ex) { _logger.Debug(ex, "ETA for {0} is too long: {1}", torrent.Name, torrent.Eta); item.RemainingTime = TimeSpan.MaxValue; } item.TotalSize = torrent.Size; if (torrent.State == DelugeTorrentStatus.Error) { item.Status = DownloadItemStatus.Warning; item.Message = "Deluge is reporting an error"; } else if (torrent.IsFinished && torrent.State != DelugeTorrentStatus.Checking) { item.Status = DownloadItemStatus.Completed; } else if (torrent.State == DelugeTorrentStatus.Queued) { item.Status = DownloadItemStatus.Queued; } else if (torrent.State == DelugeTorrentStatus.Paused) { item.Status = DownloadItemStatus.Paused; } else { item.Status = DownloadItemStatus.Downloading; } // Here we detect if Deluge is managing the torrent and whether the seed criteria has been met. This allows drone to delete the torrent as appropriate. item.CanMoveFiles = item.CanBeRemoved = (torrent.IsAutoManaged && torrent.StopAtRatio && torrent.Ratio >= torrent.StopRatio && torrent.State == DelugeTorrentStatus.Paused); items.Add(item); } return(items); }
public List <ImportResult> ProcessPath(string path, ImportMode importMode = ImportMode.Auto, Series series = null, DownloadClientItem downloadClientItem = null) { if (_diskProvider.FolderExists(path)) { var directoryInfo = new DirectoryInfo(path); if (series == null) { return(ProcessFolder(directoryInfo, importMode, downloadClientItem)); } return(ProcessFolder(directoryInfo, importMode, series, downloadClientItem)); } if (_diskProvider.FileExists(path)) { var fileInfo = new FileInfo(path); if (series == null) { return(ProcessFile(fileInfo, importMode, downloadClientItem)); } return(ProcessFile(fileInfo, importMode, series, downloadClientItem)); } _logger.Error("Import failed, path does not exist or is not accessible by Sonarr: {0}", path); return(new List <ImportResult>()); }
public TrackedDownload TrackDownload(DownloadClientDefinition downloadClient, DownloadClientItem downloadItem) { var existingItem = Find(downloadItem.DownloadId); if (existingItem != null && existingItem.State != TrackedDownloadStage.Downloading) { existingItem.DownloadItem = downloadItem; return(existingItem); } var trackedDownload = new TrackedDownload { DownloadClient = downloadClient.Id, DownloadItem = downloadItem, Protocol = downloadClient.Protocol }; try { var parsedEpisodeInfo = Parser.Parser.ParseTitle(trackedDownload.DownloadItem.Title); if (parsedEpisodeInfo == null) { return(null); } var remoteEpisode = _parsingService.Map(parsedEpisodeInfo); if (remoteEpisode.Series == null) { var historyItems = _historyService.FindByDownloadId(downloadItem.DownloadId); if (historyItems.Empty()) { return(null); } 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); } var historyItem = _historyService.MostRecentForDownloadId(downloadItem.DownloadId); if (historyItem != null) { trackedDownload.State = GetStateFromHistory(historyItem.EventType); } _cache.Set(trackedDownload.DownloadItem.DownloadId, trackedDownload); return(trackedDownload); }
public override IEnumerable <DownloadClientItem> GetItems() { var config = _proxy.GetConfig(Settings); var torrents = _proxy.GetTorrents(Settings); var queueItems = new List <DownloadClientItem>(); foreach (var torrent in torrents) { var item = new DownloadClientItem(); item.DownloadId = torrent.Hash.ToUpper(); item.Category = torrent.Category.IsNotNullOrWhiteSpace() ? torrent.Category : torrent.Label; item.Title = torrent.Name; item.TotalSize = torrent.Size; item.DownloadClient = Definition.Name; item.RemainingSize = (long)(torrent.Size * (1.0 - torrent.Progress)); item.RemainingTime = TimeSpan.FromSeconds(torrent.Eta); item.OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.SavePath)); // Avoid removing torrents that haven't reached the global max ratio. // Removal also requires the torrent to be paused, in case a higher max ratio was set on the torrent itself (which is not exposed by the api). item.CanMoveFiles = item.CanBeRemoved = (!config.MaxRatioEnabled || config.MaxRatio <= torrent.Ratio) && torrent.State == "pausedUP"; if (!item.OutputPath.IsEmpty && item.OutputPath.FileName != torrent.Name) { item.OutputPath += torrent.Name; } switch (torrent.State) { case "error": // some error occurred, applies to paused torrents item.Status = DownloadItemStatus.Failed; item.Message = "qBittorrent is reporting an error"; break; case "pausedDL": // torrent is paused and has NOT finished downloading item.Status = DownloadItemStatus.Paused; break; case "queuedDL": // queuing is enabled and torrent is queued for download case "checkingDL": // same as checkingUP, but torrent has NOT finished downloading item.Status = DownloadItemStatus.Queued; break; case "pausedUP": // torrent is paused and has finished downloading: case "uploading": // torrent is being seeded and data is being transfered case "stalledUP": // torrent is being seeded, but no connection were made case "queuedUP": // queuing is enabled and torrent is queued for upload case "checkingUP": // torrent has finished downloading and is being checked item.Status = DownloadItemStatus.Completed; item.RemainingTime = TimeSpan.Zero; // qBittorrent sends eta=8640000 for completed torrents break; case "stalledDL": // torrent is being downloaded, but no connection were made item.Status = DownloadItemStatus.Warning; item.Message = "The download is stalled with no connections"; break; case "downloading": // torrent is being downloaded and data is being transfered default: // new status in API? default to downloading item.Status = DownloadItemStatus.Downloading; break; } queueItems.Add(item); } return(queueItems); }
public override IEnumerable <DownloadClientItem> GetItems() { var torrents = _proxy.GetTorrents(Settings); var items = new List <DownloadClientItem>(); foreach (var torrent in torrents) { if (Settings.Category.IsNotNullOrWhiteSpace() && torrent.Label != Settings.Category) { continue; } var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.SavePath)); var eta = TimeSpan.FromSeconds(0); if (torrent.DownloadRate > 0 && torrent.TotalSize > 0) { eta = TimeSpan.FromSeconds(torrent.TotalSize / (double)torrent.DownloadRate); } var item = new DownloadClientItem { DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this), DownloadId = torrent.InfoHash.ToUpper(), OutputPath = outputPath + torrent.Name, RemainingSize = torrent.TotalSize - torrent.DownloadedBytes, RemainingTime = eta, Title = torrent.Name, TotalSize = torrent.TotalSize, SeedRatio = torrent.DownloadedBytes <= 0 ? 0 : (double)torrent.UploadedBytes / torrent.DownloadedBytes }; if (!string.IsNullOrEmpty(torrent.Error)) { item.Status = DownloadItemStatus.Warning; item.Message = torrent.Error; } else if (torrent.IsFinished && torrent.State != HadoukenTorrentState.CheckingFiles) { item.Status = DownloadItemStatus.Completed; } else if (torrent.State == HadoukenTorrentState.QueuedForChecking) { item.Status = DownloadItemStatus.Queued; } else if (torrent.State == HadoukenTorrentState.Paused) { item.Status = DownloadItemStatus.Paused; } else { item.Status = DownloadItemStatus.Downloading; } item.CanMoveFiles = item.CanBeRemoved = torrent.IsFinished && torrent.State == HadoukenTorrentState.Paused; items.Add(item); } return(items); }
public override IEnumerable <DownloadClientItem> GetItems() { var nzbTasks = GetTasks(); var serialNumber = _serialNumberProvider.GetSerialNumber(Settings); var items = new List <DownloadClientItem>(); long totalRemainingSize = 0; long globalSpeed = nzbTasks.Where(t => t.Status == DownloadStationTaskStatus.Downloading) .Select(GetDownloadSpeed) .Sum(); foreach (var nzb in nzbTasks) { var outputPath = new OsPath($"/{nzb.Additional.Detail["destination"]}"); var taskRemainingSize = GetRemainingSize(nzb); if (nzb.Status != DownloadStationTaskStatus.Paused) { totalRemainingSize += taskRemainingSize; } if (Settings.TvDirectory.IsNotNullOrWhiteSpace()) { if (!new OsPath($"/{Settings.TvDirectory}").Contains(outputPath)) { continue; } } else if (Settings.TvCategory.IsNotNullOrWhiteSpace()) { var directories = outputPath.FullPath.Split('\\', '/'); if (!directories.Contains(Settings.TvCategory)) { continue; } } var item = new DownloadClientItem() { Category = Settings.TvCategory, DownloadClient = Definition.Name, DownloadId = CreateDownloadId(nzb.Id, serialNumber), Title = nzb.Title, TotalSize = nzb.Size, RemainingSize = taskRemainingSize, Status = GetStatus(nzb), Message = GetMessage(nzb), IsReadOnly = !IsFinished(nzb) }; if (item.Status != DownloadItemStatus.Paused) { item.RemainingTime = GetRemainingTime(totalRemainingSize, globalSpeed); } if (item.Status == DownloadItemStatus.Completed || item.Status == DownloadItemStatus.Failed) { item.OutputPath = GetOutputPath(outputPath, nzb, serialNumber); } items.Add(item); } return(items); }
private IEnumerable <DownloadClientItem> GetHistory() { var history = _proxy.GetHistory(Settings).Take(_configService.DownloadClientHistoryLimit).ToList(); var historyItems = new List <DownloadClientItem>(); foreach (var item in history) { var droneParameter = item.Parameters.SingleOrDefault(p => p.Name == "drone"); var historyItem = new DownloadClientItem(); var itemDir = item.FinalDir.IsNullOrWhiteSpace() ? item.DestDir : item.FinalDir; historyItem.DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this); historyItem.DownloadId = droneParameter == null?item.Id.ToString() : droneParameter.Value.ToString(); historyItem.Title = item.Name; historyItem.TotalSize = MakeInt64(item.FileSizeHi, item.FileSizeLo); historyItem.OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(itemDir)); historyItem.Category = item.Category; historyItem.Message = $"PAR Status: {item.ParStatus} - Unpack Status: {item.UnpackStatus} - Move Status: {item.MoveStatus} - Script Status: {item.ScriptStatus} - Delete Status: {item.DeleteStatus} - Mark Status: {item.MarkStatus}"; historyItem.Status = DownloadItemStatus.Completed; historyItem.RemainingTime = TimeSpan.Zero; historyItem.CanMoveFiles = true; historyItem.CanBeRemoved = true; if (item.DeleteStatus == "MANUAL") { continue; } if (!_successStatus.Contains(item.ParStatus)) { historyItem.Status = DownloadItemStatus.Failed; } if (item.UnpackStatus == "SPACE") { historyItem.Status = DownloadItemStatus.Warning; } else if (!_successStatus.Contains(item.UnpackStatus)) { historyItem.Status = DownloadItemStatus.Failed; } if (!_successStatus.Contains(item.MoveStatus)) { historyItem.Status = DownloadItemStatus.Warning; } if (!_successStatus.Contains(item.ScriptStatus)) { historyItem.Status = DownloadItemStatus.Failed; } if (!_successStatus.Contains(item.DeleteStatus) && item.DeleteStatus.IsNotNullOrWhiteSpace()) { if (_deleteFailedStatus.Contains(item.DeleteStatus)) { historyItem.Status = DownloadItemStatus.Failed; } else { historyItem.Status = DownloadItemStatus.Warning; } } historyItems.Add(historyItem); } return(historyItems); }
private void LogItemChange(TrackedDownload trackedDownload, DownloadClientItem existingItem, DownloadClientItem downloadItem) { if (existingItem == null || existingItem.Status != downloadItem.Status || existingItem.CanBeRemoved != downloadItem.CanBeRemoved || existingItem.CanMoveFiles != downloadItem.CanMoveFiles) { _logger.Debug("Tracking '{0}:{1}': ClientState={2}{3} SonarrStage={4} Episode='{5}' OutputPath={6}.", downloadItem.DownloadClientInfo.Name, downloadItem.Title, downloadItem.Status, downloadItem.CanBeRemoved ? "" : downloadItem.CanMoveFiles ? " (busy)" : " (readonly)", trackedDownload.State, trackedDownload.RemoteEpisode?.ParsedEpisodeInfo, downloadItem.OutputPath); } }
public override void RemoveItem(DownloadClientItem item, bool deleteData) { Proxy.RemoveTorrent(item.DownloadId.ToLower(), deleteData, Settings); }
public TrackedDownload TrackDownload(DownloadClientDefinition downloadClient, DownloadClientItem downloadItem) { var existingItem = Find(downloadItem.DownloadId); if (existingItem != null && existingItem.State != TrackedDownloadStage.Downloading) { existingItem.DownloadItem = downloadItem; return existingItem; } var trackedDownload = new TrackedDownload { DownloadClient = downloadClient.Id, DownloadItem = downloadItem, Protocol = downloadClient.Protocol }; try { var parsedEpisodeInfo = Parser.Parser.ParseTitle(trackedDownload.DownloadItem.Title); var historyItems = _historyService.FindByDownloadId(downloadItem.DownloadId); if (parsedEpisodeInfo != null) { trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0); } if (historyItems.Any()) { var firstHistoryItem = historyItems.OrderByDescending(h => h.Date).First(); trackedDownload.State = GetStateFromHistory(firstHistoryItem.EventType); if (parsedEpisodeInfo == null || trackedDownload.RemoteEpisode == null || trackedDownload.RemoteEpisode.Series == null || trackedDownload.RemoteEpisode.Episodes.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 parsedEpisodeInfo = Parser.Parser.ParseTitle(firstHistoryItem.SourceTitle) ?? _parsingService.ParseSpecialEpisodeTitle(firstHistoryItem.SourceTitle, 0, 0); if (parsedEpisodeInfo != null) { trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, firstHistoryItem.SeriesId, historyItems.Where(v => v.EventType == HistoryEventType.Grabbed).Select(h => h.EpisodeId).Distinct()); } } } if (trackedDownload.RemoteEpisode == null) { return null; } } catch (Exception e) { _logger.Debug(e, "Failed to find episode for " + downloadItem.Title); return null; } _cache.Set(trackedDownload.DownloadItem.DownloadId, trackedDownload); return trackedDownload; }
private List <ImportResult> ProcessFolder(IDirectoryInfo directoryInfo, ImportMode importMode, DownloadClientItem downloadClientItem) { var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name); var author = _parsingService.GetAuthor(cleanedUpName); return(ProcessFolder(directoryInfo, importMode, author, downloadClientItem)); }
protected void VerifyFailed(DownloadClientItem downloadClientItem) { VerifyIdentifiable(downloadClientItem); downloadClientItem.Status.Should().Be(DownloadItemStatus.Failed); }
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 parsedEpisodeInfo = Parser.Parser.ParseTitle(trackedDownload.DownloadItem.Title); var historyItems = _historyService.FindByDownloadId(downloadItem.DownloadId) .OrderByDescending(h => h.Date) .ToList(); if (parsedEpisodeInfo != null) { trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, 0, 0); } var downloadHistory = _downloadHistoryService.GetLatestDownloadHistoryItem(downloadItem.DownloadId); if (downloadHistory != null) { var state = GetStateFromHistory(downloadHistory.EventType); trackedDownload.State = state; } if (historyItems.Any()) { var firstHistoryItem = historyItems.First(); var grabbedEvent = historyItems.FirstOrDefault(v => v.EventType == EpisodeHistoryEventType.Grabbed); trackedDownload.Indexer = grabbedEvent?.Data["indexer"]; if (parsedEpisodeInfo == null || trackedDownload.RemoteEpisode == null || trackedDownload.RemoteEpisode.Series == null || trackedDownload.RemoteEpisode.Episodes.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 parsedEpisodeInfo = Parser.Parser.ParseTitle(firstHistoryItem.SourceTitle) ?? _parsingService.ParseSpecialEpisodeTitle(parsedEpisodeInfo, firstHistoryItem.SourceTitle, 0, 0); if (parsedEpisodeInfo != null) { trackedDownload.RemoteEpisode = _parsingService.Map(parsedEpisodeInfo, firstHistoryItem.SeriesId, historyItems.Where(v => v.EventType == EpisodeHistoryEventType.Grabbed).Select(h => h.EpisodeId).Distinct()); } } } // Track it so it can be displayed in the queue even though we can't determine which series it is for if (trackedDownload.RemoteEpisode == null) { _logger.Trace("No Episode found for download '{0}'", trackedDownload.DownloadItem.Title); } } catch (Exception e) { _logger.Debug(e, "Failed to find episode for " + downloadItem.Title); return(null); } LogItemChange(trackedDownload, existingItem?.DownloadItem, trackedDownload.DownloadItem); _cache.Set(trackedDownload.DownloadItem.DownloadId, trackedDownload); return(trackedDownload); }
public override IEnumerable <DownloadClientItem> GetItems() { HadoukenTorrent[] torrents; try { torrents = _proxy.GetTorrents(Settings); } catch (DownloadClientException ex) { _logger.ErrorException(ex.Message, ex); return(Enumerable.Empty <DownloadClientItem>()); } var items = new List <DownloadClientItem>(); foreach (var torrent in torrents) { if (Settings.Category.IsNotNullOrWhiteSpace() && torrent.Label != Settings.Category) { continue; } var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.SavePath)); var eta = TimeSpan.FromSeconds(0); if (torrent.DownloadRate > 0 && torrent.TotalSize > 0) { eta = TimeSpan.FromSeconds(torrent.TotalSize / (double)torrent.DownloadRate); } var item = new DownloadClientItem { DownloadClient = Definition.Name, DownloadId = torrent.InfoHash.ToUpper(), OutputPath = outputPath + torrent.Name, RemainingSize = torrent.TotalSize - torrent.DownloadedBytes, RemainingTime = eta, Title = torrent.Name, TotalSize = torrent.TotalSize }; if (!string.IsNullOrEmpty(torrent.Error)) { item.Status = DownloadItemStatus.Warning; item.Message = torrent.Error; } else if (torrent.IsFinished && torrent.State != HadoukenTorrentState.CheckingFiles) { item.Status = DownloadItemStatus.Completed; } else if (torrent.State == HadoukenTorrentState.QueuedForChecking) { item.Status = DownloadItemStatus.Queued; } else if (torrent.State == HadoukenTorrentState.Paused) { item.Status = DownloadItemStatus.Paused; } else { item.Status = DownloadItemStatus.Downloading; } if (torrent.IsFinished && torrent.State == HadoukenTorrentState.Paused) { item.IsReadOnly = false; } else { item.IsReadOnly = true; } items.Add(item); } return(items); }
private IEnumerable <DownloadClientItem> GetHistory() { SabnzbdHistory sabHistory; try { sabHistory = _proxy.GetHistory(0, _configService.DownloadClientHistoryLimit, Settings); } catch (DownloadClientException ex) { _logger.ErrorException(ex.Message, ex); return(Enumerable.Empty <DownloadClientItem>()); } var historyItems = new List <DownloadClientItem>(); foreach (var sabHistoryItem in sabHistory.Items) { var historyItem = new DownloadClientItem { DownloadClient = Definition.Name, DownloadClientId = sabHistoryItem.Id, Category = sabHistoryItem.Category, Title = sabHistoryItem.Title, TotalSize = sabHistoryItem.Size, RemainingSize = 0, DownloadTime = TimeSpan.FromSeconds(sabHistoryItem.DownloadTime), RemainingTime = TimeSpan.Zero, Message = sabHistoryItem.FailMessage }; if (sabHistoryItem.Status == SabnzbdDownloadStatus.Failed) { if (sabHistoryItem.FailMessage.IsNotNullOrWhiteSpace() && sabHistoryItem.FailMessage.Equals("Unpacking failed, write error or disk is full?", StringComparison.InvariantCultureIgnoreCase)) { historyItem.Status = DownloadItemStatus.Warning; } else { historyItem.Status = DownloadItemStatus.Failed; } } else if (sabHistoryItem.Status == SabnzbdDownloadStatus.Completed) { historyItem.Status = DownloadItemStatus.Completed; } else // Verifying/Moving etc { historyItem.Status = DownloadItemStatus.Downloading; } var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, sabHistoryItem.Storage); if (!outputPath.IsNullOrWhiteSpace()) { historyItem.OutputPath = outputPath; var parent = outputPath.GetParentPath(); while (parent != null) { if (Path.GetFileName(parent) == sabHistoryItem.Title) { historyItem.OutputPath = parent; } parent = parent.GetParentPath(); } } historyItems.Add(historyItem); } return(historyItems); }
public override IEnumerable <DownloadClientItem> GetItems() { List <UTorrentTorrent> torrents; try { var cacheKey = string.Format("{0}:{1}:{2}", Settings.Host, Settings.Port, Settings.TvCategory); var cache = _torrentCache.Find(cacheKey); var response = _proxy.GetTorrents(cache == null ? null : cache.CacheID, Settings); if (cache != null && response.Torrents == null) { var removedAndUpdated = new HashSet <string>(response.TorrentsChanged.Select(v => v.Hash).Concat(response.TorrentsRemoved)); torrents = cache.Torrents .Where(v => !removedAndUpdated.Contains(v.Hash)) .Concat(response.TorrentsChanged) .ToList(); } else { torrents = response.Torrents; } cache = new UTorrentTorrentCache { CacheID = response.CacheNumber, Torrents = torrents }; _torrentCache.Set(cacheKey, cache, TimeSpan.FromMinutes(15)); } catch (DownloadClientException ex) { _logger.Error(ex); return(Enumerable.Empty <DownloadClientItem>()); } var queueItems = new List <DownloadClientItem>(); foreach (var torrent in torrents) { if (torrent.Label != Settings.TvCategory) { continue; } var item = new DownloadClientItem(); item.DownloadId = torrent.Hash; item.Title = torrent.Name; item.TotalSize = torrent.Size; item.Category = torrent.Label; item.DownloadClient = Definition.Name; item.RemainingSize = torrent.Remaining; if (torrent.Eta != -1) { item.RemainingTime = TimeSpan.FromSeconds(torrent.Eta); } var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.RootDownloadPath)); if (outputPath == null || outputPath.FileName == torrent.Name) { item.OutputPath = outputPath; } else { item.OutputPath = outputPath + torrent.Name; } if (torrent.Status.HasFlag(UTorrentTorrentStatus.Error)) { item.Status = DownloadItemStatus.Warning; item.Message = "uTorrent is reporting an error"; } else if (torrent.Status.HasFlag(UTorrentTorrentStatus.Loaded) && torrent.Status.HasFlag(UTorrentTorrentStatus.Checked) && torrent.Remaining == 0 && torrent.Progress == 1.0) { item.Status = DownloadItemStatus.Completed; } else if (torrent.Status.HasFlag(UTorrentTorrentStatus.Paused)) { item.Status = DownloadItemStatus.Paused; } else if (torrent.Status.HasFlag(UTorrentTorrentStatus.Started)) { item.Status = DownloadItemStatus.Downloading; } else { item.Status = DownloadItemStatus.Queued; } // 'Started' without 'Queued' is when the torrent is 'forced seeding' item.IsReadOnly = torrent.Status.HasFlag(UTorrentTorrentStatus.Queued) || torrent.Status.HasFlag(UTorrentTorrentStatus.Started); queueItems.Add(item); } return(queueItems); }