1 /* 2 * Strawberry Music Player 3 * This file was part of Clementine. 4 * Copyright 2010, David Sansome <me@davidsansome.com> 5 * Copyright 2019-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 ALBUMCOVERLOADER_H 23 #define ALBUMCOVERLOADER_H 24 25 #include "config.h" 26 27 #include <QtGlobal> 28 #include <QObject> 29 #include <QMutex> 30 #include <QPair> 31 #include <QSet> 32 #include <QHash> 33 #include <QMultiMap> 34 #include <QQueue> 35 #include <QByteArray> 36 #include <QString> 37 #include <QImage> 38 #include <QPixmap> 39 40 #include "core/song.h" 41 #include "core/tagreaderclient.h" 42 #include "settings/collectionsettingspage.h" 43 #include "albumcoverloaderoptions.h" 44 #include "albumcoverloaderresult.h" 45 #include "albumcoverimageresult.h" 46 47 class QThread; 48 class QNetworkReply; 49 class NetworkAccessManager; 50 51 class AlbumCoverLoader : public QObject { 52 Q_OBJECT 53 54 public: 55 explicit AlbumCoverLoader(QObject *parent = nullptr); 56 57 enum State { 58 State_None, 59 State_Manual, 60 State_Automatic, 61 }; 62 63 void ReloadSettings(); 64 65 void ExitAsync(); Stop()66 void Stop() { stop_requested_ = true; } 67 68 static QString AlbumCoverFilename(QString artist, QString album, const QString &extension); 69 70 static QString CoverFilenameFromSource(const Song::Source source, const QUrl &cover_url, const QString &artist, const QString &album, const QString &album_id, const QString &extension); 71 QString CoverFilenameFromVariable(const QString &artist, const QString &album, const QString &extension = QString()); 72 QString CoverFilePath(const Song &song, const QString &album_dir, const QUrl &cover_url, const QString &extension = QString()); 73 74 QString CoverFilePath(const Song::Source source, const QString &artist, QString album, const QString &album_id, const QString &album_dir, const QUrl &cover_url, const QString &extension = QString()); 75 76 quint64 LoadImageAsync(const AlbumCoverLoaderOptions &options, const Song &song); 77 quint64 LoadImageAsync(const AlbumCoverLoaderOptions &options, const QUrl &art_automatic, const QUrl &art_manual, const QUrl &song_url = QUrl(), const Song::Source song_source = Song::Source_Unknown); 78 quint64 LoadImageAsync(const AlbumCoverLoaderOptions &options, const AlbumCoverImageResult &album_cover); 79 quint64 LoadImageAsync(const AlbumCoverLoaderOptions &options, const QImage &image); 80 81 void CancelTask(const quint64 id); 82 void CancelTasks(const QSet<quint64> &ids); 83 84 quint64 SaveEmbeddedCoverAsync(const QString &song_filename, const QString &cover_filename); 85 quint64 SaveEmbeddedCoverAsync(const QString &song_filename, const QImage &image); 86 quint64 SaveEmbeddedCoverAsync(const QString &song_filename, const QByteArray &image_data); 87 quint64 SaveEmbeddedCoverAsync(const QList<QUrl> &urls, const QString &cover_filename); 88 quint64 SaveEmbeddedCoverAsync(const QList<QUrl> &urls, const QImage &image); 89 quint64 SaveEmbeddedCoverAsync(const QList<QUrl> &urls, const QByteArray &image_data); 90 91 signals: 92 void ExitFinished(); 93 void AlbumCoverLoaded(quint64 id, AlbumCoverLoaderResult result); 94 void SaveEmbeddedCoverAsyncFinished(quint64 id, bool success, bool cleared); 95 96 protected slots: 97 void Exit(); 98 void ProcessTasks(); 99 void RemoteFetchFinished(QNetworkReply *reply, const QUrl &cover_url); 100 101 void SaveEmbeddedCover(const qint64 id, const QString &song_filename, const QString &cover_filename); 102 void SaveEmbeddedCover(const qint64 id, const QString &song_filename, const QImage &image); 103 void SaveEmbeddedCover(const qint64 id, const QString &song_filename, const QByteArray &image_data); 104 void SaveEmbeddedCover(const qint64 id, const QList<QUrl> &urls, const QImage &image); 105 void SaveEmbeddedCover(const qint64 id, const QList<QUrl> &urls, const QString &cover_filename); 106 void SaveEmbeddedCover(const qint64 id, const QList<QUrl> &urls, const QByteArray &image_data); 107 108 void SaveEmbeddedArtFinished(const qint64 id, TagReaderReply *reply, const bool cleared); 109 110 protected: 111 112 struct Task { TaskTask113 explicit Task() : id(0), state(State_None), type(AlbumCoverLoaderResult::Type_None), art_updated(false), redirects(0) {} 114 115 AlbumCoverLoaderOptions options; 116 117 quint64 id; 118 Song song; 119 AlbumCoverImageResult album_cover; 120 State state; 121 AlbumCoverLoaderResult::Type type; 122 bool art_updated; 123 int redirects; 124 }; 125 126 struct TryLoadResult { 127 explicit TryLoadResult(const bool _started_async = false, 128 const bool _loaded_success = false, 129 const AlbumCoverLoaderResult::Type _type = AlbumCoverLoaderResult::Type_None, 130 const AlbumCoverImageResult &_album_cover = AlbumCoverImageResult()) : started_asyncTryLoadResult131 started_async(_started_async), 132 loaded_success(_loaded_success), 133 type(_type), 134 album_cover(_album_cover) {} 135 136 bool started_async; 137 bool loaded_success; 138 139 AlbumCoverLoaderResult::Type type; 140 AlbumCoverImageResult album_cover; 141 }; 142 143 quint64 EnqueueTask(Task &task); 144 void ProcessTask(Task *task); 145 void NextState(Task *task); 146 TryLoadResult TryLoadImage(Task *task); 147 148 bool stop_requested_; 149 150 QMutex mutex_load_image_async_; 151 QMutex mutex_save_image_async_; 152 QQueue<Task> tasks_; 153 QHash<QNetworkReply*, Task> remote_tasks_; 154 quint64 load_image_async_id_; 155 quint64 save_image_async_id_; 156 157 NetworkAccessManager *network_; 158 159 static const int kMaxRedirects = 3; 160 161 CollectionSettingsPage::SaveCoverType save_cover_type_; 162 CollectionSettingsPage::SaveCoverFilename save_cover_filename_; 163 QString cover_pattern_; 164 bool cover_overwrite_; 165 bool cover_lowercase_; 166 bool cover_replace_spaces_; 167 168 QThread *original_thread_; 169 170 QMultiMap<qint64, TagReaderReply*> tagreader_save_embedded_art_requests_; 171 172 }; 173 174 #endif // ALBUMCOVERLOADER_H 175