예제 #1
0
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;
}
예제 #2
0
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);
	}
}
예제 #3
0
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();
}
예제 #4
0
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;
}
예제 #5
0
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);
		}
	}
}
예제 #6
0
/**
 * 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);
			}
		}
	}
}
예제 #7
0
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());
}
예제 #8
0
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;
}
예제 #9
0
/**
 * 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();
	}
}
예제 #10
0
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;
	}
}
예제 #11
0
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);
	}
}
예제 #12
0
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");
}
예제 #13
0
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());
	}
}
예제 #14
0
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
			}
		}
	}
}