예제 #1
0
        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;
        }
예제 #2
0
        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);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
        }
예제 #6
0
        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);
        }
예제 #7
0
 public MovieDownloadedEvent(LocalMovie movie, MovieFile movieFile, List <MovieFile> oldFiles, DownloadClientItem downloadClientItem)
 {
     Movie     = movie;
     MovieFile = movieFile;
     OldFiles  = oldFiles;
     if (downloadClientItem != null)
     {
         DownloadId = downloadClientItem.DownloadId;
     }
 }
예제 #8
0
        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));
        }
예제 #10
0
        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);
        }
예제 #13
0
        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>());
            }
        }
예제 #14
0
        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);
        }
예제 #15
0
        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);
        }
예제 #16
0
        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));
        }
예제 #18
0
        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>());
        }
예제 #20
0
        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);
        }
예제 #21
0
        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);
        }
예제 #22
0
        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);
        }
예제 #23
0
        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);
        }
예제 #24
0
        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);
        }
예제 #25
0
 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);
     }
 }
예제 #26
0
 public override void RemoveItem(DownloadClientItem item, bool deleteData)
 {
     Proxy.RemoveTorrent(item.DownloadId.ToLower(), deleteData, Settings);
 }
예제 #27
0
        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));
        }
예제 #29
0
        protected void VerifyFailed(DownloadClientItem downloadClientItem)
        {
            VerifyIdentifiable(downloadClientItem);

            downloadClientItem.Status.Should().Be(DownloadItemStatus.Failed);
        }
예제 #30
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 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);
        }
예제 #31
0
        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);
        }
예제 #32
0
파일: Sabnzbd.cs 프로젝트: jayd2446/Sonarr
        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);
        }
예제 #33
0
        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);
        }