mirror of
https://github.com/d47081/qBittorrent.git
synced 2025-03-13 05:41:17 +00:00
Merge pull request #3567 from ngosang/rssfixes
[RSS] Several changes in RSSs. Closes #3560
This commit is contained in:
commit
70f2086202
@ -116,16 +116,12 @@
|
||||
<widget class="QLabel" name="news_lbl">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>50</weight>
|
||||
<bold>false</bold>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Torrents:</span> <span style=" font-style:italic;">(double-click to download)</span></p></body></html></string>
|
||||
<string>Torrents: (double-click to download)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -139,7 +135,7 @@ p, li { white-space: pre-wrap; }
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::SingleSelection</enum>
|
||||
<enum>QAbstractItemView::ExtendedSelection</enum>
|
||||
</property>
|
||||
<property name="selectionBehavior">
|
||||
<enum>QAbstractItemView::SelectItems</enum>
|
||||
|
@ -112,20 +112,31 @@ void RSSImp::displayItemsListMenu(const QPoint&)
|
||||
{
|
||||
QMenu myItemListMenu(this);
|
||||
QList<QListWidgetItem*> selectedItems = listArticles->selectedItems();
|
||||
if (selectedItems.size() > 0) {
|
||||
bool has_attachment = false;
|
||||
foreach (const QListWidgetItem* item, selectedItems) {
|
||||
if (m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString())
|
||||
->getItem(item->data(Article::IdRole).toString())->hasAttachment()) {
|
||||
has_attachment = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (has_attachment)
|
||||
myItemListMenu.addAction(actionDownload_torrent);
|
||||
myItemListMenu.addAction(actionOpen_news_URL);
|
||||
if (selectedItems.size() <= 0)
|
||||
return;
|
||||
|
||||
bool hasTorrent = false;
|
||||
bool hasLink = false;
|
||||
foreach (const QListWidgetItem* item, selectedItems) {
|
||||
if (!item) continue;
|
||||
RssFeedPtr feed = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
|
||||
if (!feed) continue;
|
||||
RssArticlePtr article = feed->getItem(item->data(Article::IdRole).toString());
|
||||
if (!article) continue;
|
||||
|
||||
if (!article->torrentUrl().isEmpty())
|
||||
hasTorrent = true;
|
||||
if (!article->link().isEmpty())
|
||||
hasLink = true;
|
||||
if (hasTorrent && hasLink)
|
||||
break;
|
||||
}
|
||||
myItemListMenu.exec(QCursor::pos());
|
||||
if (hasTorrent)
|
||||
myItemListMenu.addAction(actionDownload_torrent);
|
||||
if (hasLink)
|
||||
myItemListMenu.addAction(actionOpen_news_URL);
|
||||
if (hasTorrent || hasLink)
|
||||
myItemListMenu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void RSSImp::on_actionManage_cookies_triggered()
|
||||
@ -238,21 +249,13 @@ void RSSImp::deleteSelectedItems()
|
||||
QList<QTreeWidgetItem*> selectedItems = m_feedList->selectedItems();
|
||||
if (selectedItems.isEmpty())
|
||||
return;
|
||||
if ((selectedItems.size() == 1) && (selectedItems.first() == m_feedList->stickyUnreadItem()))
|
||||
return;
|
||||
|
||||
int ret;
|
||||
if (selectedItems.size() > 1) {
|
||||
ret = QMessageBox::question(this, tr("Are you sure? -- qBittorrent"), tr("Are you sure you want to delete these elements from the list?"),
|
||||
tr("&Yes"), tr("&No"),
|
||||
QString(), 0, 1);
|
||||
}
|
||||
else {
|
||||
if (selectedItems.first() == m_feedList->stickyUnreadItem())
|
||||
return;
|
||||
ret = QMessageBox::question(this, tr("Are you sure? -- qBittorrent"), tr("Are you sure you want to delete this element from the list?"),
|
||||
tr("&Yes"), tr("&No"),
|
||||
QString(), 0, 1);
|
||||
}
|
||||
if (ret)
|
||||
QMessageBox::StandardButton answer = QMessageBox::question(this, tr("Deletion confirmation"),
|
||||
tr("Are you sure you want to delete the selected RSS feeds?"),
|
||||
QMessageBox::Yes|QMessageBox::No, QMessageBox::No);
|
||||
if (answer == QMessageBox::No)
|
||||
return;
|
||||
|
||||
foreach (QTreeWidgetItem* item, selectedItems) {
|
||||
@ -337,31 +340,57 @@ void RSSImp::refreshAllFeeds()
|
||||
void RSSImp::downloadSelectedTorrents()
|
||||
{
|
||||
QList<QListWidgetItem*> selected_items = listArticles->selectedItems();
|
||||
foreach (const QListWidgetItem* item, selected_items) {
|
||||
if (selected_items.size() <= 0)
|
||||
return;
|
||||
foreach (QListWidgetItem* item, selected_items) {
|
||||
if (!item) continue;
|
||||
RssFeedPtr feed = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
|
||||
if (!feed) continue;
|
||||
RssArticlePtr article = feed->getItem(item->data(Article::IdRole).toString());
|
||||
if (!article) continue;
|
||||
|
||||
// Mark as read
|
||||
article->markAsRead();
|
||||
item->setData(Article::ColorRole, QVariant(QColor("grey")));
|
||||
item->setData(Article::IconRole, QVariant(QIcon(":/icons/sphere.png")));
|
||||
|
||||
if (article->torrentUrl().isEmpty())
|
||||
continue;
|
||||
if (Preferences::instance()->useAdditionDialog())
|
||||
AddNewTorrentDialog::show(article->torrentUrl());
|
||||
else
|
||||
BitTorrent::Session::instance()->addTorrent(article->torrentUrl());
|
||||
}
|
||||
// Decrement feed nb unread news
|
||||
updateItemInfos(m_feedList->stickyUnreadItem());
|
||||
updateItemInfos(m_feedList->getTreeItemFromUrl(selected_items.first()->data(Article::FeedUrlRole).toString()));
|
||||
}
|
||||
|
||||
// open the url of the selected RSS articles in the Web browser
|
||||
void RSSImp::openSelectedArticlesUrls()
|
||||
{
|
||||
QList<QListWidgetItem *> selected_items = listArticles->selectedItems();
|
||||
foreach (const QListWidgetItem* item, selected_items) {
|
||||
RssArticlePtr news = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString())
|
||||
->getItem(item->data(Article::IdRole).toString());
|
||||
const QString link = news->link();
|
||||
if (selected_items.size() <= 0)
|
||||
return;
|
||||
foreach (QListWidgetItem* item, selected_items) {
|
||||
if (!item) continue;
|
||||
RssFeedPtr feed = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
|
||||
if (!feed) continue;
|
||||
RssArticlePtr article = feed->getItem(item->data(Article::IdRole).toString());
|
||||
if (!article) continue;
|
||||
|
||||
// Mark as read
|
||||
article->markAsRead();
|
||||
item->setData(Article::ColorRole, QVariant(QColor("grey")));
|
||||
item->setData(Article::IconRole, QVariant(QIcon(":/icons/sphere.png")));
|
||||
|
||||
const QString link = article->link();
|
||||
if (!link.isEmpty())
|
||||
QDesktopServices::openUrl(QUrl(link));
|
||||
}
|
||||
// Decrement feed nb unread news
|
||||
updateItemInfos(m_feedList->stickyUnreadItem());
|
||||
updateItemInfos(m_feedList->getTreeItemFromUrl(selected_items.first()->data(Article::FeedUrlRole).toString()));
|
||||
}
|
||||
|
||||
//right-click on stream : give it an alias
|
||||
@ -538,21 +567,11 @@ void RSSImp::refreshTextBrowser()
|
||||
{
|
||||
QList<QListWidgetItem*> selection = listArticles->selectedItems();
|
||||
if (selection.empty()) return;
|
||||
Q_ASSERT(selection.size() == 1);
|
||||
QListWidgetItem *item = selection.first();
|
||||
Q_ASSERT(item);
|
||||
if (item == m_currentArticle) return;
|
||||
// Stop displaying previous news if necessary
|
||||
if (m_feedList->currentFeed() == m_feedList->stickyUnreadItem()) {
|
||||
if (m_currentArticle) {
|
||||
disconnect(listArticles, SIGNAL(itemSelectionChanged()), this, SLOT(refreshTextBrowser()));
|
||||
listArticles->removeItemWidget(m_currentArticle);
|
||||
Q_ASSERT(m_currentArticle);
|
||||
delete m_currentArticle;
|
||||
connect(listArticles, SIGNAL(itemSelectionChanged()), this, SLOT(refreshTextBrowser()));
|
||||
}
|
||||
m_currentArticle = item;
|
||||
}
|
||||
m_currentArticle = item;
|
||||
|
||||
RssFeedPtr stream = m_feedList->getRSSItemFromUrl(item->data(Article::FeedUrlRole).toString());
|
||||
RssArticlePtr article = stream->getItem(item->data(Article::IdRole).toString());
|
||||
QString html;
|
||||
@ -675,14 +694,11 @@ void RSSImp::onFeedContentChanged(const QString& url)
|
||||
qDebug() << Q_FUNC_INFO << url;
|
||||
QTreeWidgetItem *item = m_feedList->getTreeItemFromUrl(url);
|
||||
// If the feed is selected, update the displayed news
|
||||
if (m_feedList->currentItem() == item ) {
|
||||
if (m_feedList->currentItem() == item)
|
||||
populateArticleList(item);
|
||||
}
|
||||
else {
|
||||
// Update unread items
|
||||
if (m_feedList->currentItem() == m_feedList->stickyUnreadItem())
|
||||
populateArticleList(m_feedList->stickyUnreadItem());
|
||||
}
|
||||
// Update unread items
|
||||
else if (m_feedList->currentItem() == m_feedList->stickyUnreadItem())
|
||||
populateArticleList(m_feedList->stickyUnreadItem());
|
||||
}
|
||||
|
||||
void RSSImp::updateRefreshInterval(uint val)
|
||||
@ -715,8 +731,6 @@ RSSImp::RSSImp(QWidget *parent):
|
||||
|
||||
m_feedList = new FeedListWidget(splitter_h, m_rssManager);
|
||||
splitter_h->insertWidget(0, m_feedList);
|
||||
listArticles->setSelectionBehavior(QAbstractItemView::SelectItems);
|
||||
listArticles->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
editHotkey = new QShortcut(QKeySequence("F2"), m_feedList, 0, 0, Qt::WidgetShortcut);
|
||||
connect(editHotkey, SIGNAL(activated()), SLOT(renameSelectedRssFile()));
|
||||
connect(m_feedList, SIGNAL(doubleClicked(QModelIndex)), SLOT(renameSelectedRssFile()));
|
||||
|
@ -82,7 +82,7 @@ const QString& RssArticle::author() const {
|
||||
}
|
||||
|
||||
const QString& RssArticle::torrentUrl() const {
|
||||
return m_torrentUrl.isEmpty() ? m_link : m_torrentUrl;
|
||||
return m_torrentUrl;
|
||||
}
|
||||
|
||||
const QString& RssArticle::link() const {
|
||||
@ -123,6 +123,6 @@ const QString& RssArticle::title() const
|
||||
}
|
||||
|
||||
void RssArticle::handleTorrentDownloadSuccess(const QString &url) {
|
||||
if (url == m_torrentUrl || url == m_link)
|
||||
if (url == m_torrentUrl)
|
||||
markAsRead();
|
||||
}
|
||||
|
@ -364,6 +364,12 @@ void RssFeed::downloadArticleTorrentIfMatching(RssDownloadRuleList* rules, const
|
||||
rules->saveRulesToStorage();
|
||||
// Download the torrent
|
||||
const QString& torrent_url = article->torrentUrl();
|
||||
if (torrent_url.isEmpty()) {
|
||||
Logger::instance()->addMessage(tr("Automatic download %1 from %2 RSS feed failed because it doesn't contain a torrent or a magnet link...").arg(article->title()).arg(displayName()), Log::WARNING);
|
||||
article->markAsRead();
|
||||
return;
|
||||
}
|
||||
|
||||
Logger::instance()->addMessage(tr("Automatically downloading %1 torrent from %2 RSS feed...").arg(article->title()).arg(displayName()));
|
||||
connect(BitTorrent::Session::instance(), SIGNAL(downloadFromUrlFinished(QString)), article.data(), SLOT(handleTorrentDownloadSuccess(const QString&)), Qt::UniqueConnection);
|
||||
connect(article.data(), SIGNAL(articleWasRead()), SLOT(handleArticleStateChanged()), Qt::UniqueConnection);
|
||||
|
@ -254,24 +254,32 @@ void RssParser::parseRssArticle(QXmlStreamReader& xml, const QString& feedUrl)
|
||||
|
||||
if (xml.isStartElement()) {
|
||||
if (xml.name() == "title")
|
||||
article["title"] = xml.readElementText();
|
||||
article["title"] = xml.readElementText().trimmed();
|
||||
else if (xml.name() == "enclosure") {
|
||||
if (xml.attributes().value("type") == "application/x-bittorrent")
|
||||
article["torrent_url"] = xml.attributes().value("url").toString();
|
||||
}
|
||||
else if (xml.name() == "link")
|
||||
article["news_link"] = xml.readElementText();
|
||||
else if (xml.name() == "link") {
|
||||
QString link = xml.readElementText().trimmed();
|
||||
if (link.startsWith("magnet:", Qt::CaseInsensitive))
|
||||
article["torrent_url"] = link; // magnet link instead of a news URL
|
||||
else
|
||||
article["news_link"] = link;
|
||||
}
|
||||
else if (xml.name() == "description")
|
||||
article["description"] = xml.readElementText();
|
||||
article["description"] = xml.readElementText().trimmed();
|
||||
else if (xml.name() == "pubDate")
|
||||
article["date"] = parseDate(xml.readElementText());
|
||||
article["date"] = parseDate(xml.readElementText().trimmed());
|
||||
else if (xml.name() == "author")
|
||||
article["author"] = xml.readElementText();
|
||||
article["author"] = xml.readElementText().trimmed();
|
||||
else if (xml.name() == "guid")
|
||||
article["id"] = xml.readElementText();
|
||||
article["id"] = xml.readElementText().trimmed();
|
||||
}
|
||||
}
|
||||
|
||||
if (!article.contains("torrent_url") && article.contains("news_link"))
|
||||
article["torrent_url"] = article["news_link"];
|
||||
|
||||
if (!article.contains("id")) {
|
||||
// Item does not have a guid, fall back to some other identifier
|
||||
const QString link = article.value("news_link").toString();
|
||||
@ -338,20 +346,21 @@ void RssParser::parseAtomArticle(QXmlStreamReader& xml, const QString& feedUrl,
|
||||
// Workaround for CDATA (QString cannot parse html escapes on it's own)
|
||||
QTextDocument doc;
|
||||
doc.setHtml(xml.readElementText());
|
||||
article["title"] = doc.toPlainText();
|
||||
article["title"] = doc.toPlainText().trimmed();
|
||||
}
|
||||
else if (xml.name() == "link") {
|
||||
QString theLink = ( xml.attributes().isEmpty() ?
|
||||
xml.readElementText() :
|
||||
xml.attributes().value("href").toString() );
|
||||
QString link = ( xml.attributes().isEmpty() ?
|
||||
xml.readElementText().trimmed() :
|
||||
xml.attributes().value("href").toString() );
|
||||
|
||||
// Atom feeds can have relative links, work around this and
|
||||
// take the stress of figuring article full URI from UI
|
||||
if (link.startsWith("magnet:", Qt::CaseInsensitive))
|
||||
article["torrent_url"] = link; // magnet link instead of a news URL
|
||||
else
|
||||
// Atom feeds can have relative links, work around this and
|
||||
// take the stress of figuring article full URI from UI
|
||||
// Assemble full URI
|
||||
article["news_link"] = ( baseUrl.isEmpty() ? link : baseUrl + link );
|
||||
|
||||
// Assemble full URI
|
||||
article["news_link"] = ( baseUrl.isEmpty() ?
|
||||
theLink :
|
||||
baseUrl + theLink );
|
||||
}
|
||||
else if (xml.name() == "summary" || xml.name() == "content"){
|
||||
if(double_content) { // Duplicate content -> ignore
|
||||
@ -367,13 +376,13 @@ void RssParser::parseAtomArticle(QXmlStreamReader& xml, const QString& feedUrl,
|
||||
// Actually works great for non-broken content too
|
||||
QString feedText = xml.readElementText(QXmlStreamReader::IncludeChildElements);
|
||||
if (!feedText.isEmpty())
|
||||
article["description"] = feedText;
|
||||
article["description"] = feedText.trimmed();
|
||||
|
||||
double_content = true;
|
||||
}
|
||||
else if (xml.name() == "updated"){
|
||||
// ATOM uses standard compliant date, don't do fancy stuff
|
||||
QDateTime articleDate = QDateTime::fromString(xml.readElementText(), Qt::ISODate);
|
||||
QDateTime articleDate = QDateTime::fromString(xml.readElementText().trimmed(), Qt::ISODate);
|
||||
article["date"] = ( articleDate.isValid() ?
|
||||
articleDate :
|
||||
QDateTime::currentDateTime() );
|
||||
@ -382,15 +391,18 @@ void RssParser::parseAtomArticle(QXmlStreamReader& xml, const QString& feedUrl,
|
||||
xml.readNext();
|
||||
while(xml.name() != "author") {
|
||||
if(xml.name() == "name")
|
||||
article["author"] = xml.readElementText();
|
||||
article["author"] = xml.readElementText().trimmed();
|
||||
xml.readNext();
|
||||
}
|
||||
}
|
||||
else if (xml.name() == "id")
|
||||
article["id"] = xml.readElementText();
|
||||
article["id"] = xml.readElementText().trimmed();
|
||||
}
|
||||
}
|
||||
|
||||
if (!article.contains("torrent_url") && article.contains("news_link"))
|
||||
article["torrent_url"] = article["news_link"];
|
||||
|
||||
if (!article.contains("id")) {
|
||||
// Item does not have a guid, fall back to some other identifier
|
||||
const QString link = article.value("news_link").toString();
|
||||
|
Loading…
x
Reference in New Issue
Block a user