diff --git a/src/preferences.h b/src/preferences.h index c89e2f017..21760d459 100644 --- a/src/preferences.h +++ b/src/preferences.h @@ -55,7 +55,7 @@ enum scheduler_days { EVERY_DAY, WEEK_DAYS, WEEK_ENDS, MON, TUE, WED, THU, FRI, SAT, SUN }; enum maxRatioAction {PAUSE_ACTION, REMOVE_ACTION}; namespace Proxy { - enum ProxyType {HTTP=1, SOCKS5=2, HTTP_PW=3, SOCKS5_PW=4, SOCKS4=5}; +enum ProxyType {HTTP=1, SOCKS5=2, HTTP_PW=3, SOCKS5_PW=4, SOCKS4=5}; } class Preferences { @@ -1053,6 +1053,27 @@ public: return raw_cookies.split(':'); } + static QStringList getTorrentLabels() { + QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + return settings.value("TransferListFilters/customLabels").toStringList(); + } + + static void addTorrentLabel(const QString& label) { + QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + QStringList labels = settings.value("TransferListFilters/customLabels").toStringList(); + if(!labels.contains(label)) + labels << label; + settings.setValue("TransferListFilters/customLabels", labels); + } + + static void removeTorrentLabel(const QString& label) { + QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); + QStringList labels = settings.value("TransferListFilters/customLabels").toStringList(); + if(labels.contains(label)) + labels.removeOne(label); + settings.setValue("TransferListFilters/customLabels", labels); + } + static void setHostNameCookies(QString host_name, const QList &cookies) { QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss"); QMap hosts_table = qBTRSS.value("hosts_cookies", QMap()).toMap(); diff --git a/src/qtlibtorrent/qbtsession.cpp b/src/qtlibtorrent/qbtsession.cpp index 3e3b14fe1..3d254802b 100644 --- a/src/qtlibtorrent/qbtsession.cpp +++ b/src/qtlibtorrent/qbtsession.cpp @@ -247,11 +247,8 @@ void QBtSession::handleDownloadFailure(QString url, QString reason) { emit downloadFromUrlFailure(url, reason); // Clean up const QUrl qurl = QUrl::fromEncoded(url.toLocal8Bit()); - const int index = url_skippingDlg.indexOf(qurl); - if(index >= 0) - url_skippingDlg.removeAt(index); - if(savepath_fromurl.contains(qurl)) - savepath_fromurl.remove(qurl); + url_skippingDlg.removeOne(qurl); + savepathLabel_fromurl.remove(qurl); } void QBtSession::startTorrentsInPause(bool b) { @@ -1052,9 +1049,15 @@ QTorrentHandle QBtSession::addTorrent(QString path, bool fromScanDir, QString fr } } QString savePath; - if(!from_url.isEmpty() && savepath_fromurl.contains(QUrl::fromEncoded(from_url.toLocal8Bit()))) { + if(!from_url.isEmpty() && savepathLabel_fromurl.contains(QUrl::fromEncoded(from_url.toLocal8Bit()))) { // Enforcing the save path defined before URL download (from RSS for example) - savePath = savepath_fromurl.take(QUrl::fromEncoded(from_url.toLocal8Bit())); + QPair savePath_label = savepathLabel_fromurl.take(QUrl::fromEncoded(from_url.toLocal8Bit())); + if(savePath_label.first.isEmpty()) + savePath = getSavePath(hash, fromScanDir, path, root_folder); + else + savePath = savePath_label.first; + // Remember label + TorrentTempData::setLabel(hash, savePath_label.second); } else { savePath = getSavePath(hash, fromScanDir, path, root_folder); } @@ -2154,7 +2157,7 @@ void QBtSession::readAlerts() { QTorrentHandle h(p->handle); if(h.is_valid()) { // Attempt to remove old folder if empty - const QString& old_save_path = TorrentPersistentData::getPreviousPath(h.hash()); + const QString old_save_path = TorrentPersistentData::getPreviousPath(h.hash()); const QString new_save_path = misc::toQStringU(p->path.c_str()); qDebug("Torrent moved from %s to %s", qPrintable(old_save_path), qPrintable(new_save_path)); QDir old_save_dir(old_save_path); @@ -2489,11 +2492,11 @@ void QBtSession::addMagnetSkipAddDlg(QString uri) { addMagnetUri(uri, false); } -void QBtSession::downloadUrlAndSkipDialog(QString url, QString save_path) { +void QBtSession::downloadUrlAndSkipDialog(QString url, QString save_path, QString label) { //emit aboutToDownloadFromUrl(url); const QUrl qurl = QUrl::fromEncoded(url.toLocal8Bit()); if(!save_path.isEmpty()) - savepath_fromurl[qurl] = save_path; + savepathLabel_fromurl[qurl] = qMakePair(save_path, label); url_skippingDlg << qurl; // Launch downloader thread downloader->downloadUrl(url); diff --git a/src/qtlibtorrent/qbtsession.h b/src/qtlibtorrent/qbtsession.h index 8a5af38f6..f97258a21 100644 --- a/src/qtlibtorrent/qbtsession.h +++ b/src/qtlibtorrent/qbtsession.h @@ -119,7 +119,7 @@ public slots: void disableIPFilter(); void setQueueingEnabled(bool enable); void handleDownloadFailure(QString url, QString reason); - void downloadUrlAndSkipDialog(QString url, QString save_path=QString::null); + void downloadUrlAndSkipDialog(QString url, QString save_path, QString label); // Session configuration - Setters void setListeningPort(int port); void setMaxConnections(int maxConnec); @@ -209,7 +209,7 @@ private: session *s; QPointer timerAlerts; QPointer bd_scheduler; - QMap savepath_fromurl; + QMap > savepathLabel_fromurl; QHash > trackersInfos; QHash savePathsToRemove; QStringList torrentsToPausedAfterChecking; diff --git a/src/rss/automatedrssdownloader.cpp b/src/rss/automatedrssdownloader.cpp index 8b0537af6..2527cd4f5 100644 --- a/src/rss/automatedrssdownloader.cpp +++ b/src/rss/automatedrssdownloader.cpp @@ -28,32 +28,230 @@ * Contact : chris@qbittorrent.org */ +#include +#include +#include +#include + #include "automatedrssdownloader.h" #include "ui_automatedrssdownloader.h" #include "rssfilters.h" #include "rsssettings.h" +#include "rssdownloadrulelist.h" +#include "preferences.h" +#include "qinisettings.h" AutomatedRssDownloader::AutomatedRssDownloader(QWidget *parent) : - QDialog(parent), - ui(new Ui::AutomatedRssDownloader) + QDialog(parent), + ui(new Ui::AutomatedRssDownloader) { - ui->setupUi(this); - loadSettings(); - //filters = RssFilters::getFeedFilters(feed_url); + ui->setupUi(this); + ui->listRules->setSortingEnabled(true); + m_ruleList = RssDownloadRuleList::instance(); + initLabelCombobox(); + loadFeedList(); + loadSettings(); + connect(ui->listRules, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(updateRuleDefinitionBox(QListWidgetItem*,QListWidgetItem*))); + connect(ui->listRules, SIGNAL(currentItemChanged(QListWidgetItem*,QListWidgetItem*)), SLOT(updateFeedList(QListWidgetItem*,QListWidgetItem*))); + if(ui->listRules->count() > 0) + ui->listRules->setCurrentRow(0); + else + updateRuleDefinitionBox(); } AutomatedRssDownloader::~AutomatedRssDownloader() { + qDebug() << Q_FUNC_INFO; + // Save current item on exit + saveCurrentRule(ui->listRules->currentItem()); saveSettings(); delete ui; } void AutomatedRssDownloader::loadSettings() { + // TODO: load dialog size and pos ui->checkEnableDownloader->setChecked(RssSettings::isRssDownloadingEnabled()); + // Display download rules + loadRulesList(); } void AutomatedRssDownloader::saveSettings() { RssSettings::setRssDownloadingEnabled(ui->checkEnableDownloader->isChecked()); + // TODO: Save dialog size and pos +} + +void AutomatedRssDownloader::loadRulesList() +{ + foreach (const QString &rule_name, m_ruleList->ruleNames()) { + QListWidgetItem *item = new QListWidgetItem(rule_name, ui->listRules); + item->setFlags(item->flags()|Qt::ItemIsUserCheckable); + if(m_ruleList->getRule(rule_name).isEnabled()) + item->setCheckState(Qt::Checked); + else + item->setCheckState(Qt::Unchecked); + } +} + +void AutomatedRssDownloader::loadFeedList() +{ + const QStringList feed_aliases = RssSettings::getRssFeedsAliases(); + const QStringList feed_urls = RssSettings::getRssFeedsUrls(); + for(int i=0; ilistFeeds); + item->setData(Qt::UserRole, feed_urls.at(i)); + item->setFlags(item->flags()|Qt::ItemIsUserCheckable); + } +} + +QStringList AutomatedRssDownloader::getSelectedFeeds() const +{ + QStringList feeds; + for(int i=0; ilistFeeds->count(); ++i) { + QListWidgetItem *item = ui->listFeeds->item(i); + if(item->checkState() != Qt::Unchecked) + feeds << item->data(Qt::UserRole).toString(); + } + return feeds; +} + +void AutomatedRssDownloader::updateFeedList(QListWidgetItem* current, QListWidgetItem* previous) +{ + Q_UNUSED(previous); + RssDownloadRule rule = getCurrentRule(); + const QStringList affected_feeds = rule.rssFeeds(); + for(int i=0; ilistFeeds->count(); ++i) { + QListWidgetItem *item = ui->listFeeds->item(i); + const QString feed_url = item->data(Qt::UserRole).toString(); + if(affected_feeds.contains(feed_url)) + item->setCheckState(Qt::Checked); + else + item->setCheckState(Qt::Unchecked); + } + ui->listFeeds->setEnabled(current != 0); +} + +bool AutomatedRssDownloader::isRssDownloaderEnabled() const +{ + return ui->checkEnableDownloader->isChecked(); +} + +void AutomatedRssDownloader::updateRuleDefinitionBox(QListWidgetItem* current, QListWidgetItem* previous) +{ + qDebug() << Q_FUNC_INFO << current << previous; + // Save previous item + saveCurrentRule(previous); + // Update rule definition box + RssDownloadRule rule = getCurrentRule(); + if(rule.isValid()) { + ui->lineContains->setText(rule.mustContain()); + ui->lineNotContains->setText(rule.mustNotContain()); + ui->saveDiffDir_check->setChecked(!rule.savePath().isEmpty()); + ui->lineSavePath->setText(rule.savePath()); + if(rule.label().isEmpty()) { + ui->comboLabel->setCurrentIndex(-1); + ui->comboLabel->clearEditText(); + } else { + ui->comboLabel->setCurrentIndex(ui->comboLabel->findText(rule.label())); + } + // Enable + ui->ruleDefBox->setEnabled(true); + } else { + // Clear + ui->lineNotContains->clear(); + ui->saveDiffDir_check->setChecked(false); + ui->lineSavePath->clear(); + ui->comboLabel->clearEditText(); + if(current) { + // Use the rule name as a default for the "contains" field + ui->lineContains->setText(current->text()); + ui->ruleDefBox->setEnabled(true); + } else { + ui->lineContains->clear(); + ui->ruleDefBox->setEnabled(false); + } + } +} + +RssDownloadRule AutomatedRssDownloader::getCurrentRule() const +{ + QListWidgetItem * current_item = ui->listRules->currentItem(); + if(current_item) + return m_ruleList->getRule(current_item->text()); + return RssDownloadRule(); +} + +void AutomatedRssDownloader::initLabelCombobox() +{ + // Load custom labels + const QStringList customLabels = Preferences::getTorrentLabels(); + foreach(const QString& label, customLabels) { + ui->comboLabel->addItem(label); + } +} + +void AutomatedRssDownloader::saveCurrentRule(QListWidgetItem * item) +{ + qDebug() << Q_FUNC_INFO << item; + if(!item) return; + RssDownloadRule rule = m_ruleList->getRule(item->text()); + if(!rule.isValid()) { + rule.setName(item->text()); + } + if(item->checkState() == Qt::Unchecked) + rule.setEnabled(false); + else + rule.setEnabled(true); + rule.setMustContain(ui->lineContains->text()); + rule.setMustNotContain(ui->lineNotContains->text()); + if(ui->saveDiffDir_check->isChecked()) + rule.setSavePath(ui->lineSavePath->text()); + else + rule.setSavePath(""); + rule.setLabel(ui->comboLabel->currentText()); + // Save new label + if(!rule.label().isEmpty()) + Preferences::addTorrentLabel(rule.label()); + rule.setRssFeeds(getSelectedFeeds()); + // Save it + m_ruleList->saveRule(rule); +} + + +void AutomatedRssDownloader::on_addRuleBtn_clicked() +{ + // Ask for a rule name + const QString rule = QInputDialog::getText(this, tr("New rule name"), tr("Please type the name of the new download rule.")); + if(rule.isEmpty()) return; + // Check if this rule name already exists + if(m_ruleList->getRule(rule).isValid()) { + QMessageBox::warning(this, tr("Rule name conflict"), tr("A rule with this name already exists, please choose another name.")); + return; + } + // Add the new rule to the list + QListWidgetItem * item = new QListWidgetItem(rule, ui->listRules); + item->setFlags(item->flags()|Qt::ItemIsUserCheckable); + item->setCheckState(Qt::Checked); // Enable as a default + ui->listRules->setCurrentItem(item); +} + +void AutomatedRssDownloader::on_removeRuleBtn_clicked() +{ + QListWidgetItem * item = ui->listRules->currentItem(); + if(!item) return; + // Ask for confirmation + if(QMessageBox::question(this, tr("Rule deletion confirmation"), tr("Are you sure you want to remove the download rule named %1?").arg(item->text())) != QMessageBox::Yes) + return; + // Actually remove the item + ui->listRules->removeItemWidget(item); + // Clean up memory + delete item; +} + +void AutomatedRssDownloader::on_browseSP_clicked() +{ + QString save_path = QFileDialog::getExistingDirectory(this, tr("Destination directory"), QDir::homePath()); + if(!save_path.isEmpty()) + ui->lineSavePath->setText(save_path); } diff --git a/src/rss/automatedrssdownloader.h b/src/rss/automatedrssdownloader.h index 6a6c84dbd..e32179a7c 100644 --- a/src/rss/automatedrssdownloader.h +++ b/src/rss/automatedrssdownloader.h @@ -32,11 +32,15 @@ #define AUTOMATEDRSSDOWNLOADER_H #include +#include "rssdownloadrule.h" namespace Ui { class AutomatedRssDownloader; } +class RssDownloadRuleList; +class QListWidgetItem; + class AutomatedRssDownloader : public QDialog { Q_OBJECT @@ -44,13 +48,30 @@ class AutomatedRssDownloader : public QDialog public: explicit AutomatedRssDownloader(QWidget *parent = 0); ~AutomatedRssDownloader(); + bool isRssDownloaderEnabled() const; protected slots: void loadSettings(); void saveSettings(); + void loadRulesList(); + void updateRuleDefinitionBox(QListWidgetItem* current = 0, QListWidgetItem* previous = 0); + void saveCurrentRule(QListWidgetItem * item); + void loadFeedList(); + void updateFeedList(QListWidgetItem* current, QListWidgetItem* previous); + +private slots: + void on_addRuleBtn_clicked(); + void on_removeRuleBtn_clicked(); + void on_browseSP_clicked(); + +private: + RssDownloadRule getCurrentRule() const; + void initLabelCombobox(); + QStringList getSelectedFeeds() const; private: Ui::AutomatedRssDownloader *ui; + RssDownloadRuleList *m_ruleList; }; #endif // AUTOMATEDRSSDOWNLOADER_H diff --git a/src/rss/automatedrssdownloader.ui b/src/rss/automatedrssdownloader.ui index eb711212e..a7cc9b2a5 100644 --- a/src/rss/automatedrssdownloader.ui +++ b/src/rss/automatedrssdownloader.ui @@ -161,23 +161,33 @@ - + + + false + - Save torrent to: + Save to: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - + - + + + false + + + + false + ... @@ -185,24 +195,7 @@ - - - - Assign label: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - true - - - - + @@ -222,6 +215,30 @@ + + + + Save to a different directory + + + + + + + Assign label: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + true + + + @@ -259,14 +276,45 @@ - - - Qt::Horizontal - - - QDialogButtonBox::Close - - + + + + + Import... + + + + + + + Export... + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + @@ -281,8 +329,8 @@ accept() - 248 - 254 + 750 + 483 157 @@ -297,8 +345,8 @@ reject() - 316 - 260 + 805 + 483 286 @@ -306,5 +354,53 @@ + + saveDiffDir_check + toggled(bool) + label_6 + setEnabled(bool) + + + 304 + 171 + + + 377 + 205 + + + + + saveDiffDir_check + toggled(bool) + lineSavePath + setEnabled(bool) + + + 474 + 174 + + + 476 + 204 + + + + + saveDiffDir_check + toggled(bool) + browseSP + setEnabled(bool) + + + 544 + 166 + + + 549 + 209 + + + diff --git a/src/rss/rss.ui b/src/rss/rss.ui index e2440ed45..448fe257d 100644 --- a/src/rss/rss.ui +++ b/src/rss/rss.ui @@ -89,6 +89,13 @@ + + + + RSS Downloader... + + + @@ -275,15 +282,6 @@ p, li { white-space: pre-wrap; } Copy feed URL - - - - :/Icons/oxygen/download.png:/Icons/oxygen/download.png - - - RSS feed downloader... - - diff --git a/src/rss/rss_imp.cpp b/src/rss/rss_imp.cpp index acc3f90f5..763497c26 100644 --- a/src/rss/rss_imp.cpp +++ b/src/rss/rss_imp.cpp @@ -38,7 +38,6 @@ #include #include "rss_imp.h" -#include "feeddownloader.h" #include "feedlistwidget.h" #include "qbtsession.h" #include "cookiesdlg.h" @@ -48,6 +47,7 @@ #include "rssfolder.h" #include "rssarticle.h" #include "rssfeed.h" +#include "automatedrssdownloader.h" enum NewsCols { NEWS_ICON, NEWS_TITLE_COL, NEWS_URL_COL, NEWS_ID }; @@ -79,10 +79,6 @@ void RSSImp::displayRSSListMenu(const QPoint& pos){ if(listStreams->getItemType(selectedItems.first()) == RssFile::FEED) { myRSSListMenu.addSeparator(); myRSSListMenu.addAction(actionCopy_feed_URL); - if(selectedItems.size() == 1) { - myRSSListMenu.addSeparator(); - myRSSListMenu.addAction(actionRSS_feed_downloader); - } } }else{ myRSSListMenu.addAction(actionNew_subscription); @@ -393,15 +389,6 @@ void RSSImp::copySelectedFeedsURL() { qApp->clipboard()->setText(URLs.join("\n")); } -void RSSImp::showFeedDownloader() { - QTreeWidgetItem* item = listStreams->selectedItems()[0]; - RssFile* rss_item = listStreams->getRSSItem(item); - if(rss_item->getType() == RssFile::FEED) { - FeedDownloaderDlg* feedDownloader = new FeedDownloaderDlg(this, listStreams->getItemID(item), rss_item->getName(), BTSession); - connect(feedDownloader, SIGNAL(filteringEnabled()), this, SLOT(on_updateAllButton_clicked())); - } -} - void RSSImp::on_markReadButton_clicked() { QList selectedItems = listStreams->selectedItems(); QTreeWidgetItem* item; @@ -620,7 +607,6 @@ RSSImp::RSSImp(QBtSession *BTSession) : QWidget(), BTSession(BTSession){ connect(actionNew_subscription, SIGNAL(triggered()), this, SLOT(on_newFeedButton_clicked())); connect(actionUpdate_all_feeds, SIGNAL(triggered()), this, SLOT(on_updateAllButton_clicked())); connect(actionCopy_feed_URL, SIGNAL(triggered()), this, SLOT(copySelectedFeedsURL())); - connect(actionRSS_feed_downloader, SIGNAL(triggered()), this, SLOT(showFeedDownloader())); connect(actionMark_items_read, SIGNAL(triggered()), this, SLOT(on_markReadButton_clicked())); // News list actions connect(actionOpen_news_URL, SIGNAL(triggered()), this, SLOT(openNewsUrl())); @@ -658,3 +644,11 @@ void RSSImp::on_settingsButton_clicked() { if(dlg.exec()) updateRefreshInterval(Preferences::getRefreshInterval()); } + +void RSSImp::on_rssDownloaderBtn_clicked() +{ + AutomatedRssDownloader dlg(this); + dlg.exec(); + if(dlg.isRssDownloaderEnabled()) + on_updateAllButton_clicked(); +} diff --git a/src/rss/rss_imp.h b/src/rss/rss_imp.h index 5fd177b16..0147883e6 100644 --- a/src/rss/rss_imp.h +++ b/src/rss/rss_imp.h @@ -73,7 +73,6 @@ protected slots: void fillFeedsList(QTreeWidgetItem *parent=0, RssFolder *rss_parent=0); void saveSlidersPosition(); void restoreSlidersPosition(); - void showFeedDownloader(); void askNewFolder(); void saveFoldersOpenState(); void loadFoldersOpenState(); @@ -81,6 +80,9 @@ protected slots: void on_actionManage_cookies_triggered(); void on_settingsButton_clicked(); +private slots: + void on_rssDownloaderBtn_clicked(); + private: RssManager *rssmanager; QBtSession *BTSession; diff --git a/src/rss/rssdownloadrule.cpp b/src/rss/rssdownloadrule.cpp index b9def9f39..c3efe0a9c 100644 --- a/src/rss/rssdownloadrule.cpp +++ b/src/rss/rssdownloadrule.cpp @@ -31,6 +31,7 @@ #include #include "rssdownloadrule.h" +#include "preferences.h" #include "qinisettings.h" RssDownloadRule::RssDownloadRule() @@ -66,7 +67,7 @@ void RssDownloadRule::setMustNotContain(const QString &tokens) m_mustNotContain = tokens.split(QRegExp("[\\s|]")); } -RssDownloadRule RssDownloadRule::fromOldFormat(const QHash &rule_hash, const QString &feed_url, const QString &rule_name) +RssDownloadRule RssDownloadRule::fromOldFormat(const QVariantHash &rule_hash, const QString &feed_url, const QString &rule_name) { RssDownloadRule rule; rule.setName(rule_name); @@ -82,7 +83,7 @@ RssDownloadRule RssDownloadRule::fromOldFormat(const QHash &r return rule; } -RssDownloadRule RssDownloadRule::fromNewFormat(const QHash &rule_hash) +RssDownloadRule RssDownloadRule::fromNewFormat(const QVariantHash &rule_hash) { RssDownloadRule rule; rule.setName(rule_hash.value("name").toString()); @@ -90,16 +91,18 @@ RssDownloadRule RssDownloadRule::fromNewFormat(const QHash &r rule.setMustNotContain(rule_hash.value("must_not_contain").toString()); rule.setRssFeeds(rule_hash.value("affected_feeds").toStringList()); rule.setEnabled(rule_hash.value("enabled", false).toBool()); + rule.setSavePath(rule_hash.value("save_path").toString()); rule.setLabel(rule_hash.value("label_assigned").toString()); return rule; } -QHash RssDownloadRule::toHash() const +QVariantHash RssDownloadRule::toVariantHash() const { - QHash hash; + QVariantHash hash; hash["name"] = m_name; hash["must_contain"] = m_mustContain.join(" "); hash["must_not_contain"] = m_mustNotContain.join(" "); + hash["save_path"] = m_savePath; hash["affected_feeds"] = m_rssFeeds; hash["enabled"] = m_enabled; hash["label_assigned"] = m_label; @@ -109,3 +112,11 @@ QHash RssDownloadRule::toHash() const bool RssDownloadRule::operator==(const RssDownloadRule &other) { return m_name == other.name(); } + +void RssDownloadRule::setSavePath(const QString &save_path) +{ + if(!save_path.isEmpty() && QDir(save_path) != QDir(Preferences::getSavePath())) + m_savePath = save_path; + else + m_savePath = QString(); +} diff --git a/src/rss/rssdownloadrule.h b/src/rss/rssdownloadrule.h index 2bc987272..3dab0116f 100644 --- a/src/rss/rssdownloadrule.h +++ b/src/rss/rssdownloadrule.h @@ -32,16 +32,16 @@ #define RSSDOWNLOADRULE_H #include -#include +#include class RssDownloadRule { public: explicit RssDownloadRule(); - static RssDownloadRule fromOldFormat(const QHash& rule_hash, const QString &feed_url, const QString &rule_name); // Before v2.5.0 - static RssDownloadRule fromNewFormat(const QHash &rule_hash); - QHash toHash() const; + static RssDownloadRule fromOldFormat(const QVariantHash& rule_hash, const QString &feed_url, const QString &rule_name); // Before v2.5.0 + static RssDownloadRule fromNewFormat(const QVariantHash &rule_hash); + QVariantHash toVariantHash() const; bool matches(const QString &article_title) const; void setMustContain(const QString &tokens); void setMustNotContain(const QString &tokens); @@ -50,11 +50,14 @@ public: inline QString name() const { return m_name; } inline void setName(const QString &name) { m_name = name; } inline QString savePath() const { return m_savePath; } - inline void setSavePath(const QString &save_path) { m_savePath = save_path; } + void setSavePath(const QString &save_path); inline QString label() const { return m_label; } inline void setLabel(const QString &_label) { m_label = _label; } inline bool isEnabled() const { return m_enabled; } inline void setEnabled(bool enable) { m_enabled = enable; } + inline bool isValid() const { return !m_name.isEmpty(); } + inline QString mustContain() const { return m_mustContain.join(" "); } + inline QString mustNotContain() const { return m_mustNotContain.join(" "); } // Operators bool operator==(const RssDownloadRule &other); diff --git a/src/rss/rssdownloadrulelist.cpp b/src/rss/rssdownloadrulelist.cpp index 699770032..cbc8904ee 100644 --- a/src/rss/rssdownloadrulelist.cpp +++ b/src/rss/rssdownloadrulelist.cpp @@ -50,19 +50,20 @@ void RssDownloadRuleList::drop() delete m_instance; } -const RssDownloadRule * RssDownloadRuleList::findMatchingRule(const QString &feed_url, const QString &article_title) const +RssDownloadRule RssDownloadRuleList::findMatchingRule(const QString &feed_url, const QString &article_title) const { - const QList rules = feedRules(feed_url); - foreach(const RssDownloadRule* rule, rules) { - if(rule->matches(article_title)) return rule; + QStringList rule_names = feedRules(feed_url); + foreach(const QString &rule_name, rule_names) { + RssDownloadRule rule = m_rules[rule_name]; + if(rule.isEnabled() && rule.matches(article_title)) return rule; } - return 0; + return RssDownloadRule(); } void RssDownloadRuleList::saveRulesToStorage() { QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss"); - qBTRSS.setValue("download_rules", toVariantList()); + qBTRSS.setValue("download_rules", toVariantHash()); } void RssDownloadRuleList::loadRulesFromStorage() @@ -77,7 +78,7 @@ void RssDownloadRuleList::loadRulesFromStorage() return; } // Load from new format - loadRulesFromVariantList(qBTRSS.value("download_rules").toList()); + loadRulesFromVariantHash(qBTRSS.value("download_rules").toHash()); } void RssDownloadRuleList::importRulesInOldFormat(const QHash &rules) @@ -86,42 +87,84 @@ void RssDownloadRuleList::importRulesInOldFormat(const QHash const QHash feed_rules = rules.value(feed_url).toHash(); foreach(const QString &rule_name, feed_rules.keys()) { RssDownloadRule rule = RssDownloadRule::fromOldFormat(feed_rules.value(rule_name).toHash(), feed_url, rule_name); + if(!rule.isValid()) continue; // Check for rule name clash - while(contains(rule)) { + while(m_rules.contains(rule.name())) { rule.setName(rule.name()+"_"); } // Add the rule to the list - append(rule); + saveRule(rule); } } } -void RssDownloadRuleList::append(const RssDownloadRule &rule) +QVariantHash RssDownloadRuleList::toVariantHash() const { - Q_ASSERT(!contains(rule)); - QList::append(rule); + QVariantHash ret; + foreach(const RssDownloadRule &rule, m_rules.values()) { + ret.insert(rule.name(), rule.toVariantHash()); + } + return ret; +} + +void RssDownloadRuleList::loadRulesFromVariantHash(const QVariantHash &h) +{ + foreach(const QVariant& v, h.values()) { + RssDownloadRule rule = RssDownloadRule::fromNewFormat(v.toHash()); + if(!rule.name().isEmpty()) { + saveRule(rule); + } + } +} + +void RssDownloadRuleList::saveRule(const RssDownloadRule &rule) +{ + Q_ASSERT(rule.isValid()); + m_rules.insert(rule.name(), rule); // Update feedRules hashtable foreach(const QString &feed_url, rule.rssFeeds()) { - m_feedRules[feed_url].append(&last()); + m_feedRules[feed_url].append(rule.name()); } + // Save rules + saveRulesToStorage(); } -QVariantList RssDownloadRuleList::toVariantList() const +void RssDownloadRuleList::removeRule(const QString &name) { - QVariantList l; - QList::const_iterator it; - for(it = begin(); it != end(); it++) { - l << it->toHash(); + if(!m_rules.contains(name)) return; + const RssDownloadRule rule = m_rules.take(name); + // Update feedRules hashtable + foreach(const QString &feed_url, rule.rssFeeds()) { + m_feedRules[feed_url].removeOne(rule.name()); } - return l; + // Save rules + saveRulesToStorage(); } -void RssDownloadRuleList::loadRulesFromVariantList(const QVariantList &l) +void RssDownloadRuleList::updateRule(const RssDownloadRule &rule) { - QVariantList::const_iterator it; - for(it=l.begin(); it !=l.end(); it++) { - RssDownloadRule rule = RssDownloadRule::fromNewFormat(it->toHash()); - if(!rule.name().isEmpty()) - append(rule); - } + if(!m_rules.contains(rule.name())) return; + removeRule(rule.name()); + saveRule(rule); + // Save rules + saveRulesToStorage(); +} + +void RssDownloadRuleList::renameRule(const QString &old_name, const QString &new_name) +{ + if(!m_rules.contains(old_name)) return; + RssDownloadRule rule = m_rules.take(old_name); + rule.setName(new_name); + m_rules.insert(new_name, rule); + // Update feedRules hashtable + foreach(const QString &feed_url, rule.rssFeeds()) { + m_feedRules[feed_url].replace(m_feedRules[feed_url].indexOf(old_name), new_name); + } + // Save rules + saveRulesToStorage(); +} + +RssDownloadRule RssDownloadRuleList::getRule(const QString &name) const +{ + return m_rules.value(name); } diff --git a/src/rss/rssdownloadrulelist.h b/src/rss/rssdownloadrulelist.h index f75ef40c8..cc26cbc54 100644 --- a/src/rss/rssdownloadrulelist.h +++ b/src/rss/rssdownloadrulelist.h @@ -33,12 +33,12 @@ #include #include -#include +#include #include "rssdownloadrule.h" // This class is not thread-safe (not required) -class RssDownloadRuleList : public QList +class RssDownloadRuleList { Q_DISABLE_COPY(RssDownloadRuleList) @@ -49,19 +49,26 @@ private: public: static RssDownloadRuleList* instance(); static void drop(); - const RssDownloadRule* findMatchingRule(const QString &feed_url, const QString &article_title) const; - inline QList feedRules(const QString &feed_url) const { return m_feedRules.value(feed_url); } - QVariantList toVariantList() const; - void append(const RssDownloadRule& rule); - void saveRulesToStorage(); + RssDownloadRule findMatchingRule(const QString &feed_url, const QString &article_title) const; + // Operators + void saveRule(const RssDownloadRule &rule); + void removeRule(const QString &name); + void updateRule(const RssDownloadRule &rule); + void renameRule(const QString &old_name, const QString &new_name); + RssDownloadRule getRule(const QString &name) const; + inline QStringList ruleNames() const { return m_rules.keys(); } private: void loadRulesFromStorage(); void importRulesInOldFormat(const QHash &rules); // Before v2.5.0 - void loadRulesFromVariantList(const QVariantList& l); + void loadRulesFromVariantHash(const QVariantHash& l); + QVariantHash toVariantHash() const; + void saveRulesToStorage(); + inline QStringList feedRules(const QString &feed_url) const { return m_feedRules[feed_url]; } private: - QHash > m_feedRules; + QHash m_rules; + QHash m_feedRules; }; diff --git a/src/rss/rssfeed.cpp b/src/rss/rssfeed.cpp index 90f240981..7f290a9f6 100644 --- a/src/rss/rssfeed.cpp +++ b/src/rss/rssfeed.cpp @@ -299,24 +299,13 @@ short RssFeed::readDoc(QIODevice* device) { else torrent_url = item->getLink(); // Check if the item should be automatically downloaded - RssFilter * matching_filter = RssFilters::getFeedFilters(url).matches(item->getTitle()); - if(matching_filter != 0) { + 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())); - if(matching_filter->isValid()) { - QString save_path = matching_filter->getSavePath(); - if(save_path.isEmpty()) - BTSession->downloadUrlAndSkipDialog(torrent_url); - else - BTSession->downloadUrlAndSkipDialog(torrent_url, save_path); - } else { - // All torrents are downloaded from this feed - BTSession->downloadUrlAndSkipDialog(torrent_url); - } + BTSession->downloadUrlAndSkipDialog(torrent_url, matching_rule.savePath(), matching_rule.label()); // Item was downloaded, consider it as Read item->setRead(); - // Clean up - delete matching_filter; } } return 0; diff --git a/src/rss/rssmanager.cpp b/src/rss/rssmanager.cpp index 3cc5bb92d..8e8049b5e 100644 --- a/src/rss/rssmanager.cpp +++ b/src/rss/rssmanager.cpp @@ -33,6 +33,7 @@ #include "qbtsession.h" #include "rssfeed.h" #include "rssarticle.h" +#include "rssdownloadrulelist.h" RssManager::RssManager(QBtSession *BTSession): RssFolder(0, this, BTSession, QString::null) { loadStreamList(); @@ -43,6 +44,7 @@ RssManager::RssManager(QBtSession *BTSession): RssFolder(0, this, BTSession, QSt RssManager::~RssManager(){ qDebug("Deleting RSSManager"); + RssDownloadRuleList::drop(); saveStreamList(); qDebug("RSSManager deleted"); } @@ -55,10 +57,9 @@ void RssManager::updateRefreshInterval(unsigned int val){ } } -void RssManager::loadStreamList(){ - QIniSettings settings("qBittorrent", "qBittorrent"); - QStringList streamsUrl = settings.value("Rss/streamList").toStringList(); - QStringList aliases = settings.value("Rss/streamAlias").toStringList(); +void RssManager::loadStreamList() { + const QStringList streamsUrl = RssSettings::getRssFeedsUrls(); + const QStringList aliases = RssSettings::getRssFeedsAliases(); if(streamsUrl.size() != aliases.size()){ std::cerr << "Corrupted Rss list, not loading it\n"; return; @@ -117,12 +118,8 @@ void RssManager::saveStreamList(){ streamsUrl << stream_path; aliases << stream->getName(); } - QIniSettings settings("qBittorrent", "qBittorrent"); - settings.beginGroup("Rss"); - // FIXME: Empty folder are not saved - settings.setValue("streamList", streamsUrl); - settings.setValue("streamAlias", aliases); - settings.endGroup(); + RssSettings::setRssFeedsUrls(streamsUrl); + RssSettings::setRssFeedsAliases(aliases); } void RssManager::insertSortElem(QList &list, RssArticle *item) { diff --git a/src/rss/rsssettings.h b/src/rss/rsssettings.h index 7c6d9516d..02ddbf9d0 100644 --- a/src/rss/rsssettings.h +++ b/src/rss/rsssettings.h @@ -68,7 +68,7 @@ public: static bool isRssDownloadingEnabled() { QIniSettings settings("qBittorrent", "qBittorrent"); - return settings.value("Preferences/RSS/RssDownloading", false).toBool(); + return settings.value("Preferences/RSS/RssDownloading", true).toBool(); } static void setRssDownloadingEnabled(bool b) { @@ -76,6 +76,25 @@ public: settings.setValue("Preferences/RSS/RssDownloading", b); } + static QStringList getRssFeedsUrls() { + QIniSettings settings("qBittorrent", "qBittorrent"); + return settings.value("Rss/streamList").toStringList(); + } + + static void setRssFeedsUrls(const QStringList &rssFeeds) { + QIniSettings settings("qBittorrent", "qBittorrent"); + settings.setValue("Rss/streamList", rssFeeds); + } + + static QStringList getRssFeedsAliases() { + QIniSettings settings("qBittorrent", "qBittorrent"); + return settings.value("Rss/streamAlias").toStringList(); + } + + static void setRssFeedsAliases(const QStringList &rssAliases) { + QIniSettings settings("qBittorrent", "qBittorrent"); + settings.setValue("Rss/streamAlias", rssAliases); + } }; #endif // RSSSETTINGS_H diff --git a/src/transferlistfilterswidget.h b/src/transferlistfilterswidget.h index 2187fd409..edde85112 100644 --- a/src/transferlistfilterswidget.h +++ b/src/transferlistfilterswidget.h @@ -45,6 +45,7 @@ #include "transferlistdelegate.h" #include "transferlistwidget.h" +#include "preferences.h" #include "qinisettings.h" class LabelFiltersList: public QListWidget { @@ -280,17 +281,10 @@ public: settings.setValue("customLabels", QVariant(customLabels.keys())); } - void saveCustomLabels() const { - QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - settings.beginGroup(QString::fromUtf8("TransferListFilters")); - settings.setValue("customLabels", QVariant(customLabels.keys())); - } - void loadSettings() { QIniSettings settings(QString::fromUtf8("qBittorrent"), QString::fromUtf8("qBittorrent")); - settings.beginGroup(QString::fromUtf8("TransferListFilters")); - statusFilters->setCurrentRow(settings.value("selectedFilterIndex", 0).toInt()); - QStringList label_list = settings.value("customLabels", QStringList()).toStringList(); + statusFilters->setCurrentRow(settings.value("TransferListFilters/selectedFilterIndex", 0).toInt()); + const QStringList label_list = Preferences::getTorrentLabels(); foreach(const QString &label, label_list) { customLabels.insert(label, 0); qDebug("Creating label QListWidgetItem: %s", qPrintable(label)); @@ -328,7 +322,7 @@ protected slots: newLabel->setData(Qt::DecorationRole, QIcon(":/Icons/oxygen/folder.png")); labelFilters->addItem(newLabel); customLabels.insert(label, 0); - saveCustomLabels(); + Preferences::addTorrentLabel(label); } void showLabelMenu(QPoint) { @@ -395,7 +389,7 @@ protected slots: // Un display filter delete labelFilters->takeItem(row); // Save custom labels to remember it was deleted - saveCustomLabels(); + Preferences::removeTorrentLabel(label); } void applyLabelFilter(int row) {