int NCursesFrontend::CalcQueueSize() { int queueSize = 0; if (m_groupFiles) { queueSize = DownloadQueue::Guard()->GetQueue()->size(); } else { GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); for (NzbInfo* nzbInfo : downloadQueue->GetQueue()) { queueSize += nzbInfo->GetFileList()->size(); } } return queueSize; }
void NCursesFrontend::PrintFileQueue() { int lineNr = m_queueWinTop + 1; int64 remaining = 0; int64 paused = 0; int pausedFiles = 0; int fileNum = 0; GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); for (NzbInfo* nzbInfo : downloadQueue->GetQueue()) { for (FileInfo* fileInfo : nzbInfo->GetFileList()) { if (fileNum >= m_queueScrollOffset && fileNum < m_queueScrollOffset + m_queueWinHeight -1) { PrintFilename(fileInfo, lineNr++, fileNum == m_selectedQueueEntry); } fileNum++; if (fileInfo->GetPaused()) { pausedFiles++; paused += fileInfo->GetRemainingSize(); } remaining += fileInfo->GetRemainingSize(); } } if (fileNum > 0) { BString<1024> header(" %sFiles for downloading - %i / %i files in queue - %s / %s", m_useColor ? "" : "*** ", fileNum, fileNum - pausedFiles, *Util::FormatSize(remaining), *Util::FormatSize(remaining - paused)); PrintTopHeader(header, m_queueWinTop, true); } else { lineNr--; BString<1024> header("%s Files for downloading", m_useColor ? "" : "*** "); PrintTopHeader(header, lineNr++, true); PlotLine("Ready to receive nzb-job", lineNr++, 0, NCURSES_COLORPAIR_TEXT); } }
void QueueScriptController::Run() { ExecuteScript(m_script); SetLogPrefix(nullptr); if (m_markBad) { GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); NzbInfo* nzbInfo = downloadQueue->GetQueue()->Find(m_id); if (nzbInfo) { PrintMessage(Message::mkWarning, "Cancelling download and deleting %s", *m_nzbName); nzbInfo->SetDeleteStatus(NzbInfo::dsBad); downloadQueue->EditEntry(m_id, DownloadQueue::eaGroupDelete, 0, nullptr); } } g_QueueScriptCoordinator->CheckQueue(); }
bool ArticleCache::CheckFlush(bool flushEverything) { debug("Checking cache, Allocated: %i, FlushEverything: %i", (int)m_allocated, (int)flushEverything); BString<1024> infoName; { GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); for (NzbInfo* nzbInfo : downloadQueue->GetQueue()) { if (m_fileInfo) { break; } for (FileInfo* fileInfo : nzbInfo->GetFileList()) { if (fileInfo->GetCachedArticles() > 0 && (fileInfo->GetActiveDownloads() == 0 || flushEverything)) { m_fileInfo = fileInfo; infoName.Format("%s%c%s", m_fileInfo->GetNzbInfo()->GetName(), PATH_SEPARATOR, m_fileInfo->GetFilename()); break; } } } } if (m_fileInfo) { ArticleWriter articleWriter; articleWriter.SetFileInfo(m_fileInfo); articleWriter.SetInfoName(infoName); articleWriter.FlushCache(); m_fileInfo = nullptr; return true; } debug("Checking cache... nothing to flush"); return false; }
void PrePostProcessor::Stop() { Thread::Stop(); GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); for (NzbInfo* postJob : m_activeJobs) { if (postJob->GetPostInfo() && postJob->GetPostInfo()->GetPostThread()) { postJob->GetPostInfo()->GetPostThread()->Stop(); } } for (NzbInfo* nzbInfo : downloadQueue->GetQueue()) { if (nzbInfo->GetUnpackThread()) { ((DirectUnpack*)nzbInfo->GetUnpackThread())->Stop(downloadQueue, nzbInfo); } } }
/** * Reset the state of items after reloading from disk and * delete items which could not be resumed. * Also count the number of post-jobs. */ void PrePostProcessor::SanitisePostQueue() { GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); for (NzbInfo* nzbInfo : downloadQueue->GetQueue()) { PostInfo* postInfo = nzbInfo->GetPostInfo(); if (postInfo) { m_jobCount++; if (postInfo->GetStage() == PostInfo::ptExecutingScript || !FileSystem::DirectoryExists(nzbInfo->GetDestDir())) { postInfo->SetStage(PostInfo::ptFinished); } else { postInfo->SetStage(PostInfo::ptQueued); } } } }
void PrePostProcessor::CheckPostQueue() { GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); size_t countBefore = m_activeJobs.size(); CheckRequestPar(downloadQueue); CleanupJobs(downloadQueue); bool changed = m_activeJobs.size() != countBefore; bool allowPar; while (CanRunMoreJobs(&allowPar) && !IsStopped()) { NzbInfo* postJob = PickNextJob(downloadQueue, allowPar); if (!postJob) { break; } m_activeJobs.push_back(postJob); PostInfo* postInfo = postJob->GetPostInfo(); if (postInfo->GetStage() == PostInfo::ptQueued && (!g_Options->GetPausePostProcess() || postInfo->GetNzbInfo()->GetForcePriority())) { StartJob(downloadQueue, postInfo, allowPar); CheckRequestPar(downloadQueue); CleanupJobs(downloadQueue); changed = true; } } if (changed) { downloadQueue->Save(); UpdatePauseState(); } Util::SetStandByMode(m_activeJobs.empty()); }
bool Frontend::PrepareData() { if (IsRemoteMode()) { if (IsStopped()) { return false; } if (!RequestMessages() || ((m_summary || m_fileList) && !RequestFileList())) { const char* controlIp = !strcmp(g_Options->GetControlIp(), "0.0.0.0") ? "127.0.0.1" : g_Options->GetControlIp(); printf("\nUnable to send request to nzbget-server at %s (port %i) \n", controlIp, g_Options->GetControlPort()); Stop(); return false; } } else { if (m_summary) { m_currentDownloadSpeed = g_StatMeter->CalcCurrentDownloadSpeed(); m_pauseDownload = g_Options->GetPauseDownload(); m_downloadLimit = g_Options->GetDownloadRate(); m_threadCount = Thread::GetThreadCount(); g_StatMeter->CalcTotalStat(&m_upTimeSec, &m_dnTimeSec, &m_allBytes, &m_standBy); GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); m_postJobCount = 0; for (NzbInfo* nzbInfo : downloadQueue->GetQueue()) { m_postJobCount += nzbInfo->GetPostInfo() ? 1 : 0; } downloadQueue->CalcRemainingSize(&m_remainingSize, nullptr); } } return true; }
/** * Removes old entries from (recent) history */ void HistoryCoordinator::ServiceWork() { GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); time_t minTime = Util::CurrentTime() - g_Options->GetKeepHistory() * 60*60*24; bool changed = false; int index = 0; // traversing in a reverse order to delete items in order they were added to history // (just to produce the log-messages in a more logical order) for (HistoryList::reverse_iterator it = downloadQueue->GetHistory()->rbegin(); it != downloadQueue->GetHistory()->rend(); ) { HistoryInfo* historyInfo = (*it).get(); if (historyInfo->GetKind() != HistoryInfo::hkDup && historyInfo->GetTime() < minTime) { if (g_Options->GetDupeCheck() && historyInfo->GetKind() == HistoryInfo::hkNzb) { // replace history element HistoryHide(downloadQueue, historyInfo, index); index++; } else { if (historyInfo->GetKind() == HistoryInfo::hkNzb) { DeleteDiskFiles(historyInfo->GetNzbInfo()); } info("Collection %s removed from history", historyInfo->GetName()); downloadQueue->GetHistory()->erase(downloadQueue->GetHistory()->end() - 1 - index); } it = downloadQueue->GetHistory()->rbegin() + index; changed = true; } else { it++; index++; } } if (changed) { downloadQueue->HistoryChanged(); downloadQueue->Save(); } }
bool NCursesFrontend::EditQueue(DownloadQueue::EEditAction action, int offset) { int ID = 0; if (m_groupFiles) { GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); if (m_selectedQueueEntry >= 0 && m_selectedQueueEntry < (int)downloadQueue->GetQueue()->size()) { std::unique_ptr<NzbInfo>& nzbInfo = downloadQueue->GetQueue()->at(m_selectedQueueEntry); ID = nzbInfo->GetId(); if (action == DownloadQueue::eaFilePause) { if (nzbInfo->GetRemainingSize() == nzbInfo->GetPausedSize()) { action = DownloadQueue::eaFileResume; } else if (nzbInfo->GetPausedSize() == 0 && (nzbInfo->GetRemainingParCount() > 0) && !(m_lastPausePars && m_lastEditEntry == m_selectedQueueEntry)) { action = DownloadQueue::eaFilePauseExtraPars; m_lastPausePars = true; } else { action = DownloadQueue::eaFilePause; m_lastPausePars = false; } } } // map file-edit-actions to group-edit-actions DownloadQueue::EEditAction FileToGroupMap[] = { (DownloadQueue::EEditAction)0, DownloadQueue::eaGroupMoveOffset, DownloadQueue::eaGroupMoveTop, DownloadQueue::eaGroupMoveBottom, DownloadQueue::eaGroupPause, DownloadQueue::eaGroupResume, DownloadQueue::eaGroupDelete, DownloadQueue::eaGroupPauseAllPars, DownloadQueue::eaGroupPauseExtraPars }; action = FileToGroupMap[action]; } else { int fileNum = 0; GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); for (NzbInfo* nzbInfo : downloadQueue->GetQueue()) { for (FileInfo* fileInfo : nzbInfo->GetFileList()) { if (m_selectedQueueEntry == fileNum) { ID = fileInfo->GetId(); if (action == DownloadQueue::eaFilePause) { action = !fileInfo->GetPaused() ? DownloadQueue::eaFilePause : DownloadQueue::eaFileResume; } } fileNum++; } } } m_lastEditEntry = m_selectedQueueEntry; NeedUpdateData(); if (ID != 0) { return ServerEditQueue(action, offset, ID); } else { return false; } }
void WinConsole::UpdateTrayIcon() { if (!m_showTrayIcon) { return; } HICON hOldIcon = m_iconData->hIcon; char oldTip[200]; strncpy(oldTip, m_iconData->szTip, sizeof(m_iconData->szTip)); oldTip[200-1] = '\0'; if (g_Options->GetPauseDownload()) { m_iconData->hIcon = m_pausedIcon; strncpy(m_iconData->szTip, "NZBGet - paused", sizeof(m_iconData->szTip)); } else if (!g_StatMeter->GetStandBy()) { m_iconData->hIcon = m_workingIcon; BString<100> tip("NZBGet - downloading at %s", *Util::FormatSpeed(g_StatMeter->CalcCurrentDownloadSpeed())); strncpy(m_iconData->szTip, tip, sizeof(m_iconData->szTip)); } else { int postJobCount = 0; int urlCount = 0; { GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); for (NzbInfo* nzbInfo : downloadQueue->GetQueue()) { postJobCount += nzbInfo->GetPostInfo() ? 1 : 0; urlCount += nzbInfo->GetKind() == NzbInfo::nkUrl ? 1 : 0; } } if (postJobCount > 0) { m_iconData->hIcon = m_workingIcon; strncpy(m_iconData->szTip, "NZBGet - post-processing", sizeof(m_iconData->szTip)); } else if (urlCount > 0) { m_iconData->hIcon = m_workingIcon; strncpy(m_iconData->szTip, "NZBGet - fetching URLs", sizeof(m_iconData->szTip)); } else if (g_FeedCoordinator->HasActiveDownloads()) { m_iconData->hIcon = m_workingIcon; strncpy(m_iconData->szTip, "NZBGet - fetching feeds", sizeof(m_iconData->szTip)); } else { m_iconData->hIcon = m_idleIcon; strncpy(m_iconData->szTip, "NZBGet - idle", sizeof(m_iconData->szTip)); } } if (m_iconData->hIcon != hOldIcon || strcmp(oldTip, m_iconData->szTip)) { Shell_NotifyIcon(NIM_MODIFY, m_iconData); } }
void PrePostProcessor::WaitJobs() { debug("PrePostProcessor: waiting for jobs to complete"); // wait 5 seconds until all post-processing jobs gracefully finish time_t waitStart = Util::CurrentTime(); while (Util::CurrentTime() < waitStart + 5) { { GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); if (m_activeJobs.empty()) { break; } } CheckPostQueue(); usleep(200 * 1000); } // kill remaining post-processing jobs; not safe but we can't wait any longer { GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); for (NzbInfo* postJob : m_activeJobs) { if (postJob->GetPostInfo() && postJob->GetPostInfo()->GetPostThread()) { Thread* thread = postJob->GetPostInfo()->GetPostThread(); postJob->GetPostInfo()->SetPostThread(nullptr); warn("Terminating active post-process job for %s", postJob->GetName()); thread->Kill(); delete thread; } } } // wait 5 seconds until direct unpack threads gracefully finish waitStart = Util::CurrentTime(); while (Util::CurrentTime() < waitStart + 5) { { GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); if (std::find_if(downloadQueue->GetQueue()->begin(), downloadQueue->GetQueue()->end(), [](const std::unique_ptr<NzbInfo>& nzbInfo) { return nzbInfo->GetUnpackThread() != nullptr; }) == downloadQueue->GetQueue()->end()) { break; } } usleep(200 * 1000); } // disconnect remaining direct unpack jobs { GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); for (NzbInfo* nzbInfo : downloadQueue->GetQueue()) { nzbInfo->SetUnpackThread(nullptr); } } debug("PrePostProcessor: Jobs are completed"); }
void UrlCoordinator::UrlCompleted(UrlDownloader* urlDownloader) { debug("URL downloaded"); NzbInfo* nzbInfo = urlDownloader->GetNzbInfo(); const char* origname; if (urlDownloader->GetOriginalFilename()) { origname = urlDownloader->GetOriginalFilename(); } else { origname = FileSystem::BaseFileName(nzbInfo->GetUrl()); // TODO: decode URL escaping } CString filename = FileSystem::MakeValidFilename(origname); debug("Filename: [%s]", *filename); bool retry; { GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); // remove downloader from downloader list m_activeDownloads.erase(std::find(m_activeDownloads.begin(), m_activeDownloads.end(), urlDownloader)); nzbInfo->SetActiveDownloads(0); retry = urlDownloader->GetStatus() == WebDownloader::adRetry && !nzbInfo->GetDeleting(); if (nzbInfo->GetDeleting()) { nzbInfo->SetDeleteStatus(NzbInfo::dsManual); nzbInfo->SetUrlStatus(NzbInfo::lsNone); nzbInfo->SetDeleting(false); } else if (urlDownloader->GetStatus() == WebDownloader::adFinished) { nzbInfo->SetUrlStatus(NzbInfo::lsFinished); } else if (urlDownloader->GetStatus() == WebDownloader::adFailed) { nzbInfo->SetUrlStatus(NzbInfo::lsFailed); } else if (urlDownloader->GetStatus() == WebDownloader::adRetry) { nzbInfo->SetUrlStatus(NzbInfo::lsNone); } if (!retry) { DownloadQueue::Aspect aspect = {DownloadQueue::eaUrlCompleted, downloadQueue, nzbInfo, nullptr}; downloadQueue->Notify(&aspect); } } if (retry) { return; } if (nzbInfo->GetUrlStatus() == NzbInfo::lsFinished) { // add nzb-file to download queue Scanner::EAddStatus addStatus = g_Scanner->AddExternalFile( !Util::EmptyStr(nzbInfo->GetFilename()) ? nzbInfo->GetFilename() : *filename, !Util::EmptyStr(nzbInfo->GetCategory()) ? nzbInfo->GetCategory() : urlDownloader->GetCategory(), nzbInfo->GetPriority(), nzbInfo->GetDupeKey(), nzbInfo->GetDupeScore(), nzbInfo->GetDupeMode(), nzbInfo->GetParameters(), false, nzbInfo->GetAddUrlPaused(), nzbInfo, urlDownloader->GetOutputFilename(), nullptr, 0, nullptr); if (addStatus == Scanner::asSuccess) { // if scanner has successfully added nzb-file to queue, our pNZBInfo is // already removed from queue and destroyed return; } nzbInfo->SetUrlStatus(addStatus == Scanner::asFailed ? NzbInfo::lsScanFailed : NzbInfo::lsScanSkipped); } // the rest of function is only for failed URLs or for failed scans g_QueueScriptCoordinator->EnqueueScript(nzbInfo, QueueScriptCoordinator::qeUrlCompleted); std::unique_ptr<NzbInfo> oldNzbInfo; { GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); // delete URL from queue oldNzbInfo = downloadQueue->GetQueue()->Remove(nzbInfo); // add failed URL to history if (g_Options->GetKeepHistory() > 0 && nzbInfo->GetUrlStatus() != NzbInfo::lsFinished && !nzbInfo->GetAvoidHistory()) { std::unique_ptr<HistoryInfo> historyInfo = std::make_unique<HistoryInfo>(std::move(oldNzbInfo)); historyInfo->SetTime(Util::CurrentTime()); downloadQueue->GetHistory()->Add(std::move(historyInfo), true); downloadQueue->HistoryChanged(); } downloadQueue->Save(); } if (oldNzbInfo) { g_DiskState->DiscardFiles(oldNzbInfo.get()); } }
void PrePostProcessor::CheckPostQueue() { GuardedDownloadQueue downloadQueue = DownloadQueue::Guard(); if (!m_curJob && m_jobCount > 0) { m_curJob = GetNextJob(downloadQueue); } if (m_curJob) { PostInfo* postInfo = m_curJob->GetPostInfo(); if (!postInfo->GetWorking() && !IsNzbFileDownloading(m_curJob)) { #ifndef DISABLE_PARCHECK if (postInfo->GetRequestParCheck() && (postInfo->GetNzbInfo()->GetParStatus() <= NzbInfo::psSkipped || (postInfo->GetForceRepair() && !postInfo->GetNzbInfo()->GetParFull())) && g_Options->GetParCheck() != Options::pcManual) { postInfo->SetForceParFull(postInfo->GetNzbInfo()->GetParStatus() > NzbInfo::psSkipped); postInfo->GetNzbInfo()->SetParStatus(NzbInfo::psNone); postInfo->SetRequestParCheck(false); postInfo->SetStage(PostInfo::ptQueued); postInfo->GetNzbInfo()->GetScriptStatuses()->clear(); DeletePostThread(postInfo); } else if (postInfo->GetRequestParCheck() && postInfo->GetNzbInfo()->GetParStatus() <= NzbInfo::psSkipped && g_Options->GetParCheck() == Options::pcManual) { postInfo->SetRequestParCheck(false); postInfo->GetNzbInfo()->SetParStatus(NzbInfo::psManual); DeletePostThread(postInfo); if (!postInfo->GetNzbInfo()->GetFileList()->empty()) { postInfo->GetNzbInfo()->PrintMessage(Message::mkInfo, "Downloading all remaining files for manual par-check for %s", postInfo->GetNzbInfo()->GetName()); downloadQueue->EditEntry(postInfo->GetNzbInfo()->GetId(), DownloadQueue::eaGroupResume, 0, nullptr); postInfo->SetStage(PostInfo::ptFinished); } else { postInfo->GetNzbInfo()->PrintMessage(Message::mkInfo, "There are no par-files remain for download for %s", postInfo->GetNzbInfo()->GetName()); postInfo->SetStage(PostInfo::ptQueued); } } #endif if (postInfo->GetDeleted()) { postInfo->SetStage(PostInfo::ptFinished); } if (postInfo->GetStage() == PostInfo::ptQueued && (!g_Options->GetPausePostProcess() || postInfo->GetNzbInfo()->GetForcePriority())) { DeletePostThread(postInfo); StartJob(downloadQueue, postInfo); } else if (postInfo->GetStage() == PostInfo::ptFinished) { UpdatePauseState(false, nullptr); JobCompleted(downloadQueue, postInfo); } else if (!g_Options->GetPausePostProcess()) { error("Internal error: invalid state in post-processor"); // TODO: cancel (delete) current job } } } }