mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-01-10 23:07:59 +00:00
Fix possible rule saving issue
Matching articles are now previewable in the rss downloader dialog Make sure Rss downloading is enabled before checking for matching rules
This commit is contained in:
parent
345222cf42
commit
c387c15eb0
@ -131,7 +131,7 @@ GUI::GUI(QWidget *parent, QStringList torrentCmdLine) : QMainWindow(parent), for
|
||||
// Fix Tool bar layout
|
||||
toolBar->layout()->setSpacing(7);
|
||||
// Creating Bittorrent session
|
||||
BTSession = new QBtSession();
|
||||
BTSession = QBtSession::instance();
|
||||
connect(BTSession, SIGNAL(fullDiskError(QTorrentHandle&, QString)), this, SLOT(fullDiskError(QTorrentHandle&, QString)));
|
||||
connect(BTSession, SIGNAL(finishedTorrent(QTorrentHandle&)), this, SLOT(finishedTorrent(QTorrentHandle&)));
|
||||
connect(BTSession, SIGNAL(trackerAuthenticationRequired(QTorrentHandle&)), this, SLOT(trackerAuthenticationRequired(QTorrentHandle&)));
|
||||
@ -277,11 +277,6 @@ GUI::~GUI() {
|
||||
// Workaround to avoid bug http://bugreports.qt.nokia.com/browse/QTBUG-7305
|
||||
setUnifiedTitleAndToolBarOnMac(false);
|
||||
#endif
|
||||
// Async deletion of Bittorrent session as early as possible
|
||||
// in order to speed up exit
|
||||
session_proxy sp;
|
||||
if(BTSession)
|
||||
sp = BTSession->asyncDeletion();
|
||||
// Some saving
|
||||
properties->saveSettings();
|
||||
disconnect(tabs, SIGNAL(currentChanged(int)), this, SLOT(tab_changed(int)));
|
||||
@ -328,7 +323,7 @@ GUI::~GUI() {
|
||||
delete switchRSSShortcut;
|
||||
// Delete BTSession objects
|
||||
qDebug("Deleting BTSession");
|
||||
delete BTSession;
|
||||
QBtSession::drop();
|
||||
// May freeze for a few seconds after the next line
|
||||
// because the Bittorrent session proxy will
|
||||
// actually be deleted now and destruction
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
// Enable Web UI
|
||||
Preferences::setWebUiEnabled(true);
|
||||
// Instanciate Bittorrent Object
|
||||
BTSession = new QBtSession();
|
||||
BTSession = QBtSession::instance();
|
||||
connect(BTSession, SIGNAL(newConsoleMessage(QString)), this, SLOT(displayConsoleMessage(QString)));
|
||||
// Resume unfinished torrents
|
||||
BTSession->startUpTorrents();
|
||||
@ -61,7 +61,7 @@ public:
|
||||
}
|
||||
|
||||
~HeadlessLoader() {
|
||||
delete BTSession;
|
||||
QBtSession::drop();
|
||||
}
|
||||
|
||||
public slots:
|
||||
|
@ -68,6 +68,8 @@
|
||||
#include <boost/filesystem/exception.hpp>
|
||||
#include <queue>
|
||||
|
||||
QBtSession* QBtSession::m_instance = 0;
|
||||
|
||||
const int MAX_TRACKER_ERRORS = 2;
|
||||
const float MAX_RATIO = 100.;
|
||||
enum VersionType { NORMAL,ALPHA,BETA,RELEASE_CANDIDATE,DEVEL };
|
||||
@ -2628,3 +2630,17 @@ void QBtSession::startUpTorrents() {
|
||||
settings.setValue("ported_to_new_savepath_system", true);
|
||||
qDebug("Unfinished torrents resumed");
|
||||
}
|
||||
|
||||
QBtSession * QBtSession::instance()
|
||||
{
|
||||
if(!m_instance) {
|
||||
m_instance = new QBtSession;
|
||||
}
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
void QBtSession::drop()
|
||||
{
|
||||
if(m_instance)
|
||||
delete m_instance;
|
||||
}
|
||||
|
@ -66,9 +66,13 @@ class QBtSession : public QObject {
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(QBtSession)
|
||||
|
||||
private:
|
||||
explicit QBtSession();
|
||||
static QBtSession* m_instance;
|
||||
|
||||
public:
|
||||
// Constructor / Destructor
|
||||
QBtSession();
|
||||
static QBtSession* instance();
|
||||
static void drop();
|
||||
~QBtSession();
|
||||
QTorrentHandle getTorrentHandle(QString hash) const;
|
||||
std::vector<torrent_handle> getTorrents() const;
|
||||
|
@ -41,6 +41,8 @@
|
||||
#include "rssdownloadrulelist.h"
|
||||
#include "preferences.h"
|
||||
#include "qinisettings.h"
|
||||
#include "rssmanager.h"
|
||||
#include "rssfeed.h"
|
||||
|
||||
AutomatedRssDownloader::AutomatedRssDownloader(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
@ -49,6 +51,8 @@ AutomatedRssDownloader::AutomatedRssDownloader(QWidget *parent) :
|
||||
ui->setupUi(this);
|
||||
ui->listRules->setSortingEnabled(true);
|
||||
ui->listRules->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
ui->treeMatchingArticles->setSortingEnabled(true);
|
||||
|
||||
connect(ui->listRules, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(displayRulesListMenu(const QPoint&)));
|
||||
m_ruleList = RssDownloadRuleList::instance();
|
||||
initLabelCombobox();
|
||||
@ -58,6 +62,9 @@ AutomatedRssDownloader::AutomatedRssDownloader(QWidget *parent) :
|
||||
connect(ui->listRules, SIGNAL(itemSelectionChanged()), SLOT(updateRuleDefinitionBox()));
|
||||
connect(ui->listRules, SIGNAL(itemSelectionChanged()), SLOT(updateFeedList()));
|
||||
connect(ui->listFeeds, SIGNAL(itemChanged(QListWidgetItem*)), SLOT(handleFeedCheckStateChange(QListWidgetItem*)));
|
||||
// Update matching articles when necessary
|
||||
connect(ui->lineContains, SIGNAL(textEdited(QString)), SLOT(updateMatchingArticles()));
|
||||
connect(ui->lineNotContains, SIGNAL(textEdited(QString)), SLOT(updateMatchingArticles()));
|
||||
updateRuleDefinitionBox();
|
||||
updateFeedList();
|
||||
}
|
||||
@ -149,6 +156,7 @@ void AutomatedRssDownloader::updateFeedList()
|
||||
}
|
||||
ui->listFeeds->setEnabled(!ui->listRules->selectedItems().isEmpty());
|
||||
connect(ui->listFeeds, SIGNAL(itemChanged(QListWidgetItem*)), SLOT(handleFeedCheckStateChange(QListWidgetItem*)));
|
||||
updateMatchingArticles();
|
||||
}
|
||||
|
||||
bool AutomatedRssDownloader::isRssDownloaderEnabled() const
|
||||
@ -224,7 +232,11 @@ void AutomatedRssDownloader::saveCurrentRule(QListWidgetItem * item)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << item;
|
||||
if(!item) return;
|
||||
if(!ui->listRules->findItems(item->text(), Qt::MatchExactly).isEmpty()) return;
|
||||
if(ui->listRules->findItems(item->text(), Qt::MatchExactly).isEmpty()) {
|
||||
qDebug() << "Could not find rule" << item->text() << "in the UI list";
|
||||
qDebug() << "Probably removed the item, no need to save it";
|
||||
return;
|
||||
}
|
||||
RssDownloadRule rule = m_ruleList->getRule(item->text());
|
||||
if(!rule.isValid()) {
|
||||
rule.setName(item->text());
|
||||
@ -263,6 +275,7 @@ void AutomatedRssDownloader::on_addRuleBtn_clicked()
|
||||
QListWidgetItem * item = new QListWidgetItem(rule, ui->listRules);
|
||||
item->setFlags(item->flags()|Qt::ItemIsUserCheckable);
|
||||
item->setCheckState(Qt::Checked); // Enable as a default
|
||||
ui->listRules->clearSelection();
|
||||
ui->listRules->setCurrentItem(item);
|
||||
}
|
||||
|
||||
@ -402,6 +415,54 @@ void AutomatedRssDownloader::handleFeedCheckStateChange(QListWidgetItem *feed_it
|
||||
m_ruleList->saveRule(rule);
|
||||
}
|
||||
}
|
||||
// Update Matching articles
|
||||
updateMatchingArticles();
|
||||
}
|
||||
|
||||
void AutomatedRssDownloader::updateMatchingArticles()
|
||||
{
|
||||
ui->treeMatchingArticles->clear();
|
||||
if(ui->ruleDefBox->isEnabled()) {
|
||||
saveCurrentRule(ui->listRules->currentItem());
|
||||
}
|
||||
const QHash<QString, RssFeed*> all_feeds = RssManager::instance()->getAllFeedsAsHash();
|
||||
|
||||
foreach(const QListWidgetItem *rule_item, ui->listRules->selectedItems()) {
|
||||
RssDownloadRule rule = m_ruleList->getRule(rule_item->text());
|
||||
if(!rule.isValid()) continue;
|
||||
foreach(const QString &feed_url, rule.rssFeeds()) {
|
||||
Q_ASSERT(all_feeds.contains(feed_url));
|
||||
const RssFeed *feed = all_feeds.value(feed_url);
|
||||
const QStringList matching_articles = rule.findMatchingArticles(feed);
|
||||
if(!matching_articles.isEmpty())
|
||||
addFeedArticlesToTree(feed, matching_articles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AutomatedRssDownloader::addFeedArticlesToTree(const RssFeed *feed, const QStringList &articles)
|
||||
{
|
||||
// Check if this feed is already in the tree
|
||||
QTreeWidgetItem *treeFeedItem = 0;
|
||||
for(int i=0; i<ui->treeMatchingArticles->topLevelItemCount(); ++i) {
|
||||
QTreeWidgetItem *item = ui->treeMatchingArticles->topLevelItem(i);
|
||||
if(item->data(0, Qt::UserRole).toString() == feed->getUrl()) {
|
||||
treeFeedItem = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If there is none, create it
|
||||
if(!treeFeedItem) {
|
||||
treeFeedItem = new QTreeWidgetItem(QStringList() << feed->getName());
|
||||
treeFeedItem->setData(0, Qt::UserRole, feed->getUrl());
|
||||
ui->treeMatchingArticles->addTopLevelItem(treeFeedItem);
|
||||
}
|
||||
// Insert the articles
|
||||
foreach(const QString &art, articles) {
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem(QStringList() << art);
|
||||
treeFeedItem->addChild(item);
|
||||
}
|
||||
ui->treeMatchingArticles->expandItem(treeFeedItem);
|
||||
}
|
||||
|
||||
|
||||
|
@ -70,10 +70,12 @@ private slots:
|
||||
void on_exportBtn_clicked();
|
||||
void on_importBtn_clicked();
|
||||
void renameSelectedRule();
|
||||
void updateMatchingArticles();
|
||||
|
||||
private:
|
||||
RssDownloadRule getCurrentRule() const;
|
||||
void initLabelCombobox();
|
||||
void addFeedArticlesToTree(const RssFeed *feed, const QStringList& articles);
|
||||
|
||||
private:
|
||||
Ui::AutomatedRssDownloader *ui;
|
||||
|
@ -266,10 +266,15 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listMatchingArticles">
|
||||
<property name="enabled">
|
||||
<widget class="QTreeWidget" name="treeMatchingArticles">
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
@ -580,7 +580,7 @@ void RSSImp::updateRefreshInterval(unsigned int val) {
|
||||
RSSImp::RSSImp(QBtSession *BTSession) : QWidget(), BTSession(BTSession){
|
||||
setupUi(this);
|
||||
|
||||
rssmanager = new RssManager(BTSession);
|
||||
rssmanager = RssManager::instance();
|
||||
|
||||
listStreams = new FeedListWidget(splitter_h, rssmanager);
|
||||
splitter_h->insertWidget(0, listStreams);
|
||||
@ -634,7 +634,7 @@ RSSImp::~RSSImp(){
|
||||
qDebug("Deleting RSSImp...");
|
||||
saveFoldersOpenState();
|
||||
delete listStreams;
|
||||
delete rssmanager;
|
||||
RssManager::drop();
|
||||
qDebug("RSSImp deleted");
|
||||
}
|
||||
|
||||
|
@ -252,10 +252,6 @@ bool RssArticle::has_attachment() const {
|
||||
return !torrent_url.isEmpty();
|
||||
}
|
||||
|
||||
QString RssArticle::getId() const {
|
||||
return id;
|
||||
}
|
||||
|
||||
QHash<QString, QVariant> RssArticle::toHash() const {
|
||||
QHash<QString, QVariant> item;
|
||||
item["title"] = title;
|
||||
@ -282,10 +278,6 @@ bool RssArticle::isValid() const {
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
QString RssArticle::getTitle() const{
|
||||
return title;
|
||||
}
|
||||
|
||||
QString RssArticle::getAuthor() const {
|
||||
return author;
|
||||
}
|
||||
|
@ -48,12 +48,12 @@ public:
|
||||
QDateTime _date, QString _author, bool _read);
|
||||
~RssArticle();
|
||||
bool has_attachment() const;
|
||||
QString getId() const;
|
||||
inline QString getId() const { return id; }
|
||||
QHash<QString, QVariant> toHash() const;
|
||||
static RssArticle* fromHash(RssFeed* parent, const QHash<QString, QVariant> &h);
|
||||
RssFeed* getParent() const;
|
||||
bool isValid() const;
|
||||
QString getTitle() const;
|
||||
inline QString getTitle() const { return title; }
|
||||
QString getAuthor() const;
|
||||
QString getTorrentUrl() const;
|
||||
QString getLink() const;
|
||||
|
@ -34,6 +34,8 @@
|
||||
#include "rssdownloadrule.h"
|
||||
#include "preferences.h"
|
||||
#include "qinisettings.h"
|
||||
#include "rssfeed.h"
|
||||
#include "rssarticle.h"
|
||||
|
||||
RssDownloadRule::RssDownloadRule()
|
||||
{
|
||||
@ -123,3 +125,13 @@ void RssDownloadRule::setSavePath(const QString &save_path)
|
||||
else
|
||||
m_savePath = QString();
|
||||
}
|
||||
|
||||
QStringList RssDownloadRule::findMatchingArticles(const RssFeed *feed) const
|
||||
{
|
||||
QStringList ret;
|
||||
foreach(const RssArticle *art, feed->values()) {
|
||||
if(matches(art->getTitle()))
|
||||
ret << art->getTitle();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -34,6 +34,8 @@
|
||||
#include <QStringList>
|
||||
#include <QVariantHash>
|
||||
|
||||
class RssFeed;
|
||||
|
||||
class RssDownloadRule
|
||||
{
|
||||
|
||||
@ -58,6 +60,7 @@ public:
|
||||
inline bool isValid() const { return !m_name.isEmpty(); }
|
||||
inline QString mustContain() const { return m_mustContain.join(" "); }
|
||||
inline QString mustNotContain() const { return m_mustNotContain.join(" "); }
|
||||
QStringList findMatchingArticles(const RssFeed* feed) const;
|
||||
// Operators
|
||||
bool operator==(const RssDownloadRule &other);
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <QDebug>
|
||||
|
||||
#include "rssdownloadrulelist.h"
|
||||
#include "rsssettings.h"
|
||||
#include "qinisettings.h"
|
||||
|
||||
RssDownloadRuleList* RssDownloadRuleList::m_instance = 0;
|
||||
@ -56,6 +57,7 @@ void RssDownloadRuleList::drop()
|
||||
|
||||
RssDownloadRule RssDownloadRuleList::findMatchingRule(const QString &feed_url, const QString &article_title) const
|
||||
{
|
||||
Q_ASSERT(RssSettings::isRssDownloadingEnabled());
|
||||
QStringList rule_names = feedRules(feed_url);
|
||||
foreach(const QString &rule_name, rule_names) {
|
||||
RssDownloadRule rule = m_rules[rule_name];
|
||||
@ -127,6 +129,7 @@ void RssDownloadRuleList::loadRulesFromVariantHash(const QVariantHash &h)
|
||||
|
||||
void RssDownloadRuleList::saveRule(const RssDownloadRule &rule)
|
||||
{
|
||||
qDebug() << Q_FUNC_INFO << rule.name();
|
||||
Q_ASSERT(rule.isValid());
|
||||
if(m_rules.contains(rule.name())) {
|
||||
removeRule(rule.name());
|
||||
|
@ -290,21 +290,23 @@ short RssFeed::readDoc(QIODevice* device) {
|
||||
resizeList();
|
||||
|
||||
// RSS Feed Downloader
|
||||
foreach(RssArticle* item, values()) {
|
||||
if(item->isRead()) continue;
|
||||
QString torrent_url;
|
||||
if(item->has_attachment())
|
||||
torrent_url = item->getTorrentUrl();
|
||||
else
|
||||
torrent_url = item->getLink();
|
||||
// Check if the item should be automatically downloaded
|
||||
const RssDownloadRule matching_rule = RssDownloadRuleList::instance()->findMatchingRule(url, item->getTitle());
|
||||
if(matching_rule.isValid()) {
|
||||
// Download the torrent
|
||||
BTSession->addConsoleMessage(tr("Automatically downloading %1 torrent from %2 RSS feed...").arg(item->getTitle()).arg(getName()));
|
||||
BTSession->downloadUrlAndSkipDialog(torrent_url, matching_rule.savePath(), matching_rule.label());
|
||||
// Item was downloaded, consider it as Read
|
||||
item->setRead();
|
||||
if(RssSettings::isRssDownloadingEnabled()) {
|
||||
foreach(RssArticle* item, values()) {
|
||||
if(item->isRead()) continue;
|
||||
QString torrent_url;
|
||||
if(item->has_attachment())
|
||||
torrent_url = item->getTorrentUrl();
|
||||
else
|
||||
torrent_url = item->getLink();
|
||||
// Check if the item should be automatically downloaded
|
||||
const RssDownloadRule matching_rule = RssDownloadRuleList::instance()->findMatchingRule(url, item->getTitle());
|
||||
if(matching_rule.isValid()) {
|
||||
// Download the torrent
|
||||
BTSession->addConsoleMessage(tr("Automatically downloading %1 torrent from %2 RSS feed...").arg(item->getTitle()).arg(getName()));
|
||||
BTSession->downloadUrlAndSkipDialog(torrent_url, matching_rule.savePath(), matching_rule.label());
|
||||
// Item was downloaded, consider it as Read
|
||||
item->setRead();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -256,16 +256,27 @@ QList<RssFeed*> RssFolder::getAllFeeds() const {
|
||||
QList<RssFeed*> streams;
|
||||
foreach(RssFile *item, this->values()) {
|
||||
if(item->getType() == RssFile::FEED) {
|
||||
streams << ((RssFeed*)item);
|
||||
streams << static_cast<RssFeed*>(item);
|
||||
} else {
|
||||
foreach(RssFeed* stream, ((RssFolder*)item)->getAllFeeds()) {
|
||||
streams << stream;
|
||||
}
|
||||
streams << static_cast<RssFolder*>(item)->getAllFeeds();
|
||||
}
|
||||
}
|
||||
return streams;
|
||||
}
|
||||
|
||||
QHash<QString, RssFeed*> RssFolder::getAllFeedsAsHash() const {
|
||||
QHash<QString, RssFeed*> ret;
|
||||
foreach(RssFile *item, this->values()) {
|
||||
if(item->getType() == RssFile::FEED) {
|
||||
RssFeed* feed = static_cast<RssFeed*>(item);
|
||||
ret[feed->getUrl()] = feed;
|
||||
} else {
|
||||
ret.unite(static_cast<RssFolder*>(item)->getAllFeedsAsHash());
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void RssFolder::addFile(RssFile * item) {
|
||||
if(item->getType() == RssFile::FEED) {
|
||||
Q_ASSERT(!this->contains(((RssFeed*)item)->getUrl()));
|
||||
|
@ -57,6 +57,7 @@ public:
|
||||
unsigned int getNbFeeds() const;
|
||||
QList<RssFile*> getContent() const;
|
||||
QList<RssFeed*> getAllFeeds() const;
|
||||
QHash<QString, RssFeed*> getAllFeedsAsHash() const;
|
||||
QString getName() const;
|
||||
QString getID() const;
|
||||
bool hasChild(QString ID);
|
||||
|
@ -35,7 +35,9 @@
|
||||
#include "rssarticle.h"
|
||||
#include "rssdownloadrulelist.h"
|
||||
|
||||
RssManager::RssManager(QBtSession *BTSession): RssFolder(0, this, BTSession, QString::null) {
|
||||
RssManager* RssManager::m_instance = 0;
|
||||
|
||||
RssManager::RssManager(): RssFolder(0, this, QBtSession::instance(), QString::null) {
|
||||
loadStreamList();
|
||||
connect(&newsRefresher, SIGNAL(timeout()), this, SLOT(refreshAll()));
|
||||
refreshInterval = RssSettings::getRSSRefreshInterval();
|
||||
@ -137,3 +139,16 @@ QList<RssArticle*> RssManager::sortNewsList(const QList<RssArticle*>& news_list)
|
||||
}
|
||||
return new_list;
|
||||
}
|
||||
|
||||
RssManager * RssManager::instance()
|
||||
{
|
||||
if(!m_instance)
|
||||
m_instance = new RssManager;
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
void RssManager::drop()
|
||||
{
|
||||
if(m_instance)
|
||||
delete m_instance;
|
||||
}
|
||||
|
@ -37,9 +37,13 @@
|
||||
|
||||
class RssManager: public RssFolder {
|
||||
Q_OBJECT
|
||||
private:
|
||||
explicit RssManager();
|
||||
static RssManager* m_instance;
|
||||
|
||||
public:
|
||||
RssManager(QBtSession *BTSession);
|
||||
static RssManager* instance();
|
||||
static void drop();
|
||||
~RssManager();
|
||||
static void insertSortElem(QList<RssArticle*> &list, RssArticle *item);
|
||||
static QList<RssArticle*> sortNewsList(const QList<RssArticle*>& news_list);
|
||||
|
Loading…
Reference in New Issue
Block a user