Made good progress on the new rss feed downloader

This commit is contained in:
Christophe Dumez 2010-11-13 10:49:22 +00:00
parent d2754fb242
commit 8b83d60732
17 changed files with 553 additions and 157 deletions

View file

@ -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<QByteArray> &cookies) {
QIniSettings qBTRSS("qBittorrent", "qBittorrent-rss");
QMap<QString, QVariant> hosts_table = qBTRSS.value("hosts_cookies", QMap<QString, QVariant>()).toMap();

View file

@ -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<QString, QString> 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);

View file

@ -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<QTimer> timerAlerts;
QPointer<BandwidthScheduler> bd_scheduler;
QMap<QUrl, QString> savepath_fromurl;
QMap<QUrl, QPair<QString, QString> > savepathLabel_fromurl;
QHash<QString, QHash<QString, TrackerInfos> > trackersInfos;
QHash<QString, QString> savePathsToRemove;
QStringList torrentsToPausedAfterChecking;

View file

@ -28,32 +28,230 @@
* Contact : chris@qbittorrent.org
*/
#include <QInputDialog>
#include <QMessageBox>
#include <QFileDialog>
#include <QDebug>
#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; i<feed_aliases.size(); ++i) {
QListWidgetItem *item = new QListWidgetItem(feed_aliases.at(i), ui->listFeeds);
item->setData(Qt::UserRole, feed_urls.at(i));
item->setFlags(item->flags()|Qt::ItemIsUserCheckable);
}
}
QStringList AutomatedRssDownloader::getSelectedFeeds() const
{
QStringList feeds;
for(int i=0; i<ui->listFeeds->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; i<ui->listFeeds->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);
}

View file

@ -32,11 +32,15 @@
#define AUTOMATEDRSSDOWNLOADER_H
#include <QDialog>
#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

View file

@ -161,23 +161,33 @@
<item row="1" column="1">
<widget class="QLineEdit" name="lineNotContains"/>
</item>
<item row="2" column="0">
<item row="4" column="0">
<widget class="QLabel" name="label_6">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Save torrent to:</string>
<string>Save to:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="4" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLineEdit" name="lineSavePath"/>
<widget class="QLineEdit" name="lineSavePath">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="browseSP">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>...</string>
</property>
@ -185,24 +195,7 @@
</item>
</layout>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Assign label:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="comboLabel">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<item row="6" column="0" colspan="2">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QLabel" name="label_2">
@ -222,6 +215,30 @@
</item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<widget class="QCheckBox" name="saveDiffDir_check">
<property name="text">
<string>Save to a different directory</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Assign label:</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboLabel">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -259,14 +276,45 @@
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="importBtn">
<property name="text">
<string>Import...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="exportBtn">
<property name="text">
<string>Export...</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
@ -281,8 +329,8 @@
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
<x>750</x>
<y>483</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
@ -297,8 +345,8 @@
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
<x>805</x>
<y>483</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
@ -306,5 +354,53 @@
</hint>
</hints>
</connection>
<connection>
<sender>saveDiffDir_check</sender>
<signal>toggled(bool)</signal>
<receiver>label_6</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>304</x>
<y>171</y>
</hint>
<hint type="destinationlabel">
<x>377</x>
<y>205</y>
</hint>
</hints>
</connection>
<connection>
<sender>saveDiffDir_check</sender>
<signal>toggled(bool)</signal>
<receiver>lineSavePath</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>474</x>
<y>174</y>
</hint>
<hint type="destinationlabel">
<x>476</x>
<y>204</y>
</hint>
</hints>
</connection>
<connection>
<sender>saveDiffDir_check</sender>
<signal>toggled(bool)</signal>
<receiver>browseSP</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>544</x>
<y>166</y>
</hint>
<hint type="destinationlabel">
<x>549</x>
<y>209</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -89,6 +89,13 @@
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="rssDownloaderBtn">
<property name="text">
<string>RSS Downloader...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="settingsButton">
<property name="text">
@ -275,15 +282,6 @@ p, li { white-space: pre-wrap; }
<string>Copy feed URL</string>
</property>
</action>
<action name="actionRSS_feed_downloader">
<property name="icon">
<iconset resource="../icons.qrc">
<normaloff>:/Icons/oxygen/download.png</normaloff>:/Icons/oxygen/download.png</iconset>
</property>
<property name="text">
<string>RSS feed downloader...</string>
</property>
</action>
<action name="actionNew_folder">
<property name="icon">
<iconset resource="../icons.qrc">

View file

@ -38,7 +38,6 @@
#include <QDragMoveEvent>
#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<QTreeWidgetItem*> 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();
}

View file

@ -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;

View file

@ -31,6 +31,7 @@
#include <QRegExp>
#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<QString, QVariant> &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<QString, QVariant> &r
return rule;
}
RssDownloadRule RssDownloadRule::fromNewFormat(const QHash<QString, QVariant> &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<QString, QVariant> &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<QString, QVariant> RssDownloadRule::toHash() const
QVariantHash RssDownloadRule::toVariantHash() const
{
QHash<QString, QVariant> 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<QString, QVariant> 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();
}

View file

@ -32,16 +32,16 @@
#define RSSDOWNLOADRULE_H
#include <QStringList>
#include <QHash>
#include <QVariantHash>
class RssDownloadRule
{
public:
explicit RssDownloadRule();
static RssDownloadRule fromOldFormat(const QHash<QString, QVariant>& rule_hash, const QString &feed_url, const QString &rule_name); // Before v2.5.0
static RssDownloadRule fromNewFormat(const QHash<QString, QVariant> &rule_hash);
QHash<QString, QVariant> 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);

View file

@ -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<RssDownloadRule*> 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<QString, QVariant> &rules)
@ -86,42 +87,84 @@ void RssDownloadRuleList::importRulesInOldFormat(const QHash<QString, QVariant>
const QHash<QString, QVariant> 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<RssDownloadRule>::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<RssDownloadRule>::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);
}

View file

@ -33,12 +33,12 @@
#include <QList>
#include <QHash>
#include <QVariantList>
#include <QVariantHash>
#include "rssdownloadrule.h"
// This class is not thread-safe (not required)
class RssDownloadRuleList : public QList<RssDownloadRule>
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<RssDownloadRule*> 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<QString, QVariant> &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<QString, QList<RssDownloadRule*> > m_feedRules;
QHash<QString, RssDownloadRule> m_rules;
QHash<QString, QStringList> m_feedRules;
};

View file

@ -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;

View file

@ -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<RssArticle*> &list, RssArticle *item) {

View file

@ -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

View file

@ -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) {