1 /*
2  * Strawberry Music Player
3  * This file was part of Clementine.
4  * Copyright 2010, David Sansome <me@davidsansome.com>
5  * Copyright 2018-2021, Jonas Kvinge <jonas@jkvinge.net>
6  *
7  * Strawberry 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  * Strawberry 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 Strawberry.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #ifndef ALBUMCOVERFETCHER_H
23 #define ALBUMCOVERFETCHER_H
24 
25 #include "config.h"
26 
27 #include <QtGlobal>
28 #include <QObject>
29 #include <QMetaType>
30 #include <QSet>
31 #include <QList>
32 #include <QHash>
33 #include <QQueue>
34 #include <QByteArray>
35 #include <QString>
36 #include <QUrl>
37 #include <QImage>
38 
39 #include "coversearchstatistics.h"
40 #include "albumcoverimageresult.h"
41 
42 class QTimer;
43 class NetworkAccessManager;
44 class CoverProviders;
45 class AlbumCoverFetcherSearch;
46 
47 // This class represents a single search-for-cover request. It identifies and describes the request.
48 struct CoverSearchRequest {
DialogResultDialogResult49   explicit CoverSearchRequest() : id(-1), search(false), batch(false) {}
50 
51   // An unique (for one AlbumCoverFetcher) request identifier
52   quint64 id;
53 
54   // A search query
55   QString artist;
56   QString album;
57   QString title;
58 
59   // Is this only a search request or should we also fetch the first cover that's found?
60   bool search;
IsSizeForcedDialogResult61 
62   // Is the request part of a batch (fetching all missing covers)
63   bool batch;
64 };
RequiresCoverProcessingDialogResult65 
66 // This structure represents a single result of some album's cover search request.
67 struct CoverProviderSearchResult {
68   explicit CoverProviderSearchResult() : score_provider(0.0), score_match(0.0), score_quality(0.0), number(0) {}
69 
70   // Used for grouping in the user interface.
71   QString provider;
72 
73   // Artist and album returned by the provider
74   QString artist;
75   QString album;
76 
77   // An URL of a cover image
78   QUrl image_url;
79 
80   // Image size
81   QSize image_size;
82 
83   // Score for this provider
84   float score_provider;
85 
86   // Score for match
87   float score_match;
88 
89   // Score for image quality
90   float score_quality;
91 
92   // The result number
93   int number;
94 
95   // Total score for this result
96   float score() const { return score_provider + score_match + score_quality; }
97 
98 };
99 Q_DECLARE_METATYPE(CoverProviderSearchResult)
100 
101 // This is a complete result of a single search request (a list of results, each describing one image, actually).
102 typedef QList<CoverProviderSearchResult> CoverProviderSearchResults;
103 Q_DECLARE_METATYPE(QList<CoverProviderSearchResult>)
104 
105 // This class searches for album covers for a given query or artist/album and returns URLs. It's NOT thread-safe.
106 class AlbumCoverFetcher : public QObject {
107   Q_OBJECT
108 
109  public:
110   explicit AlbumCoverFetcher(CoverProviders *cover_providers, QObject *parent = nullptr, NetworkAccessManager *network = nullptr);
111   ~AlbumCoverFetcher() override;
112 
113   static const int kMaxConcurrentRequests;
114 
115   quint64 SearchForCovers(const QString &artist, const QString &album, const QString &title = QString());
116   quint64 FetchAlbumCover(const QString &artist, const QString &album, const QString &title, const bool batch);
117 
118   void Clear();
119 
120  signals:
121   void AlbumCoverFetched(quint64 request_id, AlbumCoverImageResult result, CoverSearchStatistics statistics);
122   void SearchFinished(quint64 request_id, CoverProviderSearchResults results, CoverSearchStatistics statistics);
123 
124  private slots:
125   void SingleSearchFinished(const quint64, const CoverProviderSearchResults &results);
126   void SingleCoverFetched(const quint64, const AlbumCoverImageResult &result);
127   void StartRequests();
128 
129  private:
130   void AddRequest(const CoverSearchRequest &req);
131 
132   CoverProviders *cover_providers_;
133   NetworkAccessManager *network_;
134   quint64 next_id_;
135 
136   QQueue<CoverSearchRequest> queued_requests_;
137   QHash<quint64, AlbumCoverFetcherSearch*> active_requests_;
138 
139   QTimer *request_starter_;
140 
141 };
142 
143 #endif  // ALBUMCOVERFETCHER_H
144