initial slim implementation of media player for qt6, will fix for qt5 and polish and integrate better later
This commit is contained in:
parent
53e6714642
commit
56c9e973df
31 changed files with 545 additions and 68 deletions
|
@ -140,7 +140,7 @@ set(QT_COMPONENTS
|
|||
)
|
||||
|
||||
if(NOT OS2)
|
||||
list(APPEND QT_COMPONENTS Multimedia)
|
||||
list(APPEND QT_COMPONENTS Multimedia MultimediaWidgets)
|
||||
endif()
|
||||
|
||||
if(WIN32 AND NOT BUILD_WITH_QT6)
|
||||
|
|
|
@ -381,7 +381,7 @@ version by clicking this popup notification.</source>
|
|||
<context>
|
||||
<name>BaseToastNotification</name>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/notifications/basetoastnotification.cpp" line="41"/>
|
||||
<location filename="../src/librssguard/gui/notifications/basetoastnotification.cpp" line="40"/>
|
||||
<source>Close this notification</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
@ -468,12 +468,12 @@ version by clicking this popup notification.</source>
|
|||
<context>
|
||||
<name>DiscoveredFeedsModel</name>
|
||||
<message>
|
||||
<location filename="../src/librssguard/services/standard/gui/formdiscoverfeeds.cpp" line="297"/>
|
||||
<location filename="../src/librssguard/services/standard/gui/formdiscoverfeeds.cpp" line="294"/>
|
||||
<source>Title</source>
|
||||
<translation type="unfinished">Title</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/services/standard/gui/formdiscoverfeeds.cpp" line="297"/>
|
||||
<location filename="../src/librssguard/services/standard/gui/formdiscoverfeeds.cpp" line="294"/>
|
||||
<source>Type</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
@ -1838,7 +1838,7 @@ QtWebEngine cache folder -> "%7"</source>
|
|||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/services/standard/gui/formdiscoverfeeds.ui" line="51"/>
|
||||
<source>Discover Sitemaps too (can take some time for bigger websites)</source>
|
||||
<source>Recursive discovery (can take some time for bigger websites)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
|
@ -1897,12 +1897,12 @@ QtWebEngine cache folder -> "%7"</source>
|
|||
<translation type="unfinished">Error: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/services/standard/gui/formdiscoverfeeds.cpp" line="195"/>
|
||||
<location filename="../src/librssguard/services/standard/gui/formdiscoverfeeds.cpp" line="192"/>
|
||||
<source>URL is valid.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/services/standard/gui/formdiscoverfeeds.cpp" line="198"/>
|
||||
<location filename="../src/librssguard/services/standard/gui/formdiscoverfeeds.cpp" line="195"/>
|
||||
<source>URL is NOT valid.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
@ -4496,6 +4496,59 @@ Login tokens expiration: %2</source>
|
|||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MediaPlayer</name>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/reusable/mediaplayer.ui" line="14"/>
|
||||
<source>Form</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/reusable/mediaplayer.cpp" line="134"/>
|
||||
<source>No media</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/reusable/mediaplayer.cpp" line="137"/>
|
||||
<source>Loading...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/reusable/mediaplayer.cpp" line="140"/>
|
||||
<source>Media loaded</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/reusable/mediaplayer.cpp" line="143"/>
|
||||
<source>Media stalled</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/reusable/mediaplayer.cpp" line="146"/>
|
||||
<source>Buffering...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/reusable/mediaplayer.cpp" line="149"/>
|
||||
<source>Loaded</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/reusable/mediaplayer.cpp" line="152"/>
|
||||
<source>Ended</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/reusable/mediaplayer.cpp" line="155"/>
|
||||
<source>Media is invalid</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/reusable/mediaplayer.cpp" line="158"/>
|
||||
<source>Unknown</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>MessageBrowser</name>
|
||||
<message>
|
||||
|
@ -5719,50 +5772,50 @@ List of supported readers:</source>
|
|||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/services/standard/parsers/atomparser.cpp" line="240"/>
|
||||
<location filename="../src/librssguard/services/standard/parsers/rdfparser.cpp" line="190"/>
|
||||
<location filename="../src/librssguard/services/standard/parsers/rssparser.cpp" line="190"/>
|
||||
<location filename="../src/librssguard/services/standard/parsers/sitemapparser.cpp" line="176"/>
|
||||
<location filename="../src/librssguard/services/standard/parsers/atomparser.cpp" line="242"/>
|
||||
<location filename="../src/librssguard/services/standard/parsers/rdfparser.cpp" line="192"/>
|
||||
<location filename="../src/librssguard/services/standard/parsers/rssparser.cpp" line="192"/>
|
||||
<location filename="../src/librssguard/services/standard/parsers/sitemapparser.cpp" line="180"/>
|
||||
<source>XML is not well-formed, %1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/services/standard/parsers/atomparser.cpp" line="246"/>
|
||||
<location filename="../src/librssguard/services/standard/parsers/atomparser.cpp" line="248"/>
|
||||
<source>not an ATOM feed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/services/standard/parsers/jsonparser.cpp" line="117"/>
|
||||
<location filename="../src/librssguard/services/standard/parsers/jsonparser.cpp" line="119"/>
|
||||
<source>JSON error '%1'</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/services/standard/parsers/jsonparser.cpp" line="148"/>
|
||||
<location filename="../src/librssguard/services/standard/parsers/jsonparser.cpp" line="150"/>
|
||||
<source>not a JSON feed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/services/standard/parsers/rdfparser.cpp" line="196"/>
|
||||
<location filename="../src/librssguard/services/standard/parsers/rdfparser.cpp" line="198"/>
|
||||
<source>not an RDF feed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/services/standard/parsers/rssparser.cpp" line="196"/>
|
||||
<location filename="../src/librssguard/services/standard/parsers/rssparser.cpp" line="198"/>
|
||||
<source>not a RSS feed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/services/standard/parsers/sitemapparser.cpp" line="141"/>
|
||||
<location filename="../src/librssguard/services/standard/parsers/sitemapparser.cpp" line="145"/>
|
||||
<source>support for gzipped sitemaps is not enabled</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/services/standard/parsers/sitemapparser.cpp" line="189"/>
|
||||
<location filename="../src/librssguard/services/standard/parsers/sitemapparser.cpp" line="193"/>
|
||||
<source>sitemap indices are not supported</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/services/standard/parsers/sitemapparser.cpp" line="193"/>
|
||||
<location filename="../src/librssguard/services/standard/parsers/sitemapparser.cpp" line="197"/>
|
||||
<source>not a Sitemap</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
@ -7895,22 +7948,27 @@ Unread news: %2</translation>
|
|||
<translation>Feeds</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/tabwidget.cpp" line="38"/>
|
||||
<location filename="../src/librssguard/gui/tabwidget.cpp" line="39"/>
|
||||
<source>Displays main menu.</source>
|
||||
<translation>Displays main menu.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/tabwidget.cpp" line="47"/>
|
||||
<location filename="../src/librssguard/gui/tabwidget.cpp" line="48"/>
|
||||
<source>Main menu</source>
|
||||
<translation>Main menu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/tabwidget.cpp" line="78"/>
|
||||
<location filename="../src/librssguard/gui/tabwidget.cpp" line="79"/>
|
||||
<source>Downloads</source>
|
||||
<translation>Downloads</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/tabwidget.cpp" line="237"/>
|
||||
<location filename="../src/librssguard/gui/tabwidget.cpp" line="232"/>
|
||||
<source>Media player</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/tabwidget.cpp" line="257"/>
|
||||
<source>Web browser</source>
|
||||
<translation>Web browser</translation>
|
||||
</message>
|
||||
|
@ -8439,12 +8497,17 @@ Last login on: %4</source>
|
|||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/webviewers/webengine/webengineviewer.cpp" line="109"/>
|
||||
<location filename="../src/librssguard/gui/webviewers/webengine/webengineviewer.cpp" line="104"/>
|
||||
<source>Open link as audio/video</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/webviewers/webengine/webengineviewer.cpp" line="113"/>
|
||||
<source>Open with external tool</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/librssguard/gui/webviewers/webengine/webengineviewer.cpp" line="128"/>
|
||||
<location filename="../src/librssguard/gui/webviewers/webengine/webengineviewer.cpp" line="132"/>
|
||||
<source>No external tools activated</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
<file>./graphics/Breeze/actions/32/arrow-right.svg</file>
|
||||
<file>./graphics/Breeze/actions/32/arrow-up.svg</file>
|
||||
<file>./graphics/Breeze/actions/32/arrow-up-double.svg</file>
|
||||
<file>./graphics/Breeze/status/22/audio-volume-muted.svg</file>
|
||||
<file>./graphics/Breeze/actions/32/call-start.svg</file>
|
||||
<file>./graphics/Breeze/actions/32/dialog-cancel.svg</file>
|
||||
<file>./graphics/Breeze/actions/22/dialog-close.svg</file>
|
||||
|
@ -77,7 +78,11 @@
|
|||
<file>./graphics/Breeze/actions/32/mail-reply-sender.svg</file>
|
||||
<file>./graphics/Breeze/actions/32/mail-send.svg</file>
|
||||
<file>./graphics/Breeze/actions/32/mail-sent.svg</file>
|
||||
<file>./graphics/Breeze/actions/32/media-playback-pause.svg</file>
|
||||
<file>./graphics/Breeze/actions/32/media-playback-start.svg</file>
|
||||
<file>./graphics/Breeze/actions/32/media-playback-stop.svg</file>
|
||||
<file>./graphics/Breeze/actions/22/player-volume.svg</file>
|
||||
<file>./graphics/Breeze/actions/22/player-volume-muted.svg</file>
|
||||
<file>./graphics/Breeze/actions/22/process-stop.svg</file>
|
||||
<file>./graphics/Breeze/actions/22/system-search.svg</file>
|
||||
<file>./graphics/Breeze/actions/22/system-upgrade.svg</file>
|
||||
|
@ -106,6 +111,7 @@
|
|||
<file>./graphics/Breeze Dark/actions/32/arrow-right.svg</file>
|
||||
<file>./graphics/Breeze Dark/actions/32/arrow-up.svg</file>
|
||||
<file>./graphics/Breeze Dark/actions/32/arrow-up-double.svg</file>
|
||||
<file>./graphics/Breeze Dark/status/22/audio-volume-muted.svg</file>
|
||||
<file>./graphics/Breeze Dark/actions/32/call-start.svg</file>
|
||||
<file>./graphics/Breeze Dark/actions/32/dialog-cancel.svg</file>
|
||||
<file>./graphics/Breeze Dark/actions/22/dialog-close.svg</file>
|
||||
|
@ -171,7 +177,11 @@
|
|||
<file>./graphics/Breeze Dark/actions/32/mail-reply-sender.svg</file>
|
||||
<file>./graphics/Breeze Dark/actions/32/mail-send.svg</file>
|
||||
<file>./graphics/Breeze Dark/actions/32/mail-sent.svg</file>
|
||||
<file>./graphics/Breeze Dark/actions/32/media-playback-pause.svg</file>
|
||||
<file>./graphics/Breeze Dark/actions/32/media-playback-start.svg</file>
|
||||
<file>./graphics/Breeze Dark/actions/32/media-playback-stop.svg</file>
|
||||
<file>./graphics/Breeze Dark/actions/22/player-volume.svg</file>
|
||||
<file>./graphics/Breeze Dark/actions/22/player-volume-muted.svg</file>
|
||||
<file>./graphics/Breeze Dark/actions/22/process-stop.svg</file>
|
||||
<file>./graphics/Breeze Dark/actions/22/system-search.svg</file>
|
||||
<file>./graphics/Breeze Dark/actions/22/system-upgrade.svg</file>
|
||||
|
@ -194,6 +204,7 @@
|
|||
<file>./graphics/Faenza/categories/64/applications-office.png</file>
|
||||
<file>./graphics/Faenza/categories/64/applications-science.png</file>
|
||||
<file>./graphics/Faenza/categories/64/applications-system.png</file>
|
||||
<file>./graphics/Faenza/status/64/audio-volume-muted.png</file>
|
||||
<file>./graphics/Faenza/actions/64/browser-download.png</file>
|
||||
<file>./graphics/Faenza/actions/64/call-start.png</file>
|
||||
<file>./graphics/Faenza/status/64/dialog-error.png</file>
|
||||
|
@ -256,7 +267,9 @@
|
|||
<file>./graphics/Faenza/actions/64/mail-reply-sender.png</file>
|
||||
<file>./graphics/Faenza/actions/64/mail-send.png</file>
|
||||
<file>./graphics/Faenza/actions/64/mail-sent.png</file>
|
||||
<file>./graphics/Faenza/actions/64/media-playback-pause.png</file>
|
||||
<file>./graphics/Faenza/actions/64/media-playback-start.png</file>
|
||||
<file>./graphics/Faenza/actions/64/media-playback-stop.png</file>
|
||||
<file>./graphics/Faenza/actions/64/process-stop.png</file>
|
||||
<file>./graphics/Faenza/actions/64/reload.png</file>
|
||||
<file>./graphics/Faenza/actions/64/system-search.png</file>
|
||||
|
@ -284,6 +297,7 @@
|
|||
<file>./graphics/Numix/22/actions/arrow-right.svg</file>
|
||||
<file>./graphics/Numix/22/actions/arrow-up.svg</file>
|
||||
<file>./graphics/Numix/22/actions/arrow-up-double.svg</file>
|
||||
<file>./graphics/Numix/22/status/audio-volume-muted.svg</file>
|
||||
<file>./graphics/Numix/22/actions/browser-download.svg</file>
|
||||
<file>./graphics/Numix/22/actions/call-start.svg</file>
|
||||
<file>./graphics/Numix/22/actions/dialog-cancel.svg</file>
|
||||
|
@ -349,7 +363,9 @@
|
|||
<file>./graphics/Numix/22/actions/mail-reply-sender.svg</file>
|
||||
<file>./graphics/Numix/22/actions/mail-send.svg</file>
|
||||
<file>./graphics/Numix/22/places/mail-sent.svg</file>
|
||||
<file>./graphics/Numix/22/actions/media-playback-pause.svg</file>
|
||||
<file>./graphics/Numix/22/actions/media-playback-start.svg</file>
|
||||
<file>./graphics/Numix/22/actions/media-playback-stop.svg</file>
|
||||
<file>./graphics/Numix/22/actions/process-stop.svg</file>
|
||||
<file>./graphics/Numix/22/actions/reload.svg</file>
|
||||
<file>./graphics/Numix/22/actions/system-search.svg</file>
|
||||
|
|
|
@ -133,6 +133,8 @@ set(SOURCES
|
|||
gui/reusable/locationlineedit.h
|
||||
gui/reusable/messagecountspinbox.cpp
|
||||
gui/reusable/messagecountspinbox.h
|
||||
gui/reusable/mediaplayer.cpp
|
||||
gui/reusable/mediaplayer.h
|
||||
gui/reusable/networkproxydetails.cpp
|
||||
gui/reusable/networkproxydetails.h
|
||||
gui/reusable/nonclosablemenu.cpp
|
||||
|
@ -464,6 +466,7 @@ set(UI_FILES
|
|||
gui/notifications/notificationseditor.ui
|
||||
gui/notifications/singlenotificationeditor.ui
|
||||
gui/notifications/toastnotification.ui
|
||||
gui/reusable/mediaplayer.ui
|
||||
gui/reusable/networkproxydetails.ui
|
||||
gui/reusable/searchtextwidget.ui
|
||||
gui/richtexteditor/mrichtextedit.ui
|
||||
|
@ -769,6 +772,7 @@ endif()
|
|||
if(NOT OS2)
|
||||
target_link_libraries(rssguard PUBLIC
|
||||
Qt${QT_VERSION_MAJOR}::Multimedia
|
||||
Qt${QT_VERSION_MAJOR}::MultimediaWidgets
|
||||
)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -673,7 +673,7 @@ void FormMain::loadSize() {
|
|||
setWindowState(windowState() | Qt::WindowState::WindowMaximized);
|
||||
|
||||
// We process events so that window is really maximized fast.
|
||||
qApp->processEvents();
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
|
||||
m_ui->m_actionMessagePreviewEnabled
|
||||
|
|
|
@ -244,7 +244,7 @@ void FeedMessageViewer::loadMessageToFeedAndArticleList(Feed* feed, const Messag
|
|||
// TODO: expand properly
|
||||
m_feedsView->setExpanded(idx_map, true);
|
||||
m_feedsView->setCurrentIndex(idx_map);
|
||||
qApp->processEvents();
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
auto idx_map_msg = m_messagesView->model()->indexFromMessage(message);
|
||||
auto msg_is_visible = !m_messagesView->isRowHidden(idx_map_msg.row(), idx_map_msg);
|
||||
|
|
|
@ -15,7 +15,6 @@ using namespace std::chrono_literals;
|
|||
|
||||
BaseToastNotification::BaseToastNotification(QWidget* parent) : QDialog(parent), m_timerId(-1) {
|
||||
setAttribute(Qt::WidgetAttribute::WA_ShowWithoutActivating);
|
||||
// setFixedWidth(qApp->settings()->value(GROUP(GUI), SETTING(GUI::ToastNotificationsWidth)).toInt());
|
||||
setFocusPolicy(Qt::FocusPolicy::NoFocus);
|
||||
setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose, false);
|
||||
|
||||
|
@ -82,7 +81,8 @@ bool BaseToastNotification::eventFilter(QObject* watched, QEvent* event) {
|
|||
if (event->type() == QEvent::Type::MouseButtonPress || event->type() == QEvent::Type::MouseButtonRelease) {
|
||||
if (dynamic_cast<QMouseEvent*>(event)->button() == Qt::MouseButton::RightButton) {
|
||||
event->accept();
|
||||
QTimer::singleShot(100, this, &BaseToastNotification::close);
|
||||
QCoreApplication::processEvents();
|
||||
QTimer::singleShot(200, this, &BaseToastNotification::close);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ void ToastNotificationsManager::processNotification(BaseToastNotification* notif
|
|||
|
||||
// Make sure notification is finally resized.
|
||||
notif->adjustSize();
|
||||
qApp->processEvents();
|
||||
QCoreApplication::processEvents();
|
||||
|
||||
// Move notification, at this point we already need to know its precise size.
|
||||
moveNotificationToCorner(notif, notif_new_pos);
|
||||
|
|
188
src/librssguard/gui/reusable/mediaplayer.cpp
Normal file
188
src/librssguard/gui/reusable/mediaplayer.cpp
Normal file
|
@ -0,0 +1,188 @@
|
|||
// For license of this file, see <project-root-folder>/LICENSE.md.
|
||||
|
||||
#include "mediaplayer.h"
|
||||
|
||||
#include "miscellaneous/iconfactory.h"
|
||||
|
||||
#if QT_VERSION_MAJOR == 6
|
||||
#include <QAudioOutput>
|
||||
#endif
|
||||
|
||||
MediaPlayer::MediaPlayer(QWidget* parent)
|
||||
: TabContent(parent),
|
||||
#if QT_VERSION_MAJOR == 6
|
||||
m_audio(new QAudioOutput(this)),
|
||||
#endif
|
||||
m_player(new QMediaPlayer(this)), m_muted(false) {
|
||||
m_ui.setupUi(this);
|
||||
|
||||
m_player->setVideoOutput(m_ui.m_video);
|
||||
m_player->setAudioOutput(m_audio);
|
||||
|
||||
setupIcons();
|
||||
createConnections();
|
||||
|
||||
onPlaybackStateChanged(QMediaPlayer::PlaybackState::StoppedState);
|
||||
onMediaStatusChanged(QMediaPlayer::MediaStatus::NoMedia);
|
||||
}
|
||||
|
||||
MediaPlayer::~MediaPlayer() {}
|
||||
|
||||
WebBrowser* MediaPlayer::webBrowser() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void MediaPlayer::playUrl(const QString& url) {
|
||||
setVolume(m_ui.m_slidVolume->value());
|
||||
|
||||
m_player->setSource(url);
|
||||
m_player->play();
|
||||
}
|
||||
|
||||
void MediaPlayer::playPause() {
|
||||
if (m_player->playbackState() != QMediaPlayer::PlaybackState::PlayingState) {
|
||||
m_player->play();
|
||||
}
|
||||
else {
|
||||
m_player->pause();
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlayer::stop() {
|
||||
m_player->stop();
|
||||
}
|
||||
|
||||
void MediaPlayer::download() {
|
||||
emit urlDownloadRequested(m_player->source());
|
||||
}
|
||||
|
||||
void MediaPlayer::muteUnmute() {
|
||||
m_ui.m_slidVolume->setEnabled(m_muted);
|
||||
setVolume(m_muted ? m_ui.m_slidVolume->value() : 0);
|
||||
|
||||
m_muted = !m_muted;
|
||||
}
|
||||
|
||||
void MediaPlayer::setVolume(int volume) {
|
||||
m_player->audioOutput()->setVolume(volume / 100.0f);
|
||||
m_ui.m_btnVolume->setIcon(volume <= 0 ? m_iconMute : m_iconUnmute);
|
||||
}
|
||||
|
||||
void MediaPlayer::seek(int position) {
|
||||
m_player->setPosition(position * 1000);
|
||||
}
|
||||
|
||||
void MediaPlayer::onDurationChanged(qint64 duration) {
|
||||
m_ui.m_slidProgress->blockSignals(true);
|
||||
m_ui.m_slidProgress->setMaximum(duration / 1000);
|
||||
m_ui.m_slidProgress->blockSignals(false);
|
||||
}
|
||||
|
||||
void MediaPlayer::onErrorOccurred(QMediaPlayer::Error error, const QString& error_string) {
|
||||
m_ui.m_lblStatus->setText(error_string);
|
||||
}
|
||||
|
||||
void MediaPlayer::onAudioAvailable(bool available) {
|
||||
m_ui.m_slidVolume->setEnabled(available);
|
||||
m_ui.m_btnVolume->setEnabled(available);
|
||||
}
|
||||
|
||||
void MediaPlayer::onVideoAvailable(bool available) {
|
||||
Q_UNUSED(available)
|
||||
}
|
||||
|
||||
void MediaPlayer::onMediaStatusChanged(QMediaPlayer::MediaStatus status) {
|
||||
m_ui.m_lblStatus->setText(mediaStatusToString(status));
|
||||
}
|
||||
|
||||
void MediaPlayer::onPlaybackStateChanged(QMediaPlayer::PlaybackState state) {
|
||||
switch (state) {
|
||||
case QMediaPlayer::StoppedState:
|
||||
m_ui.m_btnPlayPause->setIcon(m_iconPlay);
|
||||
m_ui.m_btnStop->setEnabled(false);
|
||||
break;
|
||||
|
||||
case QMediaPlayer::PlayingState:
|
||||
m_ui.m_btnPlayPause->setIcon(m_iconPause);
|
||||
m_ui.m_btnStop->setEnabled(true);
|
||||
break;
|
||||
|
||||
case QMediaPlayer::PausedState:
|
||||
m_ui.m_btnPlayPause->setIcon(m_iconPlay);
|
||||
m_ui.m_btnStop->setEnabled(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlayer::onPositionChanged(qint64 position) {
|
||||
m_ui.m_slidProgress->blockSignals(true);
|
||||
m_ui.m_slidProgress->setValue(position / 1000);
|
||||
m_ui.m_slidProgress->blockSignals(false);
|
||||
}
|
||||
|
||||
void MediaPlayer::onSeekableChanged(bool seekable) {
|
||||
m_ui.m_slidProgress->setEnabled(seekable);
|
||||
|
||||
if (!seekable) {
|
||||
onPositionChanged(0);
|
||||
}
|
||||
}
|
||||
|
||||
QString MediaPlayer::mediaStatusToString(QMediaPlayer::MediaStatus status) const {
|
||||
switch (status) {
|
||||
case QMediaPlayer::NoMedia:
|
||||
return tr("No media");
|
||||
|
||||
case QMediaPlayer::LoadingMedia:
|
||||
return tr("Loading...");
|
||||
|
||||
case QMediaPlayer::LoadedMedia:
|
||||
return tr("Media loaded");
|
||||
|
||||
case QMediaPlayer::StalledMedia:
|
||||
return tr("Media stalled");
|
||||
|
||||
case QMediaPlayer::BufferingMedia:
|
||||
return tr("Buffering...");
|
||||
|
||||
case QMediaPlayer::BufferedMedia:
|
||||
return tr("Loaded");
|
||||
|
||||
case QMediaPlayer::EndOfMedia:
|
||||
return tr("Ended");
|
||||
|
||||
case QMediaPlayer::InvalidMedia:
|
||||
return tr("Media is invalid");
|
||||
|
||||
default:
|
||||
return tr("Unknown");
|
||||
}
|
||||
}
|
||||
|
||||
void MediaPlayer::setupIcons() {
|
||||
m_iconPlay = qApp->icons()->fromTheme(QSL("media-playback-start"), QSL("player_play"));
|
||||
m_iconPause = qApp->icons()->fromTheme(QSL("media-playback-pause"), QSL("player_pause"));
|
||||
m_iconMute = qApp->icons()->fromTheme(QSL("player-volume-muted"), QSL("audio-volume-muted"));
|
||||
m_iconUnmute = qApp->icons()->fromTheme(QSL("player-volume"), QSL("stock_volume"));
|
||||
|
||||
m_ui.m_btnDownload->setIcon(qApp->icons()->fromTheme(QSL("download"), QSL("browser-download")));
|
||||
m_ui.m_btnStop->setIcon(qApp->icons()->fromTheme(QSL("media-playback-stop"), QSL("player_stop")));
|
||||
}
|
||||
|
||||
void MediaPlayer::createConnections() {
|
||||
connect(m_player, &QMediaPlayer::durationChanged, this, &MediaPlayer::onDurationChanged);
|
||||
connect(m_player, &QMediaPlayer::errorOccurred, this, &MediaPlayer::onErrorOccurred);
|
||||
connect(m_player, &QMediaPlayer::hasAudioChanged, this, &MediaPlayer::onAudioAvailable);
|
||||
connect(m_player, &QMediaPlayer::hasVideoChanged, this, &MediaPlayer::onVideoAvailable);
|
||||
connect(m_player, &QMediaPlayer::mediaStatusChanged, this, &MediaPlayer::onMediaStatusChanged);
|
||||
connect(m_player, &QMediaPlayer::playbackStateChanged, this, &MediaPlayer::onPlaybackStateChanged);
|
||||
connect(m_player, &QMediaPlayer::positionChanged, this, &MediaPlayer::onPositionChanged);
|
||||
connect(m_player, &QMediaPlayer::seekableChanged, this, &MediaPlayer::onSeekableChanged);
|
||||
|
||||
connect(m_ui.m_btnPlayPause, &PlainToolButton::clicked, this, &MediaPlayer::playPause);
|
||||
connect(m_ui.m_btnStop, &PlainToolButton::clicked, this, &MediaPlayer::stop);
|
||||
connect(m_ui.m_btnDownload, &PlainToolButton::clicked, this, &MediaPlayer::download);
|
||||
connect(m_ui.m_btnVolume, &PlainToolButton::clicked, this, &MediaPlayer::muteUnmute);
|
||||
connect(m_ui.m_slidVolume, &QSlider::valueChanged, this, &MediaPlayer::setVolume);
|
||||
connect(m_ui.m_slidProgress, &QSlider::valueChanged, this, &MediaPlayer::seek);
|
||||
}
|
72
src/librssguard/gui/reusable/mediaplayer.h
Normal file
72
src/librssguard/gui/reusable/mediaplayer.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
// For license of this file, see <project-root-folder>/LICENSE.md.
|
||||
|
||||
#ifndef MEDIAPLAYER_H
|
||||
#define MEDIAPLAYER_H
|
||||
|
||||
#include "gui/tabcontent.h"
|
||||
|
||||
#include "ui_mediaplayer.h"
|
||||
|
||||
#include <QMediaPlayer>
|
||||
|
||||
class QAudioOutput;
|
||||
|
||||
class MediaPlayer : public TabContent {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MediaPlayer(QWidget* parent = nullptr);
|
||||
virtual ~MediaPlayer();
|
||||
|
||||
virtual WebBrowser* webBrowser() const;
|
||||
|
||||
public slots:
|
||||
void playUrl(const QString& url);
|
||||
|
||||
private slots:
|
||||
void playPause();
|
||||
void stop();
|
||||
void download();
|
||||
void muteUnmute();
|
||||
|
||||
// NOTE: Volume is from 0 to 100.
|
||||
void setVolume(int volume);
|
||||
|
||||
// NOTE: Media is seekable in miliseconds, but that is too muc
|
||||
// for "int" data type, therefore we seek by second.
|
||||
void seek(int position);
|
||||
|
||||
void onDurationChanged(qint64 duration);
|
||||
void onErrorOccurred(QMediaPlayer::Error error, const QString& error_string);
|
||||
void onAudioAvailable(bool available);
|
||||
void onVideoAvailable(bool available);
|
||||
void onMediaStatusChanged(QMediaPlayer::MediaStatus status);
|
||||
void onPlaybackStateChanged(QMediaPlayer::PlaybackState state);
|
||||
void onPositionChanged(qint64 position);
|
||||
void onSeekableChanged(bool seekable);
|
||||
|
||||
signals:
|
||||
void urlDownloadRequested(const QUrl& url);
|
||||
|
||||
private:
|
||||
QString mediaStatusToString(QMediaPlayer::MediaStatus status) const;
|
||||
|
||||
void setupIcons();
|
||||
void createConnections();
|
||||
|
||||
private:
|
||||
Ui::MediaPlayer m_ui;
|
||||
|
||||
#if QT_VERSION_MAJOR == 6
|
||||
QAudioOutput* m_audio;
|
||||
#endif
|
||||
|
||||
QMediaPlayer* m_player;
|
||||
QIcon m_iconPlay;
|
||||
QIcon m_iconPause;
|
||||
QIcon m_iconMute;
|
||||
QIcon m_iconUnmute;
|
||||
bool m_muted;
|
||||
};
|
||||
|
||||
#endif // MEDIAPLAYER_H
|
95
src/librssguard/gui/reusable/mediaplayer.ui
Normal file
95
src/librssguard/gui/reusable/mediaplayer.ui
Normal file
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MediaPlayer</class>
|
||||
<widget class="QWidget" name="MediaPlayer">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>588</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QVideoWidget" name="m_video" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="m_lblStatus"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="PlainToolButton" name="m_btnPlayPause"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="PlainToolButton" name="m_btnStop"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="m_slidProgress">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="m_lblTime"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="PlainToolButton" name="m_btnVolume"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="m_slidVolume">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>50</number>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="tickInterval">
|
||||
<number>5</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="PlainToolButton" name="m_btnDownload"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QVideoWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>qvideowidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>PlainToolButton</class>
|
||||
<extends>QToolButton</extends>
|
||||
<header>plaintoolbutton.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -22,11 +22,11 @@ void PlainToolButton::paintEvent(QPaintEvent* e) {
|
|||
|
||||
if (isEnabled()) {
|
||||
if (underMouse() || isChecked()) {
|
||||
p.setOpacity(0.7);
|
||||
p.setOpacity(0.8);
|
||||
}
|
||||
}
|
||||
else {
|
||||
p.setOpacity(0.3);
|
||||
p.setOpacity(0.2);
|
||||
}
|
||||
|
||||
icon().paint(&p, rect);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "gui/feedsview.h"
|
||||
#include "gui/messagepreviewer.h"
|
||||
#include "gui/messagesview.h"
|
||||
#include "gui/reusable/mediaplayer.h"
|
||||
#include "gui/reusable/plaintoolbutton.h"
|
||||
#include "gui/tabbar.h"
|
||||
#include "gui/webbrowser.h"
|
||||
|
@ -86,14 +87,13 @@ void TabWidget::checkTabBarVisibility() {
|
|||
|
||||
if (should_be_visible) {
|
||||
setCornerWidget(m_btnMainMenu, Qt::Corner::TopLeftCorner);
|
||||
m_btnMainMenu->setVisible(true);
|
||||
}
|
||||
else {
|
||||
setCornerWidget(nullptr, Qt::Corner::TopLeftCorner);
|
||||
setCornerWidget(nullptr, Qt::Corner::TopRightCorner);
|
||||
m_btnMainMenu->setVisible(false);
|
||||
}
|
||||
|
||||
m_btnMainMenu->setVisible(should_be_visible);
|
||||
tabBar()->setVisible(should_be_visible);
|
||||
}
|
||||
|
||||
|
@ -224,6 +224,26 @@ int TabWidget::addEmptyBrowser() {
|
|||
return addBrowser(false, true);
|
||||
}
|
||||
|
||||
int TabWidget::addMediaPlayer(const QString& url, bool make_active) {
|
||||
auto* player = new MediaPlayer(this);
|
||||
|
||||
int index = addTab(player,
|
||||
qApp->icons()->fromTheme(QSL("player_play"), QSL("media-playback-start")),
|
||||
tr("Media player"),
|
||||
TabBar::TabType::Closable);
|
||||
|
||||
if (make_active) {
|
||||
setCurrentIndex(index);
|
||||
player->setFocus(Qt::FocusReason::OtherFocusReason);
|
||||
}
|
||||
|
||||
QTimer::singleShot(500, player, [player, url]() {
|
||||
player->playUrl(url);
|
||||
});
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
int TabWidget::addLinkedBrowser(const QUrl& initial_url) {
|
||||
return addBrowser(false, false, initial_url);
|
||||
}
|
||||
|
|
|
@ -78,6 +78,8 @@ class TabWidget : public QTabWidget {
|
|||
// Adds new WebBrowser tab to global TabWidget.
|
||||
int addEmptyBrowser();
|
||||
|
||||
int addMediaPlayer(const QString& url, bool make_active);
|
||||
|
||||
// Adds new WebBrowser with link. This is used when user
|
||||
// selects to "Open link in new tab.".
|
||||
int addLinkedBrowser(const QUrl& initial_url = QUrl());
|
||||
|
|
|
@ -100,6 +100,10 @@ void WebEngineViewer::contextMenuEvent(QContextMenuEvent* event) {
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
menu->addAction(qApp->icons()->fromTheme(QSL("document-open")), tr("Open link as audio/video"), [link_url]() {
|
||||
qApp->mainForm()->tabWidget()->addMediaPlayer(link_url, true);
|
||||
});
|
||||
}
|
||||
|
||||
if (menu_data.mediaUrl().isValid() || menu_data.linkUrl().isValid()) {
|
||||
|
|
|
@ -141,8 +141,10 @@ FormDiscoverFeeds::~FormDiscoverFeeds() {
|
|||
m_discoveredModel->setRootItem(nullptr);
|
||||
}
|
||||
|
||||
QList<StandardFeed*> FormDiscoverFeeds::discoverFeedsWithParser(const FeedParser* parser, const QString& url) {
|
||||
auto feeds = parser->discoverFeeds(m_serviceRoot, url);
|
||||
QList<StandardFeed*> FormDiscoverFeeds::discoverFeedsWithParser(const FeedParser* parser,
|
||||
const QString& url,
|
||||
bool greedy) {
|
||||
auto feeds = parser->discoverFeeds(m_serviceRoot, url, greedy);
|
||||
QPixmap icon;
|
||||
int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
||||
|
||||
|
@ -158,15 +160,10 @@ QList<StandardFeed*> FormDiscoverFeeds::discoverFeedsWithParser(const FeedParser
|
|||
|
||||
void FormDiscoverFeeds::discoverFeeds() {
|
||||
QString url = m_ui.m_txtUrl->lineEdit()->text();
|
||||
bool sitemap_discover = m_ui.m_cbDiscoverSitemaps->isChecked();
|
||||
bool greedy_discover = m_ui.m_cbDiscoverRecursive->isChecked();
|
||||
|
||||
std::function<QList<StandardFeed*>(const FeedParser*)> func = [=](const FeedParser* parser) -> QList<StandardFeed*> {
|
||||
if (!sitemap_discover && dynamic_cast<const SitemapParser*>(parser) != nullptr) {
|
||||
return {};
|
||||
}
|
||||
else {
|
||||
return discoverFeedsWithParser(parser, url);
|
||||
}
|
||||
return discoverFeedsWithParser(parser, url, greedy_discover);
|
||||
};
|
||||
|
||||
std::function<QList<StandardFeed*>(QList<StandardFeed*>&, const QList<StandardFeed*>&)> reducer =
|
||||
|
|
|
@ -57,7 +57,7 @@ class FormDiscoverFeeds : public QDialog {
|
|||
StandardFeed* selectedFeed() const;
|
||||
RootItem* targetParent() const;
|
||||
|
||||
QList<StandardFeed*> discoverFeedsWithParser(const FeedParser* parser, const QString& url);
|
||||
QList<StandardFeed*> discoverFeedsWithParser(const FeedParser* parser, const QString& url, bool greedy);
|
||||
|
||||
void userWantsAdvanced();
|
||||
void loadDiscoveredFeeds(const QList<StandardFeed*>& feeds);
|
||||
|
|
|
@ -46,9 +46,9 @@
|
|||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QCheckBox" name="m_cbDiscoverSitemaps">
|
||||
<widget class="QCheckBox" name="m_cbDiscoverRecursive">
|
||||
<property name="text">
|
||||
<string>Discover Sitemaps too (can take some time for bigger websites)</string>
|
||||
<string>Recursive discovery (can take some time for bigger websites)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -25,7 +25,9 @@ AtomParser::AtomParser(const QString& data) : FeedParser(data) {
|
|||
|
||||
AtomParser::~AtomParser() {}
|
||||
|
||||
QList<StandardFeed*> AtomParser::discoverFeeds(ServiceRoot* root, const QUrl& url) const {
|
||||
QList<StandardFeed*> AtomParser::discoverFeeds(ServiceRoot* root, const QUrl& url, bool greedy) const {
|
||||
Q_UNUSED(greedy)
|
||||
|
||||
QString my_url = url.toString();
|
||||
QList<StandardFeed*> feeds;
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ class AtomParser : public FeedParser {
|
|||
explicit AtomParser(const QString& data);
|
||||
virtual ~AtomParser();
|
||||
|
||||
virtual QList<StandardFeed*> discoverFeeds(ServiceRoot* root, const QUrl& url) const;
|
||||
virtual QList<StandardFeed*> discoverFeeds(ServiceRoot* root, const QUrl& url, bool greedy) const;
|
||||
|
||||
virtual QPair<StandardFeed*, QList<IconLocation>> guessFeed(const QByteArray& content,
|
||||
const QString& content_type) const;
|
||||
|
|
|
@ -41,7 +41,11 @@ FeedParser::FeedParser(QString data, bool is_xml)
|
|||
|
||||
FeedParser::~FeedParser() {}
|
||||
|
||||
QList<StandardFeed*> FeedParser::discoverFeeds(ServiceRoot* root, const QUrl& url) const {
|
||||
QList<StandardFeed*> FeedParser::discoverFeeds(ServiceRoot* root, const QUrl& url, bool greedy) const {
|
||||
Q_UNUSED(root)
|
||||
Q_UNUSED(url)
|
||||
Q_UNUSED(greedy)
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ class FeedParser {
|
|||
virtual ~FeedParser();
|
||||
|
||||
// Returns list of absolute URLs of discovered feeds from provided base URL.
|
||||
virtual QList<StandardFeed*> discoverFeeds(ServiceRoot* root, const QUrl& url) const;
|
||||
virtual QList<StandardFeed*> discoverFeeds(ServiceRoot* root, const QUrl& url, bool greedy) const;
|
||||
|
||||
// Guesses feed.
|
||||
virtual QPair<StandardFeed*, QList<IconLocation>> guessFeed(const QByteArray& content,
|
||||
|
|
|
@ -19,7 +19,9 @@ JsonParser::JsonParser(const QString& data) : FeedParser(data, false) {}
|
|||
|
||||
JsonParser::~JsonParser() {}
|
||||
|
||||
QList<StandardFeed*> JsonParser::discoverFeeds(ServiceRoot* root, const QUrl& url) const {
|
||||
QList<StandardFeed*> JsonParser::discoverFeeds(ServiceRoot* root, const QUrl& url, bool greedy) const {
|
||||
Q_UNUSED(greedy)
|
||||
|
||||
QString my_url = url.toString();
|
||||
QList<StandardFeed*> feeds;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ class JsonParser : public FeedParser {
|
|||
explicit JsonParser(const QString& data);
|
||||
virtual ~JsonParser();
|
||||
|
||||
virtual QList<StandardFeed*> discoverFeeds(ServiceRoot* root, const QUrl& url) const;
|
||||
virtual QList<StandardFeed*> discoverFeeds(ServiceRoot* root, const QUrl& url, bool greedy) const;
|
||||
|
||||
virtual QPair<StandardFeed*, QList<IconLocation>> guessFeed(const QByteArray& content,
|
||||
const QString& content_type) const;
|
||||
|
|
|
@ -18,7 +18,9 @@ RdfParser::RdfParser(const QString& data)
|
|||
|
||||
RdfParser::~RdfParser() {}
|
||||
|
||||
QList<StandardFeed*> RdfParser::discoverFeeds(ServiceRoot* root, const QUrl& url) const {
|
||||
QList<StandardFeed*> RdfParser::discoverFeeds(ServiceRoot* root, const QUrl& url, bool greedy) const {
|
||||
Q_UNUSED(greedy)
|
||||
|
||||
QString my_url = url.toString();
|
||||
QList<StandardFeed*> feeds;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class RdfParser : public FeedParser {
|
|||
explicit RdfParser(const QString& data);
|
||||
virtual ~RdfParser();
|
||||
|
||||
virtual QList<StandardFeed*> discoverFeeds(ServiceRoot* root, const QUrl& url) const;
|
||||
virtual QList<StandardFeed*> discoverFeeds(ServiceRoot* root, const QUrl& url, bool greedy) const;
|
||||
|
||||
virtual QPair<StandardFeed*, QList<IconLocation>> guessFeed(const QByteArray& content,
|
||||
const QString& content_type) const;
|
||||
|
|
|
@ -18,7 +18,9 @@ RssParser::RssParser(const QString& data) : FeedParser(data) {}
|
|||
|
||||
RssParser::~RssParser() {}
|
||||
|
||||
QList<StandardFeed*> RssParser::discoverFeeds(ServiceRoot* root, const QUrl& url) const {
|
||||
QList<StandardFeed*> RssParser::discoverFeeds(ServiceRoot* root, const QUrl& url, bool greedy) const {
|
||||
Q_UNUSED(greedy)
|
||||
|
||||
QString my_url = url.toString();
|
||||
QList<StandardFeed*> feeds;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class RssParser : public FeedParser {
|
|||
explicit RssParser(const QString& data);
|
||||
virtual ~RssParser();
|
||||
|
||||
virtual QList<StandardFeed*> discoverFeeds(ServiceRoot* root, const QUrl& url) const;
|
||||
virtual QList<StandardFeed*> discoverFeeds(ServiceRoot* root, const QUrl& url, bool greedy) const;
|
||||
|
||||
virtual QPair<StandardFeed*, QList<IconLocation>> guessFeed(const QByteArray& content,
|
||||
const QString& content_type) const;
|
||||
|
|
|
@ -21,20 +21,24 @@ SitemapParser::SitemapParser(const QString& data) : FeedParser(data) {}
|
|||
|
||||
SitemapParser::~SitemapParser() {}
|
||||
|
||||
QList<StandardFeed*> SitemapParser::discoverFeeds(ServiceRoot* root, const QUrl& url) const {
|
||||
QList<StandardFeed*> SitemapParser::discoverFeeds(ServiceRoot* root, const QUrl& url, bool greedy) const {
|
||||
QHash<QString, StandardFeed*> feeds;
|
||||
QStringList to_process_sitemaps;
|
||||
int sitemap_index_limit = 2;
|
||||
int timeout = qApp->settings()->value(GROUP(Feeds), SETTING(Feeds::UpdateTimeout)).toInt();
|
||||
|
||||
// 1. Process "URL/robots.txt" file.
|
||||
// 2. Process "URLHOST/robots.txt" file.
|
||||
// 3. Direct URL test. If sitemap index, process its children.
|
||||
// 1. Direct URL test. If sitemap index, process its children. If found, stop if non-recursive
|
||||
// discovery is chosen.
|
||||
// 2. Process "URL/robots.txt" file.
|
||||
// 3. Process "URLHOST/robots.txt" file.
|
||||
// 4. Test "URL/sitemap.xml" endpoint.
|
||||
// 5. Test "URL/sitemap.xml.gz" endpoint.
|
||||
|
||||
// 1.
|
||||
to_process_sitemaps.append(url.toString());
|
||||
|
||||
// 2.
|
||||
// 3.
|
||||
QStringList to_process_robots = {
|
||||
url.toString(QUrl::UrlFormattingOption::StripTrailingSlash).replace(QRegularExpression(QSL("\\/$")), QString()) +
|
||||
QSL("/robots.txt"),
|
||||
|
@ -70,9 +74,6 @@ QList<StandardFeed*> SitemapParser::discoverFeeds(ServiceRoot* root, const QUrl&
|
|||
}
|
||||
}
|
||||
|
||||
// 3.
|
||||
to_process_sitemaps.append(url.toString());
|
||||
|
||||
// 4.
|
||||
to_process_sitemaps.append(url.toString(QUrl::UrlFormattingOption::StripTrailingSlash)
|
||||
.replace(QRegularExpression(QSL("\\/$")), QString()) +
|
||||
|
@ -107,13 +108,16 @@ QList<StandardFeed*> SitemapParser::discoverFeeds(ServiceRoot* root, const QUrl&
|
|||
|
||||
if (res.m_networkError == QNetworkReply::NetworkError::NoError) {
|
||||
try {
|
||||
// 1.
|
||||
auto guessed_feed = guessFeed(data, res.m_contentType);
|
||||
|
||||
guessed_feed.first->setSource(my_url);
|
||||
guessed_feed.first->setTitle(my_url);
|
||||
|
||||
feeds.insert(my_url, guessed_feed.first);
|
||||
|
||||
if (!greedy) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const FeedRecognizedButFailedException& ex) {
|
||||
// This is index.
|
||||
|
|
|
@ -12,7 +12,7 @@ class SitemapParser : public FeedParser {
|
|||
explicit SitemapParser(const QString& data);
|
||||
virtual ~SitemapParser();
|
||||
|
||||
virtual QList<StandardFeed*> discoverFeeds(ServiceRoot* root, const QUrl& url) const;
|
||||
virtual QList<StandardFeed*> discoverFeeds(ServiceRoot* root, const QUrl& url, bool greedy) const;
|
||||
|
||||
virtual QPair<StandardFeed*, QList<IconLocation>> guessFeed(const QByteArray& content,
|
||||
const QString& content_type) const;
|
||||
|
|
|
@ -49,7 +49,7 @@ FeedsImportExportModel::~FeedsImportExportModel() {
|
|||
if (m_watcherLookup.isRunning()) {
|
||||
m_watcherLookup.cancel();
|
||||
m_watcherLookup.waitForFinished();
|
||||
qApp->processEvents();
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
|
||||
if (sourceModel() != nullptr && sourceModel()->rootItem() != nullptr && m_mode == Mode::Import) {
|
||||
|
@ -433,7 +433,7 @@ void FeedsImportExportModel::importAsOPML20(const QByteArray& data,
|
|||
|
||||
if (!fetch_metadata_online) {
|
||||
m_watcherLookup.waitForFinished();
|
||||
qApp->processEvents();
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -502,7 +502,7 @@ void FeedsImportExportModel::importAsTxtURLPerLine(const QByteArray& data,
|
|||
|
||||
if (!fetch_metadata_online) {
|
||||
m_watcherLookup.waitForFinished();
|
||||
qApp->processEvents();
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue