- Add the ability to parse the RSS feeds from reddit groups (in particular the image feed groups like EarthPorn) and display them
This commit is contained in:
@@ -180,6 +180,10 @@ QVector<PathEntry> parsePathEntry(QJsonObject &jsonMainDoc, bool baseRecursive,
|
|||||||
if(!imageListString.empty()) {
|
if(!imageListString.empty()) {
|
||||||
entry.imageList = imageListString;
|
entry.imageList = imageListString;
|
||||||
}
|
}
|
||||||
|
std::string rssFeedURLString = ParseJSONString(schedulerJson, "redditrss");
|
||||||
|
if(!rssFeedURLString.empty()) {
|
||||||
|
entry.rssFeedURL = rssFeedURLString;
|
||||||
|
}
|
||||||
|
|
||||||
SetJSONBool(entry.exclusive, schedulerJson, "exclusive");
|
SetJSONBool(entry.exclusive, schedulerJson, "exclusive");
|
||||||
|
|
||||||
@@ -229,7 +233,7 @@ AppConfig loadAppConfiguration(const AppConfig &commandLineConfig) {
|
|||||||
QJsonDocument d = QJsonDocument::fromJson(val.toUtf8());
|
QJsonDocument d = QJsonDocument::fromJson(val.toUtf8());
|
||||||
QJsonObject jsonDoc = d.object();
|
QJsonObject jsonDoc = d.object();
|
||||||
|
|
||||||
bool baseRecursive, baseShuffle, baseSorted;
|
bool baseRecursive = false, baseShuffle = false, baseSorted = false;
|
||||||
SetJSONBool(baseRecursive, jsonDoc, "recursive");
|
SetJSONBool(baseRecursive, jsonDoc, "recursive");
|
||||||
SetJSONBool(baseShuffle, jsonDoc, "shuffle");
|
SetJSONBool(baseShuffle, jsonDoc, "shuffle");
|
||||||
SetJSONBool(baseSorted, jsonDoc, "sorted");
|
SetJSONBool(baseSorted, jsonDoc, "sorted");
|
||||||
@@ -258,6 +262,11 @@ AppConfig loadAppConfiguration(const AppConfig &commandLineConfig) {
|
|||||||
{
|
{
|
||||||
entry.imageList = imageListString;
|
entry.imageList = imageListString;
|
||||||
}
|
}
|
||||||
|
std::string rssFeedURLString = ParseJSONString(jsonDoc, "redditrss");
|
||||||
|
if(!rssFeedURLString.empty())
|
||||||
|
{
|
||||||
|
entry.rssFeedURL = rssFeedURLString;
|
||||||
|
}
|
||||||
loadedConfig.paths.append(entry);
|
loadedConfig.paths.append(entry);
|
||||||
}
|
}
|
||||||
loadedConfig.configPath = commandLineConfig.configPath;
|
loadedConfig.configPath = commandLineConfig.configPath;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ struct Config {
|
|||||||
struct PathEntry {
|
struct PathEntry {
|
||||||
std::string path = "";
|
std::string path = "";
|
||||||
std::string imageList = "";
|
std::string imageList = "";
|
||||||
|
std::string rssFeedURL = "";
|
||||||
bool exclusive = false; // only use this entry when it is valid, skip others
|
bool exclusive = false; // only use this entry when it is valid, skip others
|
||||||
|
|
||||||
bool recursive = false;
|
bool recursive = false;
|
||||||
@@ -37,7 +38,7 @@ struct PathEntry {
|
|||||||
return true;
|
return true;
|
||||||
if(b.baseDisplayOptions.fitAspectAxisToWindow != baseDisplayOptions.fitAspectAxisToWindow)
|
if(b.baseDisplayOptions.fitAspectAxisToWindow != baseDisplayOptions.fitAspectAxisToWindow)
|
||||||
return true;
|
return true;
|
||||||
if (b.path != path || b.imageList != imageList)
|
if (b.path != path || b.imageList != imageList || b.rssFeedURL != rssFeedURL)
|
||||||
return true;
|
return true;
|
||||||
if (b.baseDisplayOptions.timeWindows.count() != baseDisplayOptions.timeWindows.count())
|
if (b.baseDisplayOptions.timeWindows.count() != baseDisplayOptions.timeWindows.count())
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -146,6 +146,9 @@ bool ImageSelector::imageInsideTimeWindow(const QVector<DisplayTimeWindow> &time
|
|||||||
|
|
||||||
bool ImageSelector::imageMatchesFilter(const ImageDetails& imageDetails)
|
bool ImageSelector::imageMatchesFilter(const ImageDetails& imageDetails)
|
||||||
{
|
{
|
||||||
|
if(imageDetails.filename.find("https://") != std::string::npos)
|
||||||
|
return imageInsideTimeWindow(imageDetails.options.timeWindows);
|
||||||
|
|
||||||
if(!QFileInfo::exists(QString(imageDetails.filename.c_str())))
|
if(!QFileInfo::exists(QString(imageDetails.filename.c_str())))
|
||||||
{
|
{
|
||||||
if(debugMode)
|
if(debugMode)
|
||||||
@@ -245,9 +248,16 @@ const ImageDetails ShuffleImageSelector::getNextImage(const ImageDisplayOptions
|
|||||||
{
|
{
|
||||||
return imageDetails;
|
return imageDetails;
|
||||||
}
|
}
|
||||||
|
bool bReloadedImages = false;
|
||||||
imageDetails = populateImageDetails(pathTraverser->getImagePath(images.at(current_image_shuffle).toStdString()), baseOptions);
|
imageDetails = populateImageDetails(pathTraverser->getImagePath(images.at(current_image_shuffle).toStdString()), baseOptions);
|
||||||
current_image_shuffle = current_image_shuffle + 1; // ignore and move to next image
|
current_image_shuffle = current_image_shuffle + 1; // ignore and move to next image
|
||||||
while(!imageMatchesFilter(imageDetails)) {
|
while(!imageMatchesFilter(imageDetails)) {
|
||||||
|
if(current_image_shuffle >= images.size()) {
|
||||||
|
// don't keep looping
|
||||||
|
if(bReloadedImages == true)
|
||||||
|
return ImageDetails();
|
||||||
|
bReloadedImages = true;
|
||||||
|
}
|
||||||
reloadImagesIfNoneLeft();
|
reloadImagesIfNoneLeft();
|
||||||
imageDetails = populateImageDetails(pathTraverser->getImagePath(images.at(current_image_shuffle).toStdString()),baseOptions);
|
imageDetails = populateImageDetails(pathTraverser->getImagePath(images.at(current_image_shuffle).toStdString()),baseOptions);
|
||||||
current_image_shuffle = current_image_shuffle + 1; // ignore and move to next image
|
current_image_shuffle = current_image_shuffle + 1; // ignore and move to next image
|
||||||
@@ -300,8 +310,16 @@ const ImageDetails SortedImageSelector::getNextImage(const ImageDisplayOptions &
|
|||||||
{
|
{
|
||||||
return imageDetails;
|
return imageDetails;
|
||||||
}
|
}
|
||||||
|
bool bReloadedImages = false;
|
||||||
imageDetails = populateImageDetails(pathTraverser->getImagePath(images.takeFirst().toStdString()), baseOptions);
|
imageDetails = populateImageDetails(pathTraverser->getImagePath(images.takeFirst().toStdString()), baseOptions);
|
||||||
while(!imageMatchesFilter(imageDetails)) {
|
while(!imageMatchesFilter(imageDetails)) {
|
||||||
|
if (images.size() == 0) {
|
||||||
|
// don't keep looping
|
||||||
|
if(bReloadedImages == true)
|
||||||
|
return ImageDetails();
|
||||||
|
bReloadedImages = true;
|
||||||
|
}
|
||||||
|
|
||||||
reloadImagesIfEmpty();
|
reloadImagesIfEmpty();
|
||||||
imageDetails = populateImageDetails(pathTraverser->getImagePath(images.takeFirst().toStdString()), baseOptions);
|
imageDetails = populateImageDetails(pathTraverser->getImagePath(images.takeFirst().toStdString()), baseOptions);
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/main.cpp
26
src/main.cpp
@@ -6,6 +6,7 @@
|
|||||||
#include "appconfig.h"
|
#include "appconfig.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -128,10 +129,14 @@ void ConfigureWindowFromSettings(MainWindow &w, const AppConfig &appConfig)
|
|||||||
w.setBaseOptions(appConfig.baseDisplayOptions);
|
w.setBaseOptions(appConfig.baseDisplayOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ImageSelector> GetSelectorForConfig(const PathEntry& path, const bool debugMode)
|
std::unique_ptr<ImageSelector> GetSelectorForConfig(const PathEntry& path, QNetworkAccessManager& networkManagerIn, const bool debugMode)
|
||||||
{
|
{
|
||||||
std::unique_ptr<PathTraverser> pathTraverser;
|
std::unique_ptr<PathTraverser> pathTraverser;
|
||||||
if (!path.imageList.empty())
|
if (!path.rssFeedURL.empty())
|
||||||
|
{
|
||||||
|
pathTraverser = std::unique_ptr<PathTraverser>(new RedditRSSFeedPathTraverser(path.rssFeedURL, networkManagerIn, debugMode));
|
||||||
|
}
|
||||||
|
else if (!path.imageList.empty())
|
||||||
{
|
{
|
||||||
pathTraverser = std::unique_ptr<PathTraverser>(new ImageListPathTraverser(path.imageList, debugMode));
|
pathTraverser = std::unique_ptr<PathTraverser>(new ImageListPathTraverser(path.imageList, debugMode));
|
||||||
}
|
}
|
||||||
@@ -161,18 +166,18 @@ std::unique_ptr<ImageSelector> GetSelectorForConfig(const PathEntry& path, const
|
|||||||
return selector;
|
return selector;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<ImageSelector> GetSelectorForApp(const AppConfig& appConfig)
|
std::unique_ptr<ImageSelector> GetSelectorForApp(const AppConfig& appConfig, QNetworkAccessManager& networkManagerIn)
|
||||||
{
|
{
|
||||||
if(appConfig.paths.count()==1)
|
if(appConfig.paths.count()==1)
|
||||||
{
|
{
|
||||||
return GetSelectorForConfig(appConfig.paths[0], appConfig.debugMode);
|
return GetSelectorForConfig(appConfig.paths[0], networkManagerIn, appConfig.debugMode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
std::unique_ptr<ListImageSelector> listSelector(new ListImageSelector());
|
std::unique_ptr<ListImageSelector> listSelector(new ListImageSelector());
|
||||||
for(const auto &path : appConfig.paths)
|
for(const auto &path : appConfig.paths)
|
||||||
{
|
{
|
||||||
auto selector = GetSelectorForConfig(path, appConfig.debugMode);
|
auto selector = GetSelectorForConfig(path, networkManagerIn, appConfig.debugMode);
|
||||||
listSelector->AddImageSelector(selector, path.exclusive, path.baseDisplayOptions);
|
listSelector->AddImageSelector(selector, path.exclusive, path.baseDisplayOptions);
|
||||||
}
|
}
|
||||||
// new things
|
// new things
|
||||||
@@ -181,7 +186,7 @@ std::unique_ptr<ImageSelector> GetSelectorForApp(const AppConfig& appConfig)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ReloadConfigIfNeeded(AppConfig &appConfig, MainWindow &w, ImageSwitcher *switcher, ImageSelector *selector)
|
void ReloadConfigIfNeeded(AppConfig &appConfig, MainWindow &w, ImageSwitcher *switcher, ImageSelector *selector, QNetworkAccessManager& networkManager)
|
||||||
{
|
{
|
||||||
QString jsonFile = getAppConfigFilePath(appConfig.configPath);
|
QString jsonFile = getAppConfigFilePath(appConfig.configPath);
|
||||||
QDir directory;
|
QDir directory;
|
||||||
@@ -198,7 +203,7 @@ void ReloadConfigIfNeeded(AppConfig &appConfig, MainWindow &w, ImageSwitcher *sw
|
|||||||
ConfigureWindowFromSettings(w, appConfig);
|
ConfigureWindowFromSettings(w, appConfig);
|
||||||
if(appConfig.PathOptionsChanged(oldConfig))
|
if(appConfig.PathOptionsChanged(oldConfig))
|
||||||
{
|
{
|
||||||
std::unique_ptr<ImageSelector> selector = GetSelectorForApp(appConfig);
|
std::unique_ptr<ImageSelector> selector = GetSelectorForApp(appConfig, networkManager);
|
||||||
switcher->setImageSelector(selector);
|
switcher->setImageSelector(selector);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,16 +238,19 @@ int main(int argc, char *argv[])
|
|||||||
std::cout << "Overlay input: " << appConfig.overlay << std::endl;
|
std::cout << "Overlay input: " << appConfig.overlay << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QNetworkAccessManager webCtrl;
|
||||||
|
|
||||||
MainWindow w;
|
MainWindow w;
|
||||||
ConfigureWindowFromSettings(w, appConfig);
|
ConfigureWindowFromSettings(w, appConfig);
|
||||||
|
w.setNetworkManager(&webCtrl);
|
||||||
w.show();
|
w.show();
|
||||||
|
|
||||||
std::unique_ptr<ImageSelector> selector = GetSelectorForApp(appConfig);
|
std::unique_ptr<ImageSelector> selector = GetSelectorForApp(appConfig, webCtrl);
|
||||||
selector->setDebugMode(appConfig.debugMode);
|
selector->setDebugMode(appConfig.debugMode);
|
||||||
|
|
||||||
ImageSwitcher switcher(w, appConfig.rotationSeconds * 1000, selector);
|
ImageSwitcher switcher(w, appConfig.rotationSeconds * 1000, selector);
|
||||||
w.setImageSwitcher(&switcher);
|
w.setImageSwitcher(&switcher);
|
||||||
std::function<void(MainWindow &w, ImageSwitcher *switcher, ImageSelector *selector)> reloader = [&appConfig](MainWindow &w, ImageSwitcher *switcher, ImageSelector *selector) { ReloadConfigIfNeeded(appConfig, w, switcher, selector); };
|
std::function<void(MainWindow &w, ImageSwitcher *switcher, ImageSelector *selector)> reloader = [&appConfig, &webCtrl](MainWindow &w, ImageSwitcher *switcher, ImageSelector *selector) { ReloadConfigIfNeeded(appConfig, w, switcher, selector, webCtrl); };
|
||||||
switcher.setConfigFileReloader(reloader);
|
switcher.setConfigFileReloader(reloader);
|
||||||
switcher.start();
|
switcher.start();
|
||||||
return a.exec();
|
return a.exec();
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <QGraphicsPixmapItem>
|
#include <QGraphicsPixmapItem>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
|
#include <QNetworkReply>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent) :
|
MainWindow::MainWindow(QWidget *parent) :
|
||||||
@@ -165,15 +166,46 @@ void MainWindow::checkWindowSize()
|
|||||||
void MainWindow::setImage(const ImageDetails &imageDetails)
|
void MainWindow::setImage(const ImageDetails &imageDetails)
|
||||||
{
|
{
|
||||||
currentImage = imageDetails;
|
currentImage = imageDetails;
|
||||||
|
downloadedData.clear();
|
||||||
|
if (pendingReply)
|
||||||
|
{
|
||||||
|
pendingReply->abort();
|
||||||
|
}
|
||||||
updateImage(false);
|
updateImage(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::fileDownloaded(QNetworkReply* netReply)
|
||||||
|
{
|
||||||
|
if (netReply == pendingReply)
|
||||||
|
{
|
||||||
|
pendingReply = nullptr;
|
||||||
|
QNetworkReply::NetworkError err = netReply->error();
|
||||||
|
if (err == QNetworkReply::NoError)
|
||||||
|
{
|
||||||
|
downloadedData = netReply->readAll();
|
||||||
|
netReply->deleteLater();
|
||||||
|
updateImage(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::updateImage(bool immediately)
|
void MainWindow::updateImage(bool immediately)
|
||||||
{
|
{
|
||||||
checkWindowSize();
|
checkWindowSize();
|
||||||
if (currentImage.filename == "")
|
if (currentImage.filename == "")
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (currentImage.filename.find("https://") != std::string::npos && downloadedData.isNull())
|
||||||
|
{
|
||||||
|
if (pendingReply == nullptr)
|
||||||
|
{
|
||||||
|
QNetworkRequest request(QUrl(currentImage.filename.c_str()));
|
||||||
|
pendingReply = networkManager->get(request);
|
||||||
|
connect( networkManager, SIGNAL (finished(QNetworkReply*)), this, SLOT (fileDownloaded(QNetworkReply*)));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
QLabel *label = this->findChild<QLabel*>("image");
|
QLabel *label = this->findChild<QLabel*>("image");
|
||||||
const QPixmap* oldImage = label->pixmap();
|
const QPixmap* oldImage = label->pixmap();
|
||||||
if (oldImage != NULL && !immediately)
|
if (oldImage != NULL && !immediately)
|
||||||
@@ -183,7 +215,28 @@ void MainWindow::updateImage(bool immediately)
|
|||||||
this->setPalette(palette);
|
this->setPalette(palette);
|
||||||
}
|
}
|
||||||
|
|
||||||
QPixmap p( currentImage.filename.c_str() );
|
QPixmap p;
|
||||||
|
if (!downloadedData.isNull())
|
||||||
|
{
|
||||||
|
p.loadFromData(downloadedData);
|
||||||
|
// BUG BUG have the selector update this?
|
||||||
|
currentImage.width = p.width();
|
||||||
|
currentImage.height = p.height();
|
||||||
|
currentImage.rotation = 0;
|
||||||
|
if (currentImage.width > currentImage.height) {
|
||||||
|
currentImage.aspect = ImageAspect_Landscape;
|
||||||
|
} else if (currentImage.height > currentImage.width) {
|
||||||
|
currentImage.aspect = ImageAspect_Portrait;
|
||||||
|
} else {
|
||||||
|
currentImage.aspect = ImageAspect_Any;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p.load( currentImage.filename.c_str() );
|
||||||
|
}
|
||||||
|
|
||||||
if(debugMode)
|
if(debugMode)
|
||||||
{
|
{
|
||||||
std::cout << "size:" << p.width() << "x" << p.height() << "(window:" << width() << "," << height() << ")" << std::endl;
|
std::cout << "size:" << p.width() << "x" << p.height() << "(window:" << width() << "," << height() << ")" << std::endl;
|
||||||
@@ -382,3 +435,8 @@ const ImageDisplayOptions &MainWindow::getBaseOptions()
|
|||||||
{
|
{
|
||||||
return baseImageOptions;
|
return baseImageOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::setNetworkManager(QNetworkAccessManager *networkManagerIn)
|
||||||
|
{
|
||||||
|
networkManager = networkManagerIn;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
#include "imagestructs.h"
|
#include "imagestructs.h"
|
||||||
#include "imageselector.h"
|
#include "imageselector.h"
|
||||||
|
|
||||||
@@ -33,8 +34,11 @@ public:
|
|||||||
void setBaseOptions(const ImageDisplayOptions &baseOptionsIn);
|
void setBaseOptions(const ImageDisplayOptions &baseOptionsIn);
|
||||||
const ImageDisplayOptions &getBaseOptions();
|
const ImageDisplayOptions &getBaseOptions();
|
||||||
void setImageSwitcher(ImageSwitcher *switcherIn);
|
void setImageSwitcher(ImageSwitcher *switcherIn);
|
||||||
|
void setNetworkManager(QNetworkAccessManager *networkManagerIn);
|
||||||
public slots:
|
public slots:
|
||||||
void checkWindowSize();
|
void checkWindowSize();
|
||||||
|
private slots:
|
||||||
|
void fileDownloaded(QNetworkReply* pReply);
|
||||||
private:
|
private:
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
|
|
||||||
@@ -43,6 +47,9 @@ private:
|
|||||||
ImageDisplayOptions baseImageOptions;
|
ImageDisplayOptions baseImageOptions;
|
||||||
bool imageAspectMatchesMonitor = false;
|
bool imageAspectMatchesMonitor = false;
|
||||||
ImageDetails currentImage;
|
ImageDetails currentImage;
|
||||||
|
QByteArray downloadedData;
|
||||||
|
QNetworkAccessManager *networkManager = nullptr;
|
||||||
|
QNetworkReply *pendingReply = nullptr;
|
||||||
bool debugMode = false;
|
bool debugMode = false;
|
||||||
QSize lastScreenSize = {0,0};
|
QSize lastScreenSize = {0,0};
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QDomDocument>
|
||||||
|
#include <QDomAttr>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdlib.h> /* srand, rand */
|
#include <stdlib.h> /* srand, rand */
|
||||||
|
|
||||||
@@ -108,5 +110,132 @@ ImageDisplayOptions ImageListPathTraverser::UpdateOptionsForImage(const std::str
|
|||||||
// no per file options modification supported
|
// no per file options modification supported
|
||||||
Q_UNUSED(filename);
|
Q_UNUSED(filename);
|
||||||
Q_UNUSED(baseOptions);
|
Q_UNUSED(baseOptions);
|
||||||
return ImageDisplayOptions();
|
return baseOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RedditRSSFeedPathTraverser::RedditRSSFeedPathTraverser(const std::string& rssFeedURLIn, QNetworkAccessManager& networkManager, bool debugModeIn) :
|
||||||
|
PathTraverser("",debugModeIn), rssFeedURL(rssFeedURLIn), webCtrl(networkManager)
|
||||||
|
{
|
||||||
|
connect( &webCtrl, SIGNAL (finished(QNetworkReply*)), this, SLOT (fileDownloaded(QNetworkReply*)));
|
||||||
|
RequestRSSFeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
RedditRSSFeedPathTraverser::~RedditRSSFeedPathTraverser()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void RedditRSSFeedPathTraverser::RequestRSSFeed()
|
||||||
|
{
|
||||||
|
if (pendingReply)
|
||||||
|
{
|
||||||
|
pendingReply->abort();
|
||||||
|
}
|
||||||
|
if (debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "Requesting RSS feed:" << rssFeedURL << std::endl;
|
||||||
|
}
|
||||||
|
rssRequestedTime = QDateTime::currentDateTime();
|
||||||
|
QNetworkRequest request(QUrl(rssFeedURL.c_str()));
|
||||||
|
pendingReply = webCtrl.get(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RedditRSSFeedPathTraverser::fileDownloaded(QNetworkReply* netReply)
|
||||||
|
{
|
||||||
|
if (netReply != pendingReply)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pendingReply = nullptr;
|
||||||
|
|
||||||
|
QNetworkReply::NetworkError err = netReply->error();
|
||||||
|
if (err != QNetworkReply::NoError)
|
||||||
|
{
|
||||||
|
std::cout << "Failed to load Reddit RSS URL: " << err << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString str (netReply->readAll());
|
||||||
|
QVariant vt = netReply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
||||||
|
netReply->deleteLater();
|
||||||
|
if (!vt.isNull())
|
||||||
|
{
|
||||||
|
if (debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "Redirected to:" << vt.toUrl().toString().toStdString() << std::endl;
|
||||||
|
}
|
||||||
|
webCtrl.get(QNetworkRequest(vt.toUrl()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QDomDocument doc;
|
||||||
|
QString error;
|
||||||
|
if (!doc.setContent(str, false, &error))
|
||||||
|
{
|
||||||
|
if (debugMode)
|
||||||
|
{
|
||||||
|
std::cout << "Failed to load page:" << error.toStdString() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QDomElement docElem = doc.documentElement();
|
||||||
|
QDomNodeList nodeList = docElem.elementsByTagName("entry");
|
||||||
|
for (int iEntry = 0; iEntry < nodeList.length(); ++iEntry)
|
||||||
|
{
|
||||||
|
QDomNode node = nodeList.item(iEntry);
|
||||||
|
QDomElement e = node.toElement();
|
||||||
|
QDomNode contentNode = e.elementsByTagName("content").item(0).firstChild();
|
||||||
|
QDomDocument docContent;
|
||||||
|
if (!docContent.setContent(contentNode.nodeValue(), false, &error))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDomNodeList addressEntries = docContent.documentElement().elementsByTagName("a");
|
||||||
|
for (int iAddr = 0; iAddr < addressEntries.length(); ++iAddr)
|
||||||
|
{
|
||||||
|
QDomNode node = addressEntries.item(iAddr);
|
||||||
|
/*QString output;
|
||||||
|
QTextStream stream(&output);
|
||||||
|
node.save(stream, 0);
|
||||||
|
qDebug() << "nodeValue: " << output;*/
|
||||||
|
if (node.toElement().text() == "[link]" && node.hasAttributes() )
|
||||||
|
{
|
||||||
|
QDomAttr a = node.toElement().attributeNode("href");
|
||||||
|
// check if the URL matches one of our supported formats
|
||||||
|
for ( const QString& format : supportedFormats )
|
||||||
|
{
|
||||||
|
if (a.value().endsWith(format))
|
||||||
|
{
|
||||||
|
imageURLS.append(a.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QStringList RedditRSSFeedPathTraverser::getImages() const
|
||||||
|
{
|
||||||
|
// refresh the feed after 5 hours
|
||||||
|
if (rssRequestedTime.secsTo(QDateTime::currentDateTime()) > 60*60*5 )
|
||||||
|
{
|
||||||
|
const_cast<RedditRSSFeedPathTraverser *>(this)->RequestRSSFeed();
|
||||||
|
}
|
||||||
|
return imageURLS;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string RedditRSSFeedPathTraverser::getImagePath(const std::string image) const
|
||||||
|
{
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageDisplayOptions RedditRSSFeedPathTraverser::UpdateOptionsForImage(const std::string& filename, const ImageDisplayOptions& baseOptions) const
|
||||||
|
{
|
||||||
|
// no per file options modification supported
|
||||||
|
Q_UNUSED(filename);
|
||||||
|
return baseOptions;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,9 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QNetworkReply>
|
||||||
#include "imageselector.h"
|
#include "imageselector.h"
|
||||||
|
|
||||||
static const QStringList supportedFormats={"jpg","jpeg","png","tif","tiff"};
|
static const QStringList supportedFormats={"jpg","jpeg","png","tif","tiff"};
|
||||||
@@ -58,4 +61,27 @@ class ImageListPathTraverser : public PathTraverser
|
|||||||
private:
|
private:
|
||||||
QStringList imageList;
|
QStringList imageList;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RedditRSSFeedPathTraverser: public QObject, public PathTraverser
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
RedditRSSFeedPathTraverser(const std::string& rSSFeedURL,QNetworkAccessManager& networkManager, bool debugModeIn);
|
||||||
|
virtual ~RedditRSSFeedPathTraverser();
|
||||||
|
|
||||||
|
virtual QStringList getImages() const;
|
||||||
|
virtual const std::string getImagePath(const std::string image) const;
|
||||||
|
virtual ImageDisplayOptions UpdateOptionsForImage(const std::string& filename, const ImageDisplayOptions& baseOptions) const;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void fileDownloaded(QNetworkReply* pReply);
|
||||||
|
private:
|
||||||
|
void RequestRSSFeed();
|
||||||
|
std::string rssFeedURL;
|
||||||
|
QStringList imageURLS;
|
||||||
|
QNetworkAccessManager& webCtrl;
|
||||||
|
QNetworkReply *pendingReply = nullptr;
|
||||||
|
QDateTime rssRequestedTime;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // PATHTRAVERSER_H
|
#endif // PATHTRAVERSER_H
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
#
|
#
|
||||||
#-------------------------------------------------
|
#-------------------------------------------------
|
||||||
|
|
||||||
QT += core gui
|
QT += core gui network xml
|
||||||
# CONFIG += qt debug
|
CONFIG += qt debug
|
||||||
|
|
||||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user