1 /* This file is part of Clementine.
2    Copyright 2012, David Sansome <me@davidsansome.com>
3    Copyright 2014, John Maguire <john.maguire@gmail.com>
4    Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
5 
6    Clementine is free software: you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation, either version 3 of the License, or
9    (at your option) any later version.
10 
11    Clementine is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with Clementine.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #ifndef INTERNET_PODCASTS_PODCASTURLLOADER_H_
21 #define INTERNET_PODCASTS_PODCASTURLLOADER_H_
22 
23 #include <QObject>
24 #include <QRegExp>
25 
26 #include "opmlcontainer.h"
27 #include "podcast.h"
28 
29 class PodcastParser;
30 
31 class QNetworkAccessManager;
32 class QNetworkReply;
33 
34 class PodcastUrlLoaderReply : public QObject {
35   Q_OBJECT
36 
37  public:
38   PodcastUrlLoaderReply(const QUrl& url, QObject* parent);
39 
40   enum ResultType { Type_Podcast, Type_Opml };
41 
url()42   const QUrl& url() const { return url_; }
is_finished()43   bool is_finished() const { return finished_; }
is_success()44   bool is_success() const { return error_text_.isEmpty(); }
error_text()45   const QString& error_text() const { return error_text_; }
46 
result_type()47   ResultType result_type() const { return result_type_; }
podcast_results()48   const PodcastList& podcast_results() const { return podcast_results_; }
opml_results()49   const OpmlContainer& opml_results() const { return opml_results_; }
50 
51   void SetFinished(const QString& error_text);
52   void SetFinished(const PodcastList& results);
53   void SetFinished(const OpmlContainer& results);
54 
55  signals:
56   void Finished(bool success);
57 
58  private:
59   QUrl url_;
60   bool finished_;
61   QString error_text_;
62 
63   ResultType result_type_;
64   PodcastList podcast_results_;
65   OpmlContainer opml_results_;
66 };
67 
68 class PodcastUrlLoader : public QObject {
69   Q_OBJECT
70 
71  public:
72   explicit PodcastUrlLoader(QObject* parent = nullptr);
73   ~PodcastUrlLoader();
74 
75   static const int kMaxRedirects;
76 
77   PodcastUrlLoaderReply* Load(const QString& url_text);
78   PodcastUrlLoaderReply* Load(const QUrl& url);
79 
80   // Both the FixPodcastUrl functions replace common podcatcher URL schemes
81   // like itpc:// or zune:// with their http:// equivalents.  The QString
82   // overload also cleans up user-entered text a bit - stripping whitespace and
83   // applying shortcuts like sc:tag.
84   static QUrl FixPodcastUrl(const QString& url_text);
85   static QUrl FixPodcastUrl(const QUrl& url);
86 
87  private:
88   struct RequestState {
89     int redirects_remaining_;
90     PodcastUrlLoaderReply* reply_;
91   };
92 
93   typedef QPair<QString, QString> QuickPrefix;
94   typedef QList<QuickPrefix> QuickPrefixList;
95 
96  private slots:
97   void RequestFinished(RequestState* state, QNetworkReply* reply);
98 
99  private:
100   void SendErrorAndDelete(const QString& error_text, RequestState* state);
101   void NextRequest(const QUrl& url, RequestState* state);
102 
103  private:
104   QNetworkAccessManager* network_;
105   PodcastParser* parser_;
106 
107   QRegExp html_link_re_;
108   QRegExp whitespace_re_;
109   QRegExp html_link_rel_re_;
110   QRegExp html_link_type_re_;
111   QRegExp html_link_href_re_;
112 };
113 
114 #endif  // INTERNET_PODCASTS_PODCASTURLLOADER_H_
115