diff --git a/.github/workflows/ci_macos.yaml b/.github/workflows/ci_macos.yaml
index 4b2709516..0b60cf989 100644
--- a/.github/workflows/ci_macos.yaml
+++ b/.github/workflows/ci_macos.yaml
@@ -49,8 +49,10 @@ jobs:
- name: Setup ccache
uses: Chocobo1/setup-ccache-action@v1
with:
- store_cache: ${{ startsWith(github.ref, 'refs/heads/') }}
+ store_cache: ${{ github.ref == 'refs/heads/master' }}
update_packager_index: false
+ ccache_options: |
+ max_size=2G
- name: Install boost
run: |
@@ -136,8 +138,18 @@ jobs:
if [ "${{ matrix.qbt_gui }}" = "GUI=OFF" ]; then
appName="qbittorrent-nox"
fi
+ # package
pushd build
- macdeployqt "$appName.app" -dmg -no-strip
+ PACKAGE_RETRY=0
+ while [ "$PACKAGE_RETRY" -lt "3" ]; do
+ macdeployqt "$appName.app" -dmg -no-strip
+ if [ -f "$appName.dmg" ]; then
+ break
+ fi
+ sleep 5
+ PACKAGE_RETRY=$((PACKAGE_RETRY + 1))
+ echo "Retry $PACKAGE_RETRY..."
+ done
popd
# prepare upload folder
mkdir upload
diff --git a/.github/workflows/ci_ubuntu.yaml b/.github/workflows/ci_ubuntu.yaml
index 313275b07..406b3917a 100644
--- a/.github/workflows/ci_ubuntu.yaml
+++ b/.github/workflows/ci_ubuntu.yaml
@@ -39,7 +39,7 @@ jobs:
- name: Setup ccache
uses: Chocobo1/setup-ccache-action@v1
with:
- store_cache: ${{ startsWith(github.ref, 'refs/heads/') }}
+ store_cache: ${{ github.ref == 'refs/heads/master' }}
update_packager_index: false
ccache_options: |
max_size=2G
diff --git a/dist/unix/org.qbittorrent.qBittorrent.metainfo.xml b/dist/unix/org.qbittorrent.qBittorrent.metainfo.xml
index c6cfa3ba8..370ddabc0 100644
--- a/dist/unix/org.qbittorrent.qBittorrent.metainfo.xml
+++ b/dist/unix/org.qbittorrent.qBittorrent.metainfo.xml
@@ -33,19 +33,19 @@
Main window (General tab collapsed)
- https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_01.png
+ https://raw.githubusercontent.com/qbittorrent/qBittorrent-website/2741f2a90854604e268c6bba9e6859aad0103583/src/img/screenshots/linux/1.webp
Main window (General tab expanded)
- https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_03.png
+ https://raw.githubusercontent.com/qbittorrent/qBittorrent-website/2741f2a90854604e268c6bba9e6859aad0103583/src/img/screenshots/linux/2.webp
Options dialog
- https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_04.png
+ https://raw.githubusercontent.com/qbittorrent/qBittorrent-website/2741f2a90854604e268c6bba9e6859aad0103583/src/img/screenshots/linux/3.webp
Search engine
- https://alexpl.fedorapeople.org/AppData/qbittorrent/screens/qbittorrent_02.png
+ https://raw.githubusercontent.com/qbittorrent/qBittorrent-website/2741f2a90854604e268c6bba9e6859aad0103583/src/img/screenshots/linux/4.webp
sledgehammer999@qbittorrent.org
diff --git a/src/app/application.cpp b/src/app/application.cpp
index 0244e40f1..3026b69b1 100644
--- a/src/app/application.cpp
+++ b/src/app/application.cpp
@@ -258,6 +258,7 @@ Application::Application(int &argc, char **argv)
setAttribute(Qt::AA_UseHighDpiPixmaps, true); // opt-in to the high DPI pixmap support
#endif
setQuitOnLastWindowClosed(false);
+ setQuitLockEnabled(false);
QPixmapCache::setCacheLimit(PIXMAP_CACHE_SIZE);
#endif
diff --git a/src/base/bittorrent/torrentimpl.cpp b/src/base/bittorrent/torrentimpl.cpp
index 7cab602d7..fea7c3858 100644
--- a/src/base/bittorrent/torrentimpl.cpp
+++ b/src/base/bittorrent/torrentimpl.cpp
@@ -1519,7 +1519,17 @@ void TorrentImpl::forceRecheck()
// an incorrect one during the interval until the cached state is updated in a regular way.
m_nativeStatus.state = lt::torrent_status::checking_resume_data;
- m_hasMissingFiles = false;
+ if (m_hasMissingFiles)
+ {
+ m_hasMissingFiles = false;
+ if (!isPaused())
+ {
+ setAutoManaged(m_operatingMode == TorrentOperatingMode::AutoManaged);
+ if (m_operatingMode == TorrentOperatingMode::Forced)
+ m_nativeHandle.resume();
+ }
+ }
+
m_unchecked = false;
m_completedFiles.fill(false);
diff --git a/src/base/torrentfilter.h b/src/base/torrentfilter.h
index 3358ef380..4c49d904b 100644
--- a/src/base/torrentfilter.h
+++ b/src/base/torrentfilter.h
@@ -60,7 +60,9 @@ public:
StalledDownloading,
Checking,
Moving,
- Errored
+ Errored,
+
+ _Count
};
// These mean any permutation, including no category / tag.
diff --git a/src/gui/addnewtorrentdialog.cpp b/src/gui/addnewtorrentdialog.cpp
index 89133e084..a2d9d49db 100644
--- a/src/gui/addnewtorrentdialog.cpp
+++ b/src/gui/addnewtorrentdialog.cpp
@@ -159,7 +159,8 @@ namespace
delta.setY(0);
dialogGeometry.translate(delta);
- delta = screenGeometry.topLeft() - dialogGeometry.topLeft();
+ const QPoint frameOffset {10, 40};
+ delta = screenGeometry.topLeft() - dialogGeometry.topLeft() + frameOffset;
if (delta.x() < 0)
delta.setX(0);
if (delta.y() < 0)
diff --git a/src/gui/fspathedit_p.cpp b/src/gui/fspathedit_p.cpp
index 1e58002e3..ba6efec12 100644
--- a/src/gui/fspathedit_p.cpp
+++ b/src/gui/fspathedit_p.cpp
@@ -164,6 +164,7 @@ QValidator::State Private::FileSystemPathValidator::validate(QString &input, int
Private::FileLineEdit::FileLineEdit(QWidget *parent)
: QLineEdit(parent)
{
+ setCompleter(new QCompleter(this));
connect(this, &QLineEdit::textChanged, this, &FileLineEdit::validateText);
}
@@ -222,7 +223,7 @@ void Private::FileLineEdit::keyPressEvent(QKeyEvent *e)
if ((e->key() == Qt::Key_Space) && (e->modifiers() == Qt::CTRL))
{
- if (!m_completer)
+ if (!m_completerModel)
{
m_iconProvider = new QFileIconProvider;
m_iconProvider->setOptions(QFileIconProvider::DontUseCustomDirectoryIcons);
@@ -235,9 +236,7 @@ void Private::FileLineEdit::keyPressEvent(QKeyEvent *e)
| (m_completeDirectoriesOnly ? QDir::Dirs : QDir::AllEntries);
m_completerModel->setFilter(filters);
- m_completer = new QCompleter(this);
- m_completer->setModel(m_completerModel);
- setCompleter(m_completer);
+ completer()->setModel(m_completerModel);
}
m_completerModel->setRootPath(Path(text()).data());
@@ -261,8 +260,8 @@ void Private::FileLineEdit::contextMenuEvent(QContextMenuEvent *event)
void Private::FileLineEdit::showCompletionPopup()
{
- m_completer->setCompletionPrefix(text());
- m_completer->complete();
+ completer()->setCompletionPrefix(text());
+ completer()->complete();
}
void Private::FileLineEdit::validateText()
diff --git a/src/gui/fspathedit_p.h b/src/gui/fspathedit_p.h
index 153cf4b08..e52face0f 100644
--- a/src/gui/fspathedit_p.h
+++ b/src/gui/fspathedit_p.h
@@ -37,7 +37,6 @@
#include "base/pathfwd.h"
class QAction;
-class QCompleter;
class QContextMenuEvent;
class QFileIconProvider;
class QFileSystemModel;
@@ -141,7 +140,6 @@ namespace Private
static QString warningText(FileSystemPathValidator::TestResult result);
QFileSystemModel *m_completerModel = nullptr;
- QCompleter *m_completer = nullptr;
QAction *m_browseAction = nullptr;
QAction *m_warningAction = nullptr;
QFileIconProvider *m_iconProvider = nullptr;
diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp
index c7e15e40c..fb01833f1 100644
--- a/src/gui/mainwindow.cpp
+++ b/src/gui/mainwindow.cpp
@@ -781,8 +781,11 @@ void MainWindow::saveSplitterSettings() const
void MainWindow::cleanup()
{
- saveSettings();
- saveSplitterSettings();
+ if (!m_neverShown)
+ {
+ saveSettings();
+ saveSplitterSettings();
+ }
// delete RSSWidget explicitly to avoid crash in
// handleRSSUnreadCountUpdated() at application shutdown
diff --git a/src/gui/transferlistfilters/statusfilterwidget.cpp b/src/gui/transferlistfilters/statusfilterwidget.cpp
index 99b00af76..731b4fe52 100644
--- a/src/gui/transferlistfilters/statusfilterwidget.cpp
+++ b/src/gui/transferlistfilters/statusfilterwidget.cpp
@@ -95,7 +95,7 @@ StatusFilterWidget::StatusFilterWidget(QWidget *parent, TransferListWidget *tran
connect(pref, &Preferences::changed, this, &StatusFilterWidget::configure);
const int storedRow = pref->getTransSelFilter();
- if (item((storedRow < count()) ? storedRow : 0)->isHidden())
+ if (item(((storedRow >= 0) && (storedRow < count())) ? storedRow : 0)->isHidden())
setCurrentRow(TorrentFilter::All, QItemSelectionModel::SelectCurrent);
else
setCurrentRow(storedRow, QItemSelectionModel::SelectCurrent);
diff --git a/src/gui/transferlistwidget.cpp b/src/gui/transferlistwidget.cpp
index 38300d05c..ff76167f8 100644
--- a/src/gui/transferlistwidget.cpp
+++ b/src/gui/transferlistwidget.cpp
@@ -1330,9 +1330,10 @@ void TransferListWidget::applyFilter(const QString &name, const TransferListMode
m_sortFilterModel->setFilterRegularExpression(QRegularExpression(pattern, QRegularExpression::CaseInsensitiveOption));
}
-void TransferListWidget::applyStatusFilter(int f)
+void TransferListWidget::applyStatusFilter(const int filterIndex)
{
- m_sortFilterModel->setStatusFilter(static_cast(f));
+ const auto filterType = static_cast(filterIndex);
+ m_sortFilterModel->setStatusFilter(((filterType >= TorrentFilter::All) && (filterType < TorrentFilter::_Count)) ? filterType : TorrentFilter::All);
// Select first item if nothing is selected
if (selectionModel()->selectedRows(0).empty() && (m_sortFilterModel->rowCount() > 0))
{
diff --git a/src/gui/transferlistwidget.h b/src/gui/transferlistwidget.h
index ad9b0f37b..84a965d4e 100644
--- a/src/gui/transferlistwidget.h
+++ b/src/gui/transferlistwidget.h
@@ -93,7 +93,7 @@ public slots:
void previewSelectedTorrents();
void hideQueuePosColumn(bool hide);
void applyFilter(const QString &name, const TransferListModel::Column &type);
- void applyStatusFilter(int f);
+ void applyStatusFilter(int filterIndex);
void applyCategoryFilter(const QString &category);
void applyTagFilter(const QString &tag);
void applyTrackerFilterAll();
diff --git a/src/webui/www/package.json b/src/webui/www/package.json
index 6be44e273..e527fed26 100644
--- a/src/webui/www/package.json
+++ b/src/webui/www/package.json
@@ -10,8 +10,8 @@
"lint": "eslint private/*.html private/scripts/*.js private/views/*.html public/*.html public/scripts/*.js && stylelint **/*.css && html-validate private public"
},
"devDependencies": {
- "eslint": "*",
- "eslint-plugin-html": "*",
+ "eslint": "^8",
+ "eslint-plugin-html": "^8",
"html-validate": "*",
"js-beautify": "*",
"prettier": "*",
diff --git a/src/webui/www/private/scripts/prop-trackers.js b/src/webui/www/private/scripts/prop-trackers.js
index e1c4ddaa0..d808c5de9 100644
--- a/src/webui/www/private/scripts/prop-trackers.js
+++ b/src/webui/www/private/scripts/prop-trackers.js
@@ -100,7 +100,7 @@ window.qBittorrent.PropTrackers = (function() {
tier: (tracker.tier >= 0) ? tracker.tier : "",
url: tracker.url,
status: status,
- peers: tracker.num_peers,
+ peers: (tracker.num_peers >= 0) ? tracker.num_peers : "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]",
seeds: (tracker.num_seeds >= 0) ? tracker.num_seeds : "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]",
leeches: (tracker.num_leeches >= 0) ? tracker.num_leeches : "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]",
downloaded: (tracker.num_downloaded >= 0) ? tracker.num_downloaded : "QBT_TR(N/A)QBT_TR[CONTEXT=TrackerListWidget]",