mirror of
https://github.com/qbittorrent/qBittorrent.git
synced 2024-10-22 02:36:15 +03:00
commit
742bc410f4
11 changed files with 99 additions and 30 deletions
|
@ -425,6 +425,8 @@ Path TorrentImpl::savePath() const
|
||||||
void TorrentImpl::setSavePath(const Path &path)
|
void TorrentImpl::setSavePath(const Path &path)
|
||||||
{
|
{
|
||||||
Q_ASSERT(!isAutoTMMEnabled());
|
Q_ASSERT(!isAutoTMMEnabled());
|
||||||
|
if (Q_UNLIKELY(isAutoTMMEnabled()))
|
||||||
|
return;
|
||||||
|
|
||||||
const Path basePath = m_session->useCategoryPathsInManualMode()
|
const Path basePath = m_session->useCategoryPathsInManualMode()
|
||||||
? m_session->categorySavePath(category()) : m_session->savePath();
|
? m_session->categorySavePath(category()) : m_session->savePath();
|
||||||
|
@ -452,6 +454,8 @@ Path TorrentImpl::downloadPath() const
|
||||||
void TorrentImpl::setDownloadPath(const Path &path)
|
void TorrentImpl::setDownloadPath(const Path &path)
|
||||||
{
|
{
|
||||||
Q_ASSERT(!isAutoTMMEnabled());
|
Q_ASSERT(!isAutoTMMEnabled());
|
||||||
|
if (Q_UNLIKELY(isAutoTMMEnabled()))
|
||||||
|
return;
|
||||||
|
|
||||||
const Path basePath = m_session->useCategoryPathsInManualMode()
|
const Path basePath = m_session->useCategoryPathsInManualMode()
|
||||||
? m_session->categoryDownloadPath(category()) : m_session->downloadPath();
|
? m_session->categoryDownloadPath(category()) : m_session->downloadPath();
|
||||||
|
@ -1364,11 +1368,13 @@ QBitArray TorrentImpl::pieces() const
|
||||||
|
|
||||||
QBitArray TorrentImpl::downloadingPieces() const
|
QBitArray TorrentImpl::downloadingPieces() const
|
||||||
{
|
{
|
||||||
QBitArray result(piecesCount());
|
if (!hasMetadata())
|
||||||
|
return {};
|
||||||
|
|
||||||
std::vector<lt::partial_piece_info> queue;
|
std::vector<lt::partial_piece_info> queue;
|
||||||
m_nativeHandle.get_download_queue(queue);
|
m_nativeHandle.get_download_queue(queue);
|
||||||
|
|
||||||
|
QBitArray result {piecesCount()};
|
||||||
for (const lt::partial_piece_info &info : queue)
|
for (const lt::partial_piece_info &info : queue)
|
||||||
result.setBit(LT::toUnderlyingType(info.piece_index));
|
result.setBit(LT::toUnderlyingType(info.piece_index));
|
||||||
|
|
||||||
|
@ -1821,8 +1827,17 @@ void TorrentImpl::moveStorage(const Path &newPath, const MoveStorageContext cont
|
||||||
{
|
{
|
||||||
if (!hasMetadata())
|
if (!hasMetadata())
|
||||||
{
|
{
|
||||||
m_savePath = newPath;
|
if (context == MoveStorageContext::ChangeSavePath)
|
||||||
m_session->handleTorrentSavePathChanged(this);
|
{
|
||||||
|
m_savePath = newPath;
|
||||||
|
m_session->handleTorrentSavePathChanged(this);
|
||||||
|
}
|
||||||
|
else if (context == MoveStorageContext::ChangeDownloadPath)
|
||||||
|
{
|
||||||
|
m_downloadPath = newPath;
|
||||||
|
m_session->handleTorrentSavePathChanged(this);
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
// Disguise as Firefox to avoid web server banning
|
// Disguise as Firefox to avoid web server banning
|
||||||
const char DEFAULT_USER_AGENT[] = "Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0";
|
const char DEFAULT_USER_AGENT[] = "Mozilla/5.0 (X11; Linux x86_64; rv:125.0) Gecko/20100101 Firefox/125.0";
|
||||||
}
|
}
|
||||||
|
|
||||||
class Net::DownloadManager::NetworkCookieJar final : public QNetworkCookieJar
|
class Net::DownloadManager::NetworkCookieJar final : public QNetworkCookieJar
|
||||||
|
|
|
@ -56,6 +56,19 @@
|
||||||
#include "gui/macutilities.h"
|
#include "gui/macutilities.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
QList<QPersistentModelIndex> toPersistentIndexes(const QModelIndexList &indexes)
|
||||||
|
{
|
||||||
|
QList<QPersistentModelIndex> persistentIndexes;
|
||||||
|
persistentIndexes.reserve(indexes.size());
|
||||||
|
for (const QModelIndex &index : indexes)
|
||||||
|
persistentIndexes.append(index);
|
||||||
|
|
||||||
|
return persistentIndexes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TorrentContentWidget::TorrentContentWidget(QWidget *parent)
|
TorrentContentWidget::TorrentContentWidget(QWidget *parent)
|
||||||
: QTreeView(parent)
|
: QTreeView(parent)
|
||||||
{
|
{
|
||||||
|
@ -219,9 +232,9 @@ void TorrentContentWidget::keyPressEvent(QKeyEvent *event)
|
||||||
|
|
||||||
const Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked)
|
const Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked)
|
||||||
? Qt::Unchecked : Qt::Checked;
|
? Qt::Unchecked : Qt::Checked;
|
||||||
const QModelIndexList selection = selectionModel()->selectedRows(TorrentContentModelItem::COL_NAME);
|
const QList<QPersistentModelIndex> selection = toPersistentIndexes(selectionModel()->selectedRows(TorrentContentModelItem::COL_NAME));
|
||||||
|
|
||||||
for (const QModelIndex &index : selection)
|
for (const QPersistentModelIndex &index : selection)
|
||||||
model()->setData(index, state, Qt::CheckStateRole);
|
model()->setData(index, state, Qt::CheckStateRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,10 +261,10 @@ void TorrentContentWidget::renameSelectedFile()
|
||||||
|
|
||||||
void TorrentContentWidget::applyPriorities(const BitTorrent::DownloadPriority priority)
|
void TorrentContentWidget::applyPriorities(const BitTorrent::DownloadPriority priority)
|
||||||
{
|
{
|
||||||
const QModelIndexList selectedRows = selectionModel()->selectedRows(0);
|
const QList<QPersistentModelIndex> selectedRows = toPersistentIndexes(selectionModel()->selectedRows(Priority));
|
||||||
for (const QModelIndex &index : selectedRows)
|
for (const QPersistentModelIndex &index : selectedRows)
|
||||||
{
|
{
|
||||||
model()->setData(index.sibling(index.row(), Priority), static_cast<int>(priority));
|
model()->setData(index, static_cast<int>(priority));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +274,7 @@ void TorrentContentWidget::applyPrioritiesByOrder()
|
||||||
// a download priority that will apply to each item. The number of groups depends on how
|
// a download priority that will apply to each item. The number of groups depends on how
|
||||||
// many "download priority" are available to be assigned
|
// many "download priority" are available to be assigned
|
||||||
|
|
||||||
const QModelIndexList selectedRows = selectionModel()->selectedRows(0);
|
const QList<QPersistentModelIndex> selectedRows = toPersistentIndexes(selectionModel()->selectedRows(Priority));
|
||||||
|
|
||||||
const qsizetype priorityGroups = 3;
|
const qsizetype priorityGroups = 3;
|
||||||
const auto priorityGroupSize = std::max<qsizetype>((selectedRows.length() / priorityGroups), 1);
|
const auto priorityGroupSize = std::max<qsizetype>((selectedRows.length() / priorityGroups), 1);
|
||||||
|
@ -283,8 +296,8 @@ void TorrentContentWidget::applyPrioritiesByOrder()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QModelIndex &index = selectedRows[i];
|
const QPersistentModelIndex &index = selectedRows[i];
|
||||||
model()->setData(index.sibling(index.row(), Priority), static_cast<int>(priority));
|
model()->setData(index, static_cast<int>(priority));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2023 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2023-2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -37,6 +37,7 @@
|
||||||
#include "base/global.h"
|
#include "base/global.h"
|
||||||
#include "autoexpandabledialog.h"
|
#include "autoexpandabledialog.h"
|
||||||
#include "flowlayout.h"
|
#include "flowlayout.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
#include "ui_torrenttagsdialog.h"
|
#include "ui_torrenttagsdialog.h"
|
||||||
|
|
||||||
|
@ -52,10 +53,10 @@ TorrentTagsDialog::TorrentTagsDialog(const TagSet &initialTags, QWidget *parent)
|
||||||
connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
connect(m_ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||||
connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
connect(m_ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
|
||||||
auto *tagsLayout = new FlowLayout(m_ui->scrollArea);
|
auto *tagsLayout = new FlowLayout(m_ui->scrollArea->widget());
|
||||||
for (const QString &tag : asConst(initialTags.united(BitTorrent::Session::instance()->tags())))
|
for (const QString &tag : asConst(initialTags.united(BitTorrent::Session::instance()->tags())))
|
||||||
{
|
{
|
||||||
auto *tagWidget = new QCheckBox(tag);
|
auto *tagWidget = new QCheckBox(Utils::Gui::tagToWidgetText(tag));
|
||||||
if (initialTags.contains(tag))
|
if (initialTags.contains(tag))
|
||||||
tagWidget->setChecked(true);
|
tagWidget->setChecked(true);
|
||||||
tagsLayout->addWidget(tagWidget);
|
tagsLayout->addWidget(tagWidget);
|
||||||
|
@ -78,12 +79,12 @@ TorrentTagsDialog::~TorrentTagsDialog()
|
||||||
TagSet TorrentTagsDialog::tags() const
|
TagSet TorrentTagsDialog::tags() const
|
||||||
{
|
{
|
||||||
TagSet tags;
|
TagSet tags;
|
||||||
auto *layout = m_ui->scrollArea->layout();
|
auto *layout = m_ui->scrollArea->widget()->layout();
|
||||||
for (int i = 0; i < (layout->count() - 1); ++i)
|
for (int i = 0; i < (layout->count() - 1); ++i)
|
||||||
{
|
{
|
||||||
const auto *tagWidget = static_cast<QCheckBox *>(layout->itemAt(i)->widget());
|
const auto *tagWidget = static_cast<QCheckBox *>(layout->itemAt(i)->widget());
|
||||||
if (tagWidget->isChecked())
|
if (tagWidget->isChecked())
|
||||||
tags.insert(tagWidget->text());
|
tags.insert(Utils::Gui::widgetTextToTag(tagWidget->text()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return tags;
|
return tags;
|
||||||
|
@ -111,9 +112,9 @@ void TorrentTagsDialog::addNewTag()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto *layout = m_ui->scrollArea->layout();
|
auto *layout = m_ui->scrollArea->widget()->layout();
|
||||||
auto *btn = layout->takeAt(layout->count() - 1);
|
auto *btn = layout->takeAt(layout->count() - 1);
|
||||||
auto *tagWidget = new QCheckBox(tag);
|
auto *tagWidget = new QCheckBox(Utils::Gui::tagToWidgetText(tag));
|
||||||
tagWidget->setChecked(true);
|
tagWidget->setChecked(true);
|
||||||
layout->addWidget(tagWidget);
|
layout->addWidget(tagWidget);
|
||||||
layout->addItem(btn);
|
layout->addItem(btn);
|
||||||
|
|
|
@ -235,10 +235,7 @@ void StatusFilterWidget::applyFilter(int row)
|
||||||
|
|
||||||
void StatusFilterWidget::handleTorrentsLoaded(const QVector<BitTorrent::Torrent *> &torrents)
|
void StatusFilterWidget::handleTorrentsLoaded(const QVector<BitTorrent::Torrent *> &torrents)
|
||||||
{
|
{
|
||||||
for (const BitTorrent::Torrent *torrent : torrents)
|
update(torrents);
|
||||||
updateTorrentStatus(torrent);
|
|
||||||
|
|
||||||
updateTexts();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatusFilterWidget::torrentAboutToBeDeleted(BitTorrent::Torrent *const torrent)
|
void StatusFilterWidget::torrentAboutToBeDeleted(BitTorrent::Torrent *const torrent)
|
||||||
|
@ -273,6 +270,12 @@ void StatusFilterWidget::torrentAboutToBeDeleted(BitTorrent::Torrent *const torr
|
||||||
m_nbStalled = m_nbStalledUploading + m_nbStalledDownloading;
|
m_nbStalled = m_nbStalledUploading + m_nbStalledDownloading;
|
||||||
|
|
||||||
updateTexts();
|
updateTexts();
|
||||||
|
|
||||||
|
if (Preferences::instance()->getHideZeroStatusFilters())
|
||||||
|
{
|
||||||
|
hideZeroItems();
|
||||||
|
updateGeometry();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StatusFilterWidget::configure()
|
void StatusFilterWidget::configure()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
|
* Copyright (C) 2023-2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
* Copyright (C) 2006 Christophe Dumez <chris@qbittorrent.org>
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -1191,7 +1192,7 @@ void TransferListWidget::displayListMenu()
|
||||||
|
|
||||||
for (const QString &tag : asConst(tags))
|
for (const QString &tag : asConst(tags))
|
||||||
{
|
{
|
||||||
auto *action = new TriStateAction(tag, tagsMenu);
|
auto *action = new TriStateAction(Utils::Gui::tagToWidgetText(tag), tagsMenu);
|
||||||
action->setCloseOnInteraction(false);
|
action->setCloseOnInteraction(false);
|
||||||
|
|
||||||
const Qt::CheckState initialState = tagsInAll.contains(tag) ? Qt::Checked
|
const Qt::CheckState initialState = tagsInAll.contains(tag) ? Qt::Checked
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
|
* Copyright (C) 2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2017 Mike Tzou
|
* Copyright (C) 2017 Mike Tzou
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -218,3 +219,29 @@ void Utils::Gui::openFolderSelect(const Path &path)
|
||||||
openPath(path.parentPath());
|
openPath(path.parentPath());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Utils::Gui::tagToWidgetText(const QString &tag)
|
||||||
|
{
|
||||||
|
return QString(tag).replace(u'&', u"&&"_s);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Utils::Gui::widgetTextToTag(const QString &text)
|
||||||
|
{
|
||||||
|
// replace pairs of '&' with single '&' and remove non-paired occurrences of '&'
|
||||||
|
QString cleanedText;
|
||||||
|
cleanedText.reserve(text.size());
|
||||||
|
bool amp = false;
|
||||||
|
for (const QChar c : text)
|
||||||
|
{
|
||||||
|
if (c == u'&')
|
||||||
|
{
|
||||||
|
amp = !amp;
|
||||||
|
if (amp)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanedText.append(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cleanedText;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
|
* Copyright (C) 2024 Vladimir Golovnev <glassez@yandex.ru>
|
||||||
* Copyright (C) 2017 Mike Tzou
|
* Copyright (C) 2017 Mike Tzou
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or
|
* This program is free software; you can redistribute it and/or
|
||||||
|
@ -34,6 +35,7 @@ class QIcon;
|
||||||
class QPixmap;
|
class QPixmap;
|
||||||
class QPoint;
|
class QPoint;
|
||||||
class QSize;
|
class QSize;
|
||||||
|
class QString;
|
||||||
class QWidget;
|
class QWidget;
|
||||||
|
|
||||||
namespace Utils::Gui
|
namespace Utils::Gui
|
||||||
|
@ -51,4 +53,7 @@ namespace Utils::Gui
|
||||||
|
|
||||||
void openPath(const Path &path);
|
void openPath(const Path &path);
|
||||||
void openFolderSelect(const Path &path);
|
void openFolderSelect(const Path &path);
|
||||||
|
|
||||||
|
QString tagToWidgetText(const QString &tag);
|
||||||
|
QString widgetTextToTag(const QString &text);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#VERSION: 1.43
|
#VERSION: 1.44
|
||||||
|
|
||||||
# Author:
|
# Author:
|
||||||
# Christophe DUMEZ (chris@qbittorrent.org)
|
# Christophe DUMEZ (chris@qbittorrent.org)
|
||||||
|
@ -40,7 +40,7 @@ import urllib.parse
|
||||||
import urllib.request
|
import urllib.request
|
||||||
|
|
||||||
# Some sites blocks default python User-agent
|
# Some sites blocks default python User-agent
|
||||||
user_agent = 'Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0'
|
user_agent = 'Mozilla/5.0 (X11; Linux x86_64; rv:125.0) Gecko/20100101 Firefox/125.0'
|
||||||
headers = {'User-Agent': user_agent}
|
headers = {'User-Agent': user_agent}
|
||||||
# SOCKS5 Proxy support
|
# SOCKS5 Proxy support
|
||||||
if "sock_proxy" in os.environ and len(os.environ["sock_proxy"].strip()) > 0:
|
if "sock_proxy" in os.environ and len(os.environ["sock_proxy"].strip()) > 0:
|
||||||
|
|
|
@ -670,6 +670,7 @@ window.addEvent('load', function() {
|
||||||
torrentsTable.clear();
|
torrentsTable.clear();
|
||||||
category_list = {};
|
category_list = {};
|
||||||
tagList = {};
|
tagList = {};
|
||||||
|
trackerList.clear();
|
||||||
}
|
}
|
||||||
if (response['rid']) {
|
if (response['rid']) {
|
||||||
syncMainDataLastResponseId = response['rid'];
|
syncMainDataLastResponseId = response['rid'];
|
||||||
|
|
|
@ -597,6 +597,9 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
|
||||||
rulesList[rule].torrentParams.save_path = $('saveToText').value;
|
rulesList[rule].torrentParams.save_path = $('saveToText').value;
|
||||||
rulesList[rule].torrentParams.use_auto_tmm = false;
|
rulesList[rule].torrentParams.use_auto_tmm = false;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
rulesList[rule].torrentParams.save_path = "";
|
||||||
|
}
|
||||||
|
|
||||||
switch ($('addPausedCombobox').value) {
|
switch ($('addPausedCombobox').value) {
|
||||||
case 'default':
|
case 'default':
|
||||||
|
@ -746,13 +749,13 @@ Supports the formats: S01E01, 1x1, 2017.12.31 and 31.12.2017 (Date formats also
|
||||||
$('lastMatchText').textContent = 'QBT_TR(Last Match: Unknown)QBT_TR[CONTEXT=AutomatedRssDownloader]';
|
$('lastMatchText').textContent = 'QBT_TR(Last Match: Unknown)QBT_TR[CONTEXT=AutomatedRssDownloader]';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rulesList[ruleName].torrentParams.stopped === null)
|
if ((rulesList[ruleName].torrentParams.stopped === undefined) || (rulesList[ruleName].torrentParams.stopped === null))
|
||||||
$('addPausedCombobox').value = 'default';
|
$("addStoppedCombobox").value = "default";
|
||||||
else
|
else
|
||||||
$('addPausedCombobox').value = rulesList[ruleName].torrentParams.stopped ? 'always' : 'never';
|
$('addPausedCombobox').value = rulesList[ruleName].torrentParams.stopped ? 'always' : 'never';
|
||||||
|
|
||||||
if (rulesList[ruleName].torrentParams.content_layout === null)
|
if ((rulesList[ruleName].torrentParams.content_layout === undefined) || (rulesList[ruleName].torrentParams.content_layout === null))
|
||||||
$('contentLayoutCombobox').value = 'Default';
|
$("contentLayoutCombobox").value = "Default";
|
||||||
else
|
else
|
||||||
$('contentLayoutCombobox').value = rulesList[ruleName].torrentParams.content_layout;
|
$('contentLayoutCombobox').value = rulesList[ruleName].torrentParams.content_layout;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue