1 /* This file is part of Clementine.
2    Copyright 2010-2012, David Sansome <me@davidsansome.com>
3    Copyright 2010-2012, 2014, John Maguire <john.maguire@gmail.com>
4    Copyright 2011, Paweł Bara <keirangtp@gmail.com>
5    Copyright 2014, Krzysztof Sobiecki <sobkas@gmail.com>
6 
7    Clementine is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11 
12    Clementine is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with Clementine.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #ifndef COVERS_ALBUMCOVERLOADER_H_
22 #define COVERS_ALBUMCOVERLOADER_H_
23 
24 #include "albumcoverloaderoptions.h"
25 #include "config.h"
26 #include "core/song.h"
27 
28 #include <QImage>
29 #include <QMutex>
30 #include <QObject>
31 #include <QQueue>
32 #include <QUrl>
33 
34 class NetworkAccessManager;
35 class QNetworkReply;
36 
37 class AlbumCoverLoader : public QObject {
38   Q_OBJECT
39 
40  public:
41   explicit AlbumCoverLoader(QObject* parent = nullptr);
42 
Stop()43   void Stop() { stop_requested_ = true; }
44 
45   static QString ImageCacheDir();
46 
47   quint64 LoadImageAsync(const AlbumCoverLoaderOptions& options,
48                          const Song& song);
49   virtual quint64 LoadImageAsync(const AlbumCoverLoaderOptions& options,
50                                  const QString& art_automatic,
51                                  const QString& art_manual,
52                                  const QString& song_filename = QString(),
53                                  const QImage& embedded_image = QImage());
54 
55   void CancelTask(quint64 id);
56   void CancelTasks(const QSet<quint64>& ids);
57 
58   static QPixmap TryLoadPixmap(const QString& automatic, const QString& manual,
59                                const QString& filename = QString());
60   static QImage ScaleAndPad(const AlbumCoverLoaderOptions& options,
61                             const QImage& image);
62 
63  signals:
64   void ImageLoaded(quint64 id, const QImage& image);
65   void ImageLoaded(quint64 id, const QImage& scaled, const QImage& original);
66 
67  protected slots:
68   void ProcessTasks();
69   void RemoteFetchFinished(QNetworkReply* reply);
70 #ifdef HAVE_SPOTIFY
71   void SpotifyImageLoaded(const QString& url, const QImage& image);
72 #endif
73 
74  protected:
75   enum State { State_TryingManual, State_TryingAuto, };
76 
77   struct Task {
TaskTask78     Task() : redirects(0) {}
79 
80     AlbumCoverLoaderOptions options;
81 
82     quint64 id;
83     QString art_automatic;
84     QString art_manual;
85     QString song_filename;
86     QImage embedded_image;
87     State state;
88     int redirects;
89   };
90 
91   struct TryLoadResult {
TryLoadResultTryLoadResult92     TryLoadResult(bool async, bool success, const QImage& i)
93         : started_async(async), loaded_success(success), image(i) {}
94 
95     bool started_async;
96     bool loaded_success;
97     QImage image;
98   };
99 
100   void ProcessTask(Task* task);
101   void NextState(Task* task);
102   TryLoadResult TryLoadImage(const Task& task);
103 
104   bool stop_requested_;
105 
106   QMutex mutex_;
107   QQueue<Task> tasks_;
108   QMap<QNetworkReply*, Task> remote_tasks_;
109   QMap<QString, Task> remote_spotify_tasks_;
110   quint64 next_id_;
111 
112   NetworkAccessManager* network_;
113 
114   bool connected_spotify_;
115 
116   static const int kMaxRedirects = 3;
117 };
118 
119 #endif  // COVERS_ALBUMCOVERLOADER_H_
120