mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-01-24 13:34:27 +00:00
parent
cecf2d28e6
commit
b8cd614775
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2017 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2017-2023 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
|
||||||
@ -133,6 +133,8 @@ AutoDownloader::AutoDownloader()
|
|||||||
|
|
||||||
load();
|
load();
|
||||||
|
|
||||||
|
connect(Session::instance(), &Session::feedURLChanged, this, &AutoDownloader::handleFeedURLChanged);
|
||||||
|
|
||||||
m_processingTimer->setSingleShot(true);
|
m_processingTimer->setSingleShot(true);
|
||||||
connect(m_processingTimer, &QTimer::timeout, this, &AutoDownloader::process);
|
connect(m_processingTimer, &QTimer::timeout, this, &AutoDownloader::process);
|
||||||
|
|
||||||
@ -331,22 +333,28 @@ void AutoDownloader::setDownloadRepacks(const bool enabled)
|
|||||||
|
|
||||||
void AutoDownloader::process()
|
void AutoDownloader::process()
|
||||||
{
|
{
|
||||||
if (m_processingQueue.isEmpty()) return; // processing was disabled
|
if (m_processingQueue.isEmpty()) // processing was disabled
|
||||||
|
return;
|
||||||
|
|
||||||
processJob(m_processingQueue.takeFirst());
|
processJob(m_processingQueue.takeFirst());
|
||||||
if (!m_processingQueue.isEmpty())
|
if (!m_processingQueue.isEmpty())
|
||||||
|
{
|
||||||
// Schedule to process the next torrent (if any)
|
// Schedule to process the next torrent (if any)
|
||||||
m_processingTimer->start();
|
m_processingTimer->start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoDownloader::handleTorrentDownloadFinished(const QString &url)
|
void AutoDownloader::handleTorrentDownloadFinished(const QString &url)
|
||||||
{
|
{
|
||||||
const auto job = m_waitingJobs.take(url);
|
const auto job = m_waitingJobs.take(url);
|
||||||
if (!job) return;
|
if (!job)
|
||||||
|
return;
|
||||||
|
|
||||||
if (Feed *feed = Session::instance()->feedByURL(job->feedURL))
|
if (Feed *feed = Session::instance()->feedByURL(job->feedURL))
|
||||||
|
{
|
||||||
if (Article *article = feed->articleByGUID(job->articleData.value(Article::KeyId).toString()))
|
if (Article *article = feed->articleByGUID(job->articleData.value(Article::KeyId).toString()))
|
||||||
article->markAsRead();
|
article->markAsRead();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoDownloader::handleTorrentDownloadFailed(const QString &url)
|
void AutoDownloader::handleTorrentDownloadFailed(const QString &url)
|
||||||
@ -361,6 +369,34 @@ void AutoDownloader::handleNewArticle(const Article *article)
|
|||||||
addJobForArticle(article);
|
addJobForArticle(article);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AutoDownloader::handleFeedURLChanged(Feed *feed, const QString &oldURL)
|
||||||
|
{
|
||||||
|
for (AutoDownloadRule &rule : m_rules)
|
||||||
|
{
|
||||||
|
if (const auto i = rule.feedURLs().indexOf(oldURL); i >= 0)
|
||||||
|
{
|
||||||
|
auto feedURLs = rule.feedURLs();
|
||||||
|
feedURLs.replace(i, feed->url());
|
||||||
|
rule.setFeedURLs(feedURLs);
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (QSharedPointer<ProcessingJob> job : asConst(m_processingQueue))
|
||||||
|
{
|
||||||
|
if (job->feedURL == oldURL)
|
||||||
|
job->feedURL = feed->url();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (QSharedPointer<ProcessingJob> job : asConst(m_waitingJobs))
|
||||||
|
{
|
||||||
|
if (job->feedURL == oldURL)
|
||||||
|
job->feedURL = feed->url();
|
||||||
|
}
|
||||||
|
|
||||||
|
store();
|
||||||
|
}
|
||||||
|
|
||||||
void AutoDownloader::setRule_impl(const AutoDownloadRule &rule)
|
void AutoDownloader::setRule_impl(const AutoDownloadRule &rule)
|
||||||
{
|
{
|
||||||
m_rules.insert(rule.name(), rule);
|
m_rules.insert(rule.name(), rule);
|
||||||
@ -369,9 +405,10 @@ void AutoDownloader::setRule_impl(const AutoDownloadRule &rule)
|
|||||||
void AutoDownloader::addJobForArticle(const Article *article)
|
void AutoDownloader::addJobForArticle(const Article *article)
|
||||||
{
|
{
|
||||||
const QString torrentURL = article->torrentUrl();
|
const QString torrentURL = article->torrentUrl();
|
||||||
if (m_waitingJobs.contains(torrentURL)) return;
|
if (m_waitingJobs.contains(torrentURL))
|
||||||
|
return;
|
||||||
|
|
||||||
QSharedPointer<ProcessingJob> job(new ProcessingJob);
|
auto job = QSharedPointer<ProcessingJob>::create();
|
||||||
job->feedURL = article->feed()->url();
|
job->feedURL = article->feed()->url();
|
||||||
job->articleData = article->data();
|
job->articleData = article->data();
|
||||||
m_processingQueue.append(job);
|
m_processingQueue.append(job);
|
||||||
@ -383,9 +420,12 @@ void AutoDownloader::processJob(const QSharedPointer<ProcessingJob> &job)
|
|||||||
{
|
{
|
||||||
for (AutoDownloadRule &rule : m_rules)
|
for (AutoDownloadRule &rule : m_rules)
|
||||||
{
|
{
|
||||||
if (!rule.isEnabled()) continue;
|
if (!rule.isEnabled())
|
||||||
if (!rule.feedURLs().contains(job->feedURL)) continue;
|
continue;
|
||||||
if (!rule.accepts(job->articleData)) continue;
|
if (!rule.feedURLs().contains(job->feedURL))
|
||||||
|
continue;
|
||||||
|
if (!rule.accepts(job->articleData))
|
||||||
|
continue;
|
||||||
|
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
storeDeferred();
|
storeDeferred();
|
||||||
@ -423,12 +463,18 @@ void AutoDownloader::load()
|
|||||||
QFile rulesFile {(m_fileStorage->storageDir() / Path(RULES_FILE_NAME)).data()};
|
QFile rulesFile {(m_fileStorage->storageDir() / Path(RULES_FILE_NAME)).data()};
|
||||||
|
|
||||||
if (!rulesFile.exists())
|
if (!rulesFile.exists())
|
||||||
|
{
|
||||||
loadRulesLegacy();
|
loadRulesLegacy();
|
||||||
|
}
|
||||||
else if (rulesFile.open(QFile::ReadOnly))
|
else if (rulesFile.open(QFile::ReadOnly))
|
||||||
|
{
|
||||||
loadRules(rulesFile.readAll());
|
loadRules(rulesFile.readAll());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LogMsg(tr("Couldn't read RSS AutoDownloader rules from %1. Error: %2")
|
LogMsg(tr("Couldn't read RSS AutoDownloader rules from %1. Error: %2")
|
||||||
.arg(rulesFile.fileName(), rulesFile.errorString()), Log::CRITICAL);
|
.arg(rulesFile.fileName(), rulesFile.errorString()), Log::CRITICAL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AutoDownloader::loadRules(const QByteArray &data)
|
void AutoDownloader::loadRules(const QByteArray &data)
|
||||||
@ -442,7 +488,7 @@ void AutoDownloader::loadRules(const QByteArray &data)
|
|||||||
catch (const ParsingError &error)
|
catch (const ParsingError &error)
|
||||||
{
|
{
|
||||||
LogMsg(tr("Couldn't load RSS AutoDownloader rules. Reason: %1")
|
LogMsg(tr("Couldn't load RSS AutoDownloader rules. Reason: %1")
|
||||||
.arg(error.message()), Log::CRITICAL);
|
.arg(error.message()), Log::CRITICAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,7 +506,8 @@ void AutoDownloader::loadRulesLegacy()
|
|||||||
|
|
||||||
void AutoDownloader::store()
|
void AutoDownloader::store()
|
||||||
{
|
{
|
||||||
if (!m_dirty) return;
|
if (!m_dirty)
|
||||||
|
return;
|
||||||
|
|
||||||
m_dirty = false;
|
m_dirty = false;
|
||||||
m_savingTimer.stop();
|
m_savingTimer.stop();
|
||||||
@ -486,7 +533,8 @@ bool AutoDownloader::isProcessingEnabled() const
|
|||||||
void AutoDownloader::resetProcessingQueue()
|
void AutoDownloader::resetProcessingQueue()
|
||||||
{
|
{
|
||||||
m_processingQueue.clear();
|
m_processingQueue.clear();
|
||||||
if (!isProcessingEnabled()) return;
|
if (!isProcessingEnabled())
|
||||||
|
return;
|
||||||
|
|
||||||
for (Article *article : asConst(Session::instance()->rootFolder()->articles()))
|
for (Article *article : asConst(Session::instance()->rootFolder()->articles()))
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Bittorrent Client using Qt and libtorrent.
|
* Bittorrent Client using Qt and libtorrent.
|
||||||
* Copyright (C) 2017 Vladimir Golovnev <glassez@yandex.ru>
|
* Copyright (C) 2017-2023 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
|
||||||
@ -113,6 +113,7 @@ namespace RSS
|
|||||||
void handleTorrentDownloadFinished(const QString &url);
|
void handleTorrentDownloadFinished(const QString &url);
|
||||||
void handleTorrentDownloadFailed(const QString &url);
|
void handleTorrentDownloadFailed(const QString &url);
|
||||||
void handleNewArticle(const Article *article);
|
void handleNewArticle(const Article *article);
|
||||||
|
void handleFeedURLChanged(Feed *feed, const QString &oldURL);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void timerEvent(QTimerEvent *event) override;
|
void timerEvent(QTimerEvent *event) override;
|
||||||
|
@ -455,6 +455,13 @@ Path Feed::iconPath() const
|
|||||||
return m_iconPath;
|
return m_iconPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Feed::setURL(const QString &url)
|
||||||
|
{
|
||||||
|
const QString oldURL = m_url;
|
||||||
|
m_url = url;
|
||||||
|
emit urlChanged(oldURL);
|
||||||
|
}
|
||||||
|
|
||||||
QJsonValue Feed::toJsonValue(const bool withData) const
|
QJsonValue Feed::toJsonValue(const bool withData) const
|
||||||
{
|
{
|
||||||
QJsonObject jsonObj;
|
QJsonObject jsonObj;
|
||||||
|
@ -91,6 +91,7 @@ namespace RSS
|
|||||||
void iconLoaded(Feed *feed = nullptr);
|
void iconLoaded(Feed *feed = nullptr);
|
||||||
void titleChanged(Feed *feed = nullptr);
|
void titleChanged(Feed *feed = nullptr);
|
||||||
void stateChanged(Feed *feed = nullptr);
|
void stateChanged(Feed *feed = nullptr);
|
||||||
|
void urlChanged(const QString &oldURL);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleSessionProcessingEnabledChanged(bool enabled);
|
void handleSessionProcessingEnabledChanged(bool enabled);
|
||||||
@ -113,12 +114,13 @@ namespace RSS
|
|||||||
void decreaseUnreadCount();
|
void decreaseUnreadCount();
|
||||||
void downloadIcon();
|
void downloadIcon();
|
||||||
int updateArticles(const QList<QVariantHash> &loadedArticles);
|
int updateArticles(const QList<QVariantHash> &loadedArticles);
|
||||||
|
void setURL(const QString &url);
|
||||||
|
|
||||||
Session *m_session = nullptr;
|
Session *m_session = nullptr;
|
||||||
Private::Parser *m_parser = nullptr;
|
Private::Parser *m_parser = nullptr;
|
||||||
Private::FeedSerializer *m_serializer = nullptr;
|
Private::FeedSerializer *m_serializer = nullptr;
|
||||||
const QUuid m_uid;
|
const QUuid m_uid;
|
||||||
const QString m_url;
|
QString m_url;
|
||||||
QString m_title;
|
QString m_title;
|
||||||
QString m_lastBuildDate;
|
QString m_lastBuildDate;
|
||||||
bool m_hasError = false;
|
bool m_hasError = false;
|
||||||
|
@ -156,10 +156,39 @@ nonstd::expected<void, QString> Session::addFeed(const QString &url, const QStri
|
|||||||
return result.get_unexpected();
|
return result.get_unexpected();
|
||||||
|
|
||||||
const auto destFolder = result.value();
|
const auto destFolder = result.value();
|
||||||
addItem(new Feed(generateUID(), url, path, this), destFolder);
|
auto *feed = new Feed(generateUID(), url, path, this);
|
||||||
|
addItem(feed, destFolder);
|
||||||
store();
|
store();
|
||||||
if (isProcessingEnabled())
|
if (isProcessingEnabled())
|
||||||
feedByURL(url)->refresh();
|
feed->refresh();
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
nonstd::expected<void, QString> Session::setFeedURL(const QString &path, const QString &url)
|
||||||
|
{
|
||||||
|
auto *feed = qobject_cast<Feed *>(m_itemsByPath.value(path));
|
||||||
|
if (!feed)
|
||||||
|
return nonstd::make_unexpected(tr("Feed doesn't exist: %1.").arg(path));
|
||||||
|
|
||||||
|
return setFeedURL(feed, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
nonstd::expected<void, QString> Session::setFeedURL(Feed *feed, const QString &url)
|
||||||
|
{
|
||||||
|
Q_ASSERT(feed);
|
||||||
|
|
||||||
|
if (url == feed->url())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (m_feedsByURL.contains(url))
|
||||||
|
return nonstd::make_unexpected(tr("RSS feed with given URL already exists: %1.").arg(url));
|
||||||
|
|
||||||
|
m_feedsByURL[url] = m_feedsByURL.take(feed->url());
|
||||||
|
feed->setURL(url);
|
||||||
|
store();
|
||||||
|
if (isProcessingEnabled())
|
||||||
|
feed->refresh();
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -409,6 +438,16 @@ void Session::addItem(Item *item, Folder *destFolder)
|
|||||||
connect(feed, &Feed::titleChanged, this, &Session::handleFeedTitleChanged);
|
connect(feed, &Feed::titleChanged, this, &Session::handleFeedTitleChanged);
|
||||||
connect(feed, &Feed::iconLoaded, this, &Session::feedIconLoaded);
|
connect(feed, &Feed::iconLoaded, this, &Session::feedIconLoaded);
|
||||||
connect(feed, &Feed::stateChanged, this, &Session::feedStateChanged);
|
connect(feed, &Feed::stateChanged, this, &Session::feedStateChanged);
|
||||||
|
connect(feed, &Feed::urlChanged, this, [this, feed](const QString &oldURL)
|
||||||
|
{
|
||||||
|
if (feed->name() == oldURL)
|
||||||
|
{
|
||||||
|
// If feed still use an URL as a name trying to rename it to match new URL...
|
||||||
|
moveItem(feed, Item::joinPath(Item::parentPath(feed->path()), feed->url()));
|
||||||
|
}
|
||||||
|
|
||||||
|
emit feedURLChanged(feed, oldURL);
|
||||||
|
});
|
||||||
m_feedsByUID[feed->uid()] = feed;
|
m_feedsByUID[feed->uid()] = feed;
|
||||||
m_feedsByURL[feed->url()] = feed;
|
m_feedsByURL[feed->url()] = feed;
|
||||||
}
|
}
|
||||||
@ -502,9 +541,11 @@ void Session::handleItemAboutToBeDestroyed(Item *item)
|
|||||||
void Session::handleFeedTitleChanged(Feed *feed)
|
void Session::handleFeedTitleChanged(Feed *feed)
|
||||||
{
|
{
|
||||||
if (feed->name() == feed->url())
|
if (feed->name() == feed->url())
|
||||||
|
{
|
||||||
// Now we have something better than a URL.
|
// Now we have something better than a URL.
|
||||||
// Trying to rename feed...
|
// Trying to rename feed...
|
||||||
moveItem(feed, Item::joinPath(Item::parentPath(feed->path()), feed->title()));
|
moveItem(feed, Item::joinPath(Item::parentPath(feed->path()), feed->title()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QUuid Session::generateUID() const
|
QUuid Session::generateUID() const
|
||||||
|
@ -116,6 +116,8 @@ namespace RSS
|
|||||||
|
|
||||||
nonstd::expected<void, QString> addFolder(const QString &path);
|
nonstd::expected<void, QString> addFolder(const QString &path);
|
||||||
nonstd::expected<void, QString> addFeed(const QString &url, const QString &path);
|
nonstd::expected<void, QString> addFeed(const QString &url, const QString &path);
|
||||||
|
nonstd::expected<void, QString> setFeedURL(const QString &path, const QString &url);
|
||||||
|
nonstd::expected<void, QString> setFeedURL(Feed *feed, const QString &url);
|
||||||
nonstd::expected<void, QString> moveItem(const QString &itemPath, const QString &destPath);
|
nonstd::expected<void, QString> moveItem(const QString &itemPath, const QString &destPath);
|
||||||
nonstd::expected<void, QString> moveItem(Item *item, const QString &destPath);
|
nonstd::expected<void, QString> moveItem(Item *item, const QString &destPath);
|
||||||
nonstd::expected<void, QString> removeItem(const QString &itemPath);
|
nonstd::expected<void, QString> removeItem(const QString &itemPath);
|
||||||
@ -138,6 +140,7 @@ namespace RSS
|
|||||||
void itemAboutToBeRemoved(Item *item);
|
void itemAboutToBeRemoved(Item *item);
|
||||||
void feedIconLoaded(Feed *feed);
|
void feedIconLoaded(Feed *feed);
|
||||||
void feedStateChanged(Feed *feed);
|
void feedStateChanged(Feed *feed);
|
||||||
|
void feedURLChanged(Feed *feed, const QString &oldURL);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void handleItemAboutToBeDestroyed(Item *item);
|
void handleItemAboutToBeDestroyed(Item *item);
|
||||||
|
@ -65,6 +65,7 @@ RSSWidget::RSSWidget(QWidget *parent)
|
|||||||
m_ui->actionCopyFeedURL->setIcon(UIThemeManager::instance()->getIcon(u"edit-copy"_qs));
|
m_ui->actionCopyFeedURL->setIcon(UIThemeManager::instance()->getIcon(u"edit-copy"_qs));
|
||||||
m_ui->actionDelete->setIcon(UIThemeManager::instance()->getIcon(u"edit-clear"_qs));
|
m_ui->actionDelete->setIcon(UIThemeManager::instance()->getIcon(u"edit-clear"_qs));
|
||||||
m_ui->actionDownloadTorrent->setIcon(UIThemeManager::instance()->getIcon(u"downloading"_qs, u"download"_qs));
|
m_ui->actionDownloadTorrent->setIcon(UIThemeManager::instance()->getIcon(u"downloading"_qs, u"download"_qs));
|
||||||
|
m_ui->actionEditFeedURL->setIcon(UIThemeManager::instance()->getIcon(u"edit-rename"_qs));
|
||||||
m_ui->actionMarkItemsRead->setIcon(UIThemeManager::instance()->getIcon(u"task-complete"_qs, u"mail-mark-read"_qs));
|
m_ui->actionMarkItemsRead->setIcon(UIThemeManager::instance()->getIcon(u"task-complete"_qs, u"mail-mark-read"_qs));
|
||||||
m_ui->actionNewFolder->setIcon(UIThemeManager::instance()->getIcon(u"folder-new"_qs));
|
m_ui->actionNewFolder->setIcon(UIThemeManager::instance()->getIcon(u"folder-new"_qs));
|
||||||
m_ui->actionNewSubscription->setIcon(UIThemeManager::instance()->getIcon(u"list-add"_qs));
|
m_ui->actionNewSubscription->setIcon(UIThemeManager::instance()->getIcon(u"list-add"_qs));
|
||||||
@ -101,6 +102,7 @@ RSSWidget::RSSWidget(QWidget *parent)
|
|||||||
// Feeds list actions
|
// Feeds list actions
|
||||||
connect(m_ui->actionDelete, &QAction::triggered, this, &RSSWidget::deleteSelectedItems);
|
connect(m_ui->actionDelete, &QAction::triggered, this, &RSSWidget::deleteSelectedItems);
|
||||||
connect(m_ui->actionRename, &QAction::triggered, this, &RSSWidget::renameSelectedRSSItem);
|
connect(m_ui->actionRename, &QAction::triggered, this, &RSSWidget::renameSelectedRSSItem);
|
||||||
|
connect(m_ui->actionEditFeedURL, &QAction::triggered, this, &RSSWidget::editSelectedRSSFeedURL);
|
||||||
connect(m_ui->actionUpdate, &QAction::triggered, this, &RSSWidget::refreshSelectedItems);
|
connect(m_ui->actionUpdate, &QAction::triggered, this, &RSSWidget::refreshSelectedItems);
|
||||||
connect(m_ui->actionNewFolder, &QAction::triggered, this, &RSSWidget::askNewFolder);
|
connect(m_ui->actionNewFolder, &QAction::triggered, this, &RSSWidget::askNewFolder);
|
||||||
connect(m_ui->actionNewSubscription, &QAction::triggered, this, &RSSWidget::on_newFeedButton_clicked);
|
connect(m_ui->actionNewSubscription, &QAction::triggered, this, &RSSWidget::on_newFeedButton_clicked);
|
||||||
@ -158,12 +160,15 @@ void RSSWidget::displayRSSListMenu(const QPoint &pos)
|
|||||||
|
|
||||||
if (selectedItems.size() == 1)
|
if (selectedItems.size() == 1)
|
||||||
{
|
{
|
||||||
if (selectedItems.first() != m_feedListWidget->stickyUnreadItem())
|
QTreeWidgetItem *selectedItem = selectedItems.first();
|
||||||
|
if (selectedItem != m_feedListWidget->stickyUnreadItem())
|
||||||
{
|
{
|
||||||
menu->addAction(m_ui->actionRename);
|
menu->addAction(m_ui->actionRename);
|
||||||
|
if (m_feedListWidget->isFeed(selectedItem))
|
||||||
|
menu->addAction(m_ui->actionEditFeedURL);
|
||||||
menu->addAction(m_ui->actionDelete);
|
menu->addAction(m_ui->actionDelete);
|
||||||
menu->addSeparator();
|
menu->addSeparator();
|
||||||
if (m_feedListWidget->isFolder(selectedItems.first()))
|
if (m_feedListWidget->isFolder(selectedItem))
|
||||||
menu->addAction(m_ui->actionNewFolder);
|
menu->addAction(m_ui->actionNewFolder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -420,6 +425,29 @@ void RSSWidget::renameSelectedRSSItem()
|
|||||||
} while (!ok);
|
} while (!ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RSSWidget::editSelectedRSSFeedURL()
|
||||||
|
{
|
||||||
|
QList<QTreeWidgetItem *> selectedItems = m_feedListWidget->selectedItems();
|
||||||
|
if (selectedItems.size() != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QTreeWidgetItem *item = selectedItems.first();
|
||||||
|
RSS::Feed *rssFeed = qobject_cast<RSS::Feed *>(m_feedListWidget->getRSSItem(item));
|
||||||
|
Q_ASSERT(rssFeed);
|
||||||
|
if (Q_UNLIKELY(!rssFeed))
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
QString newURL = AutoExpandableDialog::getText(this, tr("Please type a RSS feed URL")
|
||||||
|
, tr("Feed URL:"), QLineEdit::Normal, rssFeed->url(), &ok).trimmed();
|
||||||
|
if (!ok || newURL.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const nonstd::expected<void, QString> result = RSS::Session::instance()->setFeedURL(rssFeed, newURL);
|
||||||
|
if (!result)
|
||||||
|
QMessageBox::warning(this, u"qBittorrent"_qs, result.error(), QMessageBox::Ok);
|
||||||
|
}
|
||||||
|
|
||||||
void RSSWidget::refreshSelectedItems()
|
void RSSWidget::refreshSelectedItems()
|
||||||
{
|
{
|
||||||
for (QTreeWidgetItem *item : asConst(m_feedListWidget->selectedItems()))
|
for (QTreeWidgetItem *item : asConst(m_feedListWidget->selectedItems()))
|
||||||
|
@ -66,6 +66,7 @@ private slots:
|
|||||||
void displayRSSListMenu(const QPoint &pos);
|
void displayRSSListMenu(const QPoint &pos);
|
||||||
void displayItemsListMenu();
|
void displayItemsListMenu();
|
||||||
void renameSelectedRSSItem();
|
void renameSelectedRSSItem();
|
||||||
|
void editSelectedRSSFeedURL();
|
||||||
void refreshSelectedItems();
|
void refreshSelectedItems();
|
||||||
void copySelectedFeedsURL();
|
void copySelectedFeedsURL();
|
||||||
void handleCurrentFeedItemChanged(QTreeWidgetItem *currentItem);
|
void handleCurrentFeedItemChanged(QTreeWidgetItem *currentItem);
|
||||||
|
@ -197,6 +197,14 @@
|
|||||||
<string>New folder...</string>
|
<string>New folder...</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionEditFeedURL">
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit feed URL...</string>
|
||||||
|
</property>
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Edit feed URL</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
@ -66,6 +66,17 @@ void RSSController::addFeedAction()
|
|||||||
throw APIError(APIErrorType::Conflict, result.error());
|
throw APIError(APIErrorType::Conflict, result.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RSSController::setFeedURLAction()
|
||||||
|
{
|
||||||
|
requireParams({u"path"_qs, u"url"_qs});
|
||||||
|
|
||||||
|
const QString path = params()[u"path"_qs].trimmed();
|
||||||
|
const QString url = params()[u"url"_qs].trimmed();
|
||||||
|
const nonstd::expected<void, QString> result = RSS::Session::instance()->setFeedURL(path, url);
|
||||||
|
if (!result)
|
||||||
|
throw APIError(APIErrorType::Conflict, result.error());
|
||||||
|
}
|
||||||
|
|
||||||
void RSSController::removeItemAction()
|
void RSSController::removeItemAction()
|
||||||
{
|
{
|
||||||
requireParams({u"path"_qs});
|
requireParams({u"path"_qs});
|
||||||
|
@ -41,6 +41,7 @@ public:
|
|||||||
private slots:
|
private slots:
|
||||||
void addFolderAction();
|
void addFolderAction();
|
||||||
void addFeedAction();
|
void addFeedAction();
|
||||||
|
void setFeedURLAction();
|
||||||
void removeItemAction();
|
void removeItemAction();
|
||||||
void moveItemAction();
|
void moveItemAction();
|
||||||
void itemsAction();
|
void itemsAction();
|
||||||
|
@ -148,6 +148,7 @@ private:
|
|||||||
{{u"auth"_qs, u"login"_qs}, Http::METHOD_POST},
|
{{u"auth"_qs, u"login"_qs}, Http::METHOD_POST},
|
||||||
{{u"auth"_qs, u"logout"_qs}, Http::METHOD_POST},
|
{{u"auth"_qs, u"logout"_qs}, Http::METHOD_POST},
|
||||||
{{u"rss"_qs, u"addFeed"_qs}, Http::METHOD_POST},
|
{{u"rss"_qs, u"addFeed"_qs}, Http::METHOD_POST},
|
||||||
|
{{u"rss"_qs, u"setFeedURL"_qs}, Http::METHOD_POST},
|
||||||
{{u"rss"_qs, u"addFolder"_qs}, Http::METHOD_POST},
|
{{u"rss"_qs, u"addFolder"_qs}, Http::METHOD_POST},
|
||||||
{{u"rss"_qs, u"markAsRead"_qs}, Http::METHOD_POST},
|
{{u"rss"_qs, u"markAsRead"_qs}, Http::METHOD_POST},
|
||||||
{{u"rss"_qs, u"moveItem"_qs}, Http::METHOD_POST},
|
{{u"rss"_qs, u"moveItem"_qs}, Http::METHOD_POST},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user