Rewrite album cover loader
This commit is contained in:
@@ -48,7 +48,7 @@
|
||||
#include "scopedtransaction.h"
|
||||
|
||||
const char *Database::kDatabaseFilename = "strawberry.db";
|
||||
const int Database::kSchemaVersion = 16;
|
||||
const int Database::kSchemaVersion = 17;
|
||||
const int Database::kMinSupportedSchemaVersion = 10;
|
||||
const char *Database::kMagicAllSongsTables = "%allsongstables";
|
||||
|
||||
|
||||
@@ -1177,6 +1177,7 @@ void MainWindow::ReloadAllSettings() {
|
||||
collection_view_->ReloadSettings();
|
||||
ui_->playlist->view()->ReloadSettings();
|
||||
app_->playlist_manager()->playlist_container()->ReloadSettings();
|
||||
app_->current_albumcover_loader()->ReloadSettingsAsync();
|
||||
album_cover_choice_controller_->ReloadSettings();
|
||||
context_view_->ReloadSettings();
|
||||
file_view_->ReloadSettings();
|
||||
@@ -1381,14 +1382,14 @@ void MainWindow::SongChanged(const Song &song) {
|
||||
SendNowPlaying();
|
||||
|
||||
const bool enable_change_art = song.is_collection_song() && !song.effective_albumartist().isEmpty() && !song.album().isEmpty();
|
||||
album_cover_choice_controller_->show_cover_action()->setEnabled(song.has_valid_art() && !song.has_manually_unset_cover());
|
||||
album_cover_choice_controller_->cover_to_file_action()->setEnabled(song.has_valid_art() && !song.has_manually_unset_cover());
|
||||
album_cover_choice_controller_->show_cover_action()->setEnabled(song.has_valid_art() && !song.art_unset());
|
||||
album_cover_choice_controller_->cover_to_file_action()->setEnabled(song.has_valid_art() && !song.art_unset());
|
||||
album_cover_choice_controller_->cover_from_file_action()->setEnabled(enable_change_art);
|
||||
album_cover_choice_controller_->cover_from_url_action()->setEnabled(enable_change_art);
|
||||
album_cover_choice_controller_->search_for_cover_action()->setEnabled(app_->cover_providers()->HasAnyProviders() && enable_change_art);
|
||||
album_cover_choice_controller_->unset_cover_action()->setEnabled(enable_change_art && !song.has_manually_unset_cover());
|
||||
album_cover_choice_controller_->unset_cover_action()->setEnabled(enable_change_art && !song.art_unset());
|
||||
album_cover_choice_controller_->clear_cover_action()->setEnabled(enable_change_art && !song.art_manual().isEmpty());
|
||||
album_cover_choice_controller_->delete_cover_action()->setEnabled(enable_change_art && song.has_valid_art() && !song.has_manually_unset_cover());
|
||||
album_cover_choice_controller_->delete_cover_action()->setEnabled(enable_change_art && (song.art_embedded() || !song.art_automatic().isEmpty() || !song.art_manual().isEmpty()));
|
||||
|
||||
}
|
||||
|
||||
@@ -3072,14 +3073,14 @@ void MainWindow::AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult
|
||||
emit AlbumCoverReady(song, result.album_cover.image);
|
||||
|
||||
const bool enable_change_art = song.is_collection_song() && !song.effective_albumartist().isEmpty() && !song.album().isEmpty();
|
||||
album_cover_choice_controller_->show_cover_action()->setEnabled(result.success && result.type != AlbumCoverLoaderResult::Type::ManuallyUnset);
|
||||
album_cover_choice_controller_->cover_to_file_action()->setEnabled(result.success && result.type != AlbumCoverLoaderResult::Type::ManuallyUnset);
|
||||
album_cover_choice_controller_->show_cover_action()->setEnabled(result.success && result.type != AlbumCoverLoaderResult::Type::Unset);
|
||||
album_cover_choice_controller_->cover_to_file_action()->setEnabled(result.success && result.type != AlbumCoverLoaderResult::Type::Unset);
|
||||
album_cover_choice_controller_->cover_from_file_action()->setEnabled(enable_change_art);
|
||||
album_cover_choice_controller_->cover_from_url_action()->setEnabled(enable_change_art);
|
||||
album_cover_choice_controller_->search_for_cover_action()->setEnabled(app_->cover_providers()->HasAnyProviders() && enable_change_art);
|
||||
album_cover_choice_controller_->unset_cover_action()->setEnabled(enable_change_art && !song.has_manually_unset_cover());
|
||||
album_cover_choice_controller_->unset_cover_action()->setEnabled(enable_change_art && !song.art_unset());
|
||||
album_cover_choice_controller_->clear_cover_action()->setEnabled(enable_change_art && !song.art_manual().isEmpty());
|
||||
album_cover_choice_controller_->delete_cover_action()->setEnabled(enable_change_art && result.success && result.type != AlbumCoverLoaderResult::Type::ManuallyUnset);
|
||||
album_cover_choice_controller_->delete_cover_action()->setEnabled(enable_change_art && result.success && result.type != AlbumCoverLoaderResult::Type::Unset);
|
||||
|
||||
GetCoverAutomatically();
|
||||
|
||||
@@ -3089,7 +3090,8 @@ void MainWindow::GetCoverAutomatically() {
|
||||
|
||||
// Search for cover automatically?
|
||||
const bool search = album_cover_choice_controller_->search_cover_auto_action()->isChecked() &&
|
||||
!song_.has_manually_unset_cover() &&
|
||||
!song_.art_unset() &&
|
||||
!song_.art_embedded() &&
|
||||
!song_.art_automatic_is_valid() &&
|
||||
!song_.art_manual_is_valid() &&
|
||||
!song_.effective_albumartist().isEmpty() &&
|
||||
|
||||
@@ -401,14 +401,16 @@ void Mpris2::AlbumCoverLoaded(const Song &song, const AlbumCoverLoaderResult &re
|
||||
else if (result.temp_cover_url.isValid() && result.temp_cover_url.isLocalFile()) {
|
||||
cover_url = result.temp_cover_url;
|
||||
}
|
||||
else if (song.art_manual().isValid() && song.art_manual().isLocalFile() && song.art_manual().path() != Song::kManuallyUnsetCover && song.art_manual().path() != Song::kEmbeddedCover) {
|
||||
else if (song.art_manual().isValid() && song.art_manual().isLocalFile()) {
|
||||
cover_url = song.art_manual();
|
||||
}
|
||||
else if (song.art_automatic().isValid() && song.art_automatic().isLocalFile() && song.art_automatic().path() != Song::kManuallyUnsetCover && song.art_automatic().path() != Song::kEmbeddedCover) {
|
||||
else if (song.art_automatic().isValid() && song.art_automatic().isLocalFile()) {
|
||||
cover_url = song.art_automatic();
|
||||
}
|
||||
|
||||
if (cover_url.isValid()) AddMetadata("mpris:artUrl", cover_url.toString(), &last_metadata_);
|
||||
if (cover_url.isValid()) {
|
||||
AddMetadata("mpris:artUrl", cover_url.toString(), &last_metadata_);
|
||||
}
|
||||
|
||||
AddMetadata("year", song.year(), &last_metadata_);
|
||||
AddMetadata("bitrate", song.bitrate(), &last_metadata_);
|
||||
|
||||
1052
src/core/song.cpp
1052
src/core/song.cpp
File diff suppressed because it is too large
Load Diff
270
src/core/song.h
270
src/core/song.h
@@ -2,7 +2,7 @@
|
||||
* Strawberry Music Player
|
||||
* This file was part of Clementine.
|
||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
* Copyright 2018-2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||
* Copyright 2018-2023, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -109,10 +109,6 @@ class Song {
|
||||
Stream = 91
|
||||
};
|
||||
|
||||
Song(const Source source = Source::Unknown);
|
||||
Song(const Song &other);
|
||||
~Song();
|
||||
|
||||
static const QStringList kColumns;
|
||||
static const QString kColumnSpec;
|
||||
static const QString kBindSpec;
|
||||
@@ -123,9 +119,6 @@ class Song {
|
||||
static const QString kFtsBindSpec;
|
||||
static const QString kFtsUpdateSpec;
|
||||
|
||||
static const QString kManuallyUnsetCover;
|
||||
static const QString kEmbeddedCover;
|
||||
|
||||
static const QRegularExpression kAlbumRemoveDisc;
|
||||
static const QRegularExpression kAlbumRemoveMisc;
|
||||
static const QRegularExpression kTitleRemoveMisc;
|
||||
@@ -134,77 +127,22 @@ class Song {
|
||||
|
||||
static const QStringList kAcceptedExtensions;
|
||||
|
||||
static QString JoinSpec(const QString &table);
|
||||
Song(const Source source = Source::Unknown);
|
||||
Song(const Song &other);
|
||||
~Song();
|
||||
|
||||
static Source SourceFromURL(const QUrl &url);
|
||||
static QString TextForSource(const Source source);
|
||||
static QString DescriptionForSource(const Source source);
|
||||
static Source SourceFromText(const QString &source);
|
||||
static QIcon IconForSource(const Source source);
|
||||
static QString TextForFiletype(const FileType filetype);
|
||||
static QString ExtensionForFiletype(const FileType filetype);
|
||||
static QIcon IconForFiletype(const FileType filetype);
|
||||
|
||||
QString TextForSource() const { return TextForSource(source()); }
|
||||
QString DescriptionForSource() const { return DescriptionForSource(source()); }
|
||||
QIcon IconForSource() const { return IconForSource(source()); }
|
||||
QString TextForFiletype() const { return TextForFiletype(filetype()); }
|
||||
QIcon IconForFiletype() const { return IconForFiletype(filetype()); }
|
||||
|
||||
bool IsFileLossless() const;
|
||||
static FileType FiletypeByMimetype(const QString &mimetype);
|
||||
static FileType FiletypeByDescription(const QString &text);
|
||||
static FileType FiletypeByExtension(const QString &ext);
|
||||
static QString ImageCacheDir(const Source source);
|
||||
|
||||
// Sort songs alphabetically using their pretty title
|
||||
static int CompareSongsName(const Song &song1, const Song &song2);
|
||||
static void SortSongsListAlphabetically(QList<Song> *songs);
|
||||
|
||||
// Constructors
|
||||
void Init(const QString &title, const QString &artist, const QString &album, const qint64 length_nanosec);
|
||||
void Init(const QString &title, const QString &artist, const QString &album, const qint64 beginning, const qint64 end);
|
||||
void InitFromProtobuf(const spb::tagreader::SongMetadata &pb);
|
||||
void InitFromQuery(const SqlRow &query, const bool reliable_metadata);
|
||||
void InitFromFilePartial(const QString &filename, const QFileInfo &fileinfo);
|
||||
void InitArtManual();
|
||||
void InitArtAutomatic();
|
||||
|
||||
bool MergeFromEngineMetadata(const EngineMetadata &engine_metadata);
|
||||
|
||||
#ifdef HAVE_LIBGPOD
|
||||
void InitFromItdb(_Itdb_Track *track, const QString &prefix);
|
||||
void ToItdb(_Itdb_Track *track) const;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBMTP
|
||||
void InitFromMTP(const LIBMTP_track_struct *track, const QString &host);
|
||||
void ToMTP(LIBMTP_track_struct *track) const;
|
||||
#endif
|
||||
|
||||
// Copies important statistics from the other song to this one, overwriting any data that already exists.
|
||||
// Useful when you want updated tags from disk but you want to keep user stats.
|
||||
void MergeUserSetData(const Song &other, const bool merge_playcount, const bool merge_rating);
|
||||
|
||||
// Save
|
||||
void BindToQuery(SqlQuery *query) const;
|
||||
void BindToFtsQuery(SqlQuery *query) const;
|
||||
void ToXesam(QVariantMap *map) const;
|
||||
void ToProtobuf(spb::tagreader::SongMetadata *pb) const;
|
||||
bool operator==(const Song &other) const;
|
||||
bool operator!=(const Song &other) const;
|
||||
Song &operator=(const Song &other);
|
||||
|
||||
// Simple accessors
|
||||
bool is_valid() const;
|
||||
bool is_unavailable() const;
|
||||
int id() const;
|
||||
bool is_valid() const;
|
||||
|
||||
const QString &title() const;
|
||||
const QString &title_sortable() const;
|
||||
const QString &album() const;
|
||||
const QString &album_sortable() const;
|
||||
const QString &artist() const;
|
||||
const QString &artist_sortable() const;
|
||||
const QString &albumartist() const;
|
||||
const QString &albumartist_sortable() const;
|
||||
int track() const;
|
||||
int disc() const;
|
||||
int year() const;
|
||||
@@ -237,6 +175,7 @@ class Song {
|
||||
qint64 filesize() const;
|
||||
qint64 mtime() const;
|
||||
qint64 ctime() const;
|
||||
bool unavailable() const;
|
||||
|
||||
QString fingerprint() const;
|
||||
|
||||
@@ -246,14 +185,15 @@ class Song {
|
||||
qint64 lastseen() const;
|
||||
|
||||
bool compilation_detected() const;
|
||||
bool compilation_off() const;
|
||||
bool compilation_on() const;
|
||||
bool compilation_off() const;
|
||||
|
||||
bool art_embedded() const;
|
||||
const QUrl &art_automatic() const;
|
||||
const QUrl &art_manual() const;
|
||||
bool art_unset() const;
|
||||
|
||||
const QString &cue_path() const;
|
||||
bool has_cue() const;
|
||||
|
||||
float rating() const;
|
||||
|
||||
@@ -271,74 +211,16 @@ class Song {
|
||||
const QString &musicbrainz_release_group_id() const;
|
||||
const QString &musicbrainz_work_id() const;
|
||||
|
||||
const QString &effective_album() const;
|
||||
int effective_originalyear() const;
|
||||
const QString &effective_albumartist() const;
|
||||
const QString &effective_albumartist_sortable() const;
|
||||
|
||||
bool is_collection_song() const;
|
||||
bool is_stream() const;
|
||||
bool is_radio() const;
|
||||
bool is_cdda() const;
|
||||
bool is_metadata_good() const;
|
||||
bool art_automatic_is_valid() const;
|
||||
bool art_manual_is_valid() const;
|
||||
bool has_valid_art() const;
|
||||
bool is_compilation() const;
|
||||
bool stream_url_can_expire() const;
|
||||
bool is_module_music() const;
|
||||
|
||||
// Playlist views are special because you don't want to fill in album artists automatically for compilations, but you do for normal albums:
|
||||
const QString &playlist_albumartist() const;
|
||||
const QString &playlist_albumartist_sortable() const;
|
||||
|
||||
// Returns true if this Song had it's cover manually unset by user.
|
||||
bool has_manually_unset_cover() const;
|
||||
// This method represents an explicit request to unset this song's cover.
|
||||
void set_manually_unset_cover();
|
||||
|
||||
// Returns true if this song (it's media file) has an embedded cover.
|
||||
bool has_embedded_cover() const;
|
||||
// Sets a flag saying that this song (it's media file) has an embedded cover.
|
||||
void set_embedded_cover();
|
||||
|
||||
void clear_art_automatic();
|
||||
void clear_art_manual();
|
||||
|
||||
static bool save_embedded_cover_supported(const FileType filetype);
|
||||
bool save_embedded_cover_supported() const { return url().isLocalFile() && save_embedded_cover_supported(filetype()) && !has_cue(); };
|
||||
|
||||
bool additional_tags_supported() const;
|
||||
bool albumartist_supported() const;
|
||||
bool composer_supported() const;
|
||||
bool performer_supported() const;
|
||||
bool grouping_supported() const;
|
||||
bool genre_supported() const;
|
||||
bool compilation_supported() const;
|
||||
bool rating_supported() const;
|
||||
bool comment_supported() const;
|
||||
bool lyrics_supported() const;
|
||||
|
||||
const QUrl &stream_url() const;
|
||||
const QUrl &effective_stream_url() const;
|
||||
bool init_from_file() const;
|
||||
|
||||
// Pretty accessors
|
||||
QString PrettyTitle() const;
|
||||
QString PrettyTitleWithArtist() const;
|
||||
QString PrettyLength() const;
|
||||
QString PrettyYear() const;
|
||||
QString PrettyOriginalYear() const;
|
||||
const QString &title_sortable() const;
|
||||
const QString &album_sortable() const;
|
||||
const QString &artist_sortable() const;
|
||||
const QString &albumartist_sortable() const;
|
||||
|
||||
QString TitleWithCompilationArtist() const;
|
||||
|
||||
QString SampleRateBitDepthToText() const;
|
||||
|
||||
QString PrettyRating() const;
|
||||
const QUrl &stream_url() const;
|
||||
|
||||
// Setters
|
||||
bool IsEditable() const;
|
||||
|
||||
void set_id(const int id);
|
||||
void set_valid(const bool v);
|
||||
|
||||
@@ -391,8 +273,10 @@ class Song {
|
||||
void set_compilation_on(const bool v);
|
||||
void set_compilation_off(const bool v);
|
||||
|
||||
void set_art_embedded(const bool v);
|
||||
void set_art_automatic(const QUrl &v);
|
||||
void set_art_manual(const QUrl &v);
|
||||
void set_art_unset(const bool v);
|
||||
|
||||
void set_cue_path(const QString &v);
|
||||
|
||||
@@ -414,6 +298,61 @@ class Song {
|
||||
|
||||
void set_stream_url(const QUrl &v);
|
||||
|
||||
const QUrl &effective_stream_url() const;
|
||||
const QString &effective_albumartist() const;
|
||||
const QString &effective_albumartist_sortable() const;
|
||||
const QString &effective_album() const;
|
||||
int effective_originalyear() const;
|
||||
const QString &playlist_albumartist() const;
|
||||
const QString &playlist_albumartist_sortable() const;
|
||||
|
||||
bool is_metadata_good() const;
|
||||
bool is_collection_song() const;
|
||||
bool is_stream() const;
|
||||
bool is_radio() const;
|
||||
bool is_cdda() const;
|
||||
bool is_compilation() const;
|
||||
bool stream_url_can_expire() const;
|
||||
bool is_module_music() const;
|
||||
bool has_cue() const;
|
||||
|
||||
bool art_automatic_is_valid() const;
|
||||
bool art_manual_is_valid() const;
|
||||
bool has_valid_art() const;
|
||||
void clear_art_automatic();
|
||||
void clear_art_manual();
|
||||
|
||||
bool additional_tags_supported() const;
|
||||
bool albumartist_supported() const;
|
||||
bool composer_supported() const;
|
||||
bool performer_supported() const;
|
||||
bool grouping_supported() const;
|
||||
bool genre_supported() const;
|
||||
bool compilation_supported() const;
|
||||
bool rating_supported() const;
|
||||
bool comment_supported() const;
|
||||
bool lyrics_supported() const;
|
||||
|
||||
static bool save_embedded_cover_supported(const FileType filetype);
|
||||
bool save_embedded_cover_supported() const { return url().isLocalFile() && save_embedded_cover_supported(filetype()) && !has_cue(); };
|
||||
|
||||
static QString JoinSpec(const QString &table);
|
||||
|
||||
// Pretty accessors
|
||||
QString PrettyTitle() const;
|
||||
QString PrettyTitleWithArtist() const;
|
||||
QString PrettyLength() const;
|
||||
QString PrettyYear() const;
|
||||
QString PrettyOriginalYear() const;
|
||||
|
||||
QString TitleWithCompilationArtist() const;
|
||||
|
||||
QString SampleRateBitDepthToText() const;
|
||||
|
||||
QString PrettyRating() const;
|
||||
|
||||
bool IsEditable() const;
|
||||
|
||||
// Comparison functions
|
||||
bool IsMetadataEqual(const Song &other) const;
|
||||
bool IsPlayStatisticsEqual(const Song &other) const;
|
||||
@@ -427,16 +366,69 @@ class Song {
|
||||
bool IsOnSameAlbum(const Song &other) const;
|
||||
bool IsSimilar(const Song &other) const;
|
||||
|
||||
bool operator==(const Song &other) const;
|
||||
bool operator!=(const Song &other) const;
|
||||
static Source SourceFromURL(const QUrl &url);
|
||||
static QString TextForSource(const Source source);
|
||||
static QString DescriptionForSource(const Source source);
|
||||
static Source SourceFromText(const QString &source);
|
||||
static QIcon IconForSource(const Source source);
|
||||
static QString TextForFiletype(const FileType filetype);
|
||||
static QString ExtensionForFiletype(const FileType filetype);
|
||||
static QIcon IconForFiletype(const FileType filetype);
|
||||
|
||||
QString TextForSource() const { return TextForSource(source()); }
|
||||
QString DescriptionForSource() const { return DescriptionForSource(source()); }
|
||||
QIcon IconForSource() const { return IconForSource(source()); }
|
||||
QString TextForFiletype() const { return TextForFiletype(filetype()); }
|
||||
QIcon IconForFiletype() const { return IconForFiletype(filetype()); }
|
||||
|
||||
bool IsFileLossless() const;
|
||||
static FileType FiletypeByMimetype(const QString &mimetype);
|
||||
static FileType FiletypeByDescription(const QString &text);
|
||||
static FileType FiletypeByExtension(const QString &ext);
|
||||
static QString ImageCacheDir(const Source source);
|
||||
|
||||
// Sort songs alphabetically using their pretty title
|
||||
static int CompareSongsName(const Song &song1, const Song &song2);
|
||||
static void SortSongsListAlphabetically(QList<Song> *songs);
|
||||
|
||||
// Constructors
|
||||
void Init(const QString &title, const QString &artist, const QString &album, const qint64 length_nanosec);
|
||||
void Init(const QString &title, const QString &artist, const QString &album, const qint64 beginning, const qint64 end);
|
||||
void InitFromProtobuf(const spb::tagreader::SongMetadata &pb);
|
||||
void InitFromQuery(const SqlRow &query, const bool reliable_metadata);
|
||||
void InitFromFilePartial(const QString &filename, const QFileInfo &fileinfo);
|
||||
void InitArtManual();
|
||||
void InitArtAutomatic();
|
||||
|
||||
#ifdef HAVE_LIBGPOD
|
||||
void InitFromItdb(_Itdb_Track *track, const QString &prefix);
|
||||
void ToItdb(_Itdb_Track *track) const;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBMTP
|
||||
void InitFromMTP(const LIBMTP_track_struct *track, const QString &host);
|
||||
void ToMTP(LIBMTP_track_struct *track) const;
|
||||
#endif
|
||||
|
||||
// Save
|
||||
void BindToQuery(SqlQuery *query) const;
|
||||
void BindToFtsQuery(SqlQuery *query) const;
|
||||
void ToXesam(QVariantMap *map) const;
|
||||
void ToProtobuf(spb::tagreader::SongMetadata *pb) const;
|
||||
|
||||
bool MergeFromEngineMetadata(const EngineMetadata &engine_metadata);
|
||||
|
||||
// Copies important statistics from the other song to this one, overwriting any data that already exists.
|
||||
// Useful when you want updated tags from disk but you want to keep user stats.
|
||||
void MergeUserSetData(const Song &other, const bool merge_playcount, const bool merge_rating);
|
||||
|
||||
// Two songs that are on the same album will have the same AlbumKey.
|
||||
// It is more efficient to use IsOnSameAlbum, but this function can be used when you need to hash the key to do fast lookups.
|
||||
QString AlbumKey() const;
|
||||
|
||||
Song &operator=(const Song &other);
|
||||
|
||||
private:
|
||||
static const QString kManuallyUnsetCover;
|
||||
static const QString kEmbeddedCover;
|
||||
struct Private;
|
||||
|
||||
static QString sortable(const QString &v);
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <QIcon>
|
||||
|
||||
#include "covermanager/albumcoverloader.h"
|
||||
#include "covermanager/albumcoverloaderoptions.h"
|
||||
#include "standarditemiconloader.h"
|
||||
|
||||
StandardItemIconLoader::StandardItemIconLoader(AlbumCoverLoader *cover_loader, QObject *parent)
|
||||
@@ -37,8 +38,6 @@ StandardItemIconLoader::StandardItemIconLoader(AlbumCoverLoader *cover_loader, Q
|
||||
cover_loader_(cover_loader),
|
||||
model_(nullptr) {
|
||||
|
||||
cover_options_.desired_height_ = 16;
|
||||
|
||||
QObject::connect(cover_loader_, &AlbumCoverLoader::AlbumCoverLoaded, this, &StandardItemIconLoader::AlbumCoverLoaded);
|
||||
|
||||
}
|
||||
@@ -58,14 +57,20 @@ void StandardItemIconLoader::SetModel(QAbstractItemModel *model) {
|
||||
|
||||
void StandardItemIconLoader::LoadIcon(const QUrl &art_automatic, const QUrl &art_manual, QStandardItem *for_item) {
|
||||
|
||||
const quint64 id = cover_loader_->LoadImageAsync(cover_options_, art_automatic, art_manual);
|
||||
pending_covers_[id] = for_item;
|
||||
AlbumCoverLoaderOptions cover_options(AlbumCoverLoaderOptions::Option::ScaledImage);
|
||||
cover_options.desired_scaled_size = QSize(16, 16);
|
||||
const quint64 id = cover_loader_->LoadImageAsync(cover_options, false, art_automatic, art_manual, false);
|
||||
pending_covers_.insert(id, for_item);
|
||||
|
||||
}
|
||||
|
||||
void StandardItemIconLoader::LoadIcon(const Song &song, QStandardItem *for_item) {
|
||||
const quint64 id = cover_loader_->LoadImageAsync(cover_options_, song);
|
||||
pending_covers_[id] = for_item;
|
||||
|
||||
AlbumCoverLoaderOptions cover_options(AlbumCoverLoaderOptions::Option::ScaledImage);
|
||||
cover_options.desired_scaled_size = QSize(16, 16);
|
||||
const quint64 id = cover_loader_->LoadImageAsync(cover_options, song);
|
||||
pending_covers_.insert(id, for_item);
|
||||
|
||||
}
|
||||
|
||||
void StandardItemIconLoader::RowsAboutToBeRemoved(const QModelIndex &parent, int begin, int end) {
|
||||
@@ -76,7 +81,7 @@ void StandardItemIconLoader::RowsAboutToBeRemoved(const QModelIndex &parent, int
|
||||
|
||||
if (item_parent && item_parent->index() == parent && item->index().row() >= begin && item->index().row() <= end) {
|
||||
cover_loader_->CancelTask(it.key());
|
||||
it = pending_covers_.erase(it); // clazy:exclude=strict-iterators
|
||||
it = pending_covers_.erase(it);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
@@ -103,7 +108,7 @@ void StandardItemIconLoader::AlbumCoverLoaded(const quint64 id, const AlbumCover
|
||||
QStandardItem *item = pending_covers_.take(id);
|
||||
if (!item) return;
|
||||
|
||||
if (result.success && !result.image_scaled.isNull() && result.type != AlbumCoverLoaderResult::Type::ManuallyUnset) {
|
||||
if (result.success && !result.image_scaled.isNull() && result.type != AlbumCoverLoaderResult::Type::Unset) {
|
||||
item->setIcon(QIcon(QPixmap::fromImage(result.image_scaled)));
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include <QUrl>
|
||||
#include <QImage>
|
||||
|
||||
#include "covermanager/albumcoverloaderoptions.h"
|
||||
#include "covermanager/albumcoverloaderresult.h"
|
||||
|
||||
class QAbstractItemModel;
|
||||
@@ -38,8 +37,6 @@ class QStandardItem;
|
||||
class Song;
|
||||
class AlbumCoverLoader;
|
||||
|
||||
class QModelIndex;
|
||||
|
||||
// Uses an AlbumCoverLoader to asynchronously load and set an icon on a QStandardItem.
|
||||
class StandardItemIconLoader : public QObject {
|
||||
Q_OBJECT
|
||||
@@ -47,8 +44,6 @@ class StandardItemIconLoader : public QObject {
|
||||
public:
|
||||
explicit StandardItemIconLoader(AlbumCoverLoader *cover_loader, QObject *parent = nullptr);
|
||||
|
||||
AlbumCoverLoaderOptions *options() { return &cover_options_; }
|
||||
|
||||
void SetModel(QAbstractItemModel *model);
|
||||
|
||||
void LoadIcon(const QUrl &art_automatic, const QUrl &art_manual, QStandardItem *for_item);
|
||||
@@ -61,10 +56,7 @@ class StandardItemIconLoader : public QObject {
|
||||
|
||||
private:
|
||||
AlbumCoverLoader *cover_loader_;
|
||||
AlbumCoverLoaderOptions cover_options_;
|
||||
|
||||
QAbstractItemModel *model_;
|
||||
|
||||
QMap<quint64, QStandardItem*> pending_covers_;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Strawberry Music Player
|
||||
* This file was part of Clementine.
|
||||
* Copyright 2010, David Sansome <me@davidsansome.com>
|
||||
* Copyright 2019-2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||
* Copyright 2019-2023, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -93,25 +93,30 @@ TagReaderReply *TagReaderClient::ReadFile(const QString &filename) {
|
||||
|
||||
}
|
||||
|
||||
TagReaderReply *TagReaderClient::SaveFile(const QString &filename, const Song &metadata, const SaveTags save_tags, const SavePlaycount save_playcount, const SaveRating save_rating, const SaveCoverOptions &save_cover_options) {
|
||||
TagReaderReply *TagReaderClient::SaveFile(const QString &filename, const Song &metadata, const SaveTypes save_types, const SaveCoverOptions &save_cover_options) {
|
||||
|
||||
spb::tagreader::Message message;
|
||||
spb::tagreader::SaveFileRequest *request = message.mutable_save_file_request();
|
||||
|
||||
const QByteArray filename_data = filename.toUtf8();
|
||||
request->set_filename(filename_data.constData(), filename_data.length());
|
||||
request->set_save_tags(save_tags == SaveTags::On);
|
||||
request->set_save_playcount(save_playcount == SavePlaycount::On);
|
||||
request->set_save_rating(save_rating == SaveRating::On);
|
||||
request->set_save_cover(save_cover_options.enabled);
|
||||
request->set_cover_is_jpeg(save_cover_options.is_jpeg);
|
||||
|
||||
request->set_save_tags(save_types.testFlag(SaveType::Tags));
|
||||
request->set_save_playcount(save_types.testFlag(SaveType::PlayCount));
|
||||
request->set_save_rating(save_types.testFlag(SaveType::Rating));
|
||||
request->set_save_cover(save_types.testFlag(SaveType::Cover));
|
||||
|
||||
if (save_cover_options.cover_filename.length() > 0) {
|
||||
const QByteArray cover_filename = filename.toUtf8();
|
||||
const QByteArray cover_filename = save_cover_options.cover_filename.toUtf8();
|
||||
request->set_cover_filename(cover_filename.constData(), cover_filename.length());
|
||||
}
|
||||
if (save_cover_options.cover_data.length() > 0) {
|
||||
request->set_cover_data(save_cover_options.cover_data.constData(), save_cover_options.cover_data.length());
|
||||
}
|
||||
if (save_cover_options.mime_type.length() > 0) {
|
||||
const QByteArray cover_mime_type = save_cover_options.mime_type.toUtf8();
|
||||
request->set_cover_mime_type(cover_mime_type.constData(), cover_mime_type.length());
|
||||
}
|
||||
metadata.ToProtobuf(request->mutable_metadata());
|
||||
|
||||
ReplyType *reply = worker_pool_->SendMessageWithReply(&message);
|
||||
@@ -139,15 +144,17 @@ TagReaderReply *TagReaderClient::SaveEmbeddedArt(const QString &filename, const
|
||||
|
||||
const QByteArray filename_data = filename.toUtf8();
|
||||
request->set_filename(filename_data.constData(), filename_data.length());
|
||||
request->set_cover_is_jpeg(save_cover_options.is_jpeg);
|
||||
if (save_cover_options.cover_filename.length() > 0) {
|
||||
const QByteArray cover_filename = filename.toUtf8();
|
||||
const QByteArray cover_filename = save_cover_options.cover_filename.toUtf8();
|
||||
request->set_cover_filename(cover_filename.constData(), cover_filename.length());
|
||||
}
|
||||
if (save_cover_options.cover_data.length() > 0) {
|
||||
request->set_cover_data(save_cover_options.cover_data.constData(), save_cover_options.cover_data.length());
|
||||
}
|
||||
|
||||
if (save_cover_options.mime_type.length() > 0) {
|
||||
const QByteArray cover_mime_type = save_cover_options.mime_type.toUtf8();
|
||||
request->set_cover_mime_type(cover_mime_type.constData(), cover_mime_type.length());
|
||||
}
|
||||
|
||||
return worker_pool_->SendMessageWithReply(&message);
|
||||
|
||||
@@ -225,13 +232,13 @@ void TagReaderClient::ReadFileBlocking(const QString &filename, Song *song) {
|
||||
|
||||
}
|
||||
|
||||
bool TagReaderClient::SaveFileBlocking(const QString &filename, const Song &metadata, const SaveTags save_tags, const SavePlaycount save_playcount, const SaveRating save_rating, const SaveCoverOptions &save_cover_options) {
|
||||
bool TagReaderClient::SaveFileBlocking(const QString &filename, const Song &metadata, const SaveTypes save_types, const SaveCoverOptions &save_cover_options) {
|
||||
|
||||
Q_ASSERT(QThread::currentThread() != thread());
|
||||
|
||||
bool ret = false;
|
||||
|
||||
TagReaderReply *reply = SaveFile(filename, metadata, save_tags, save_playcount, save_rating, save_cover_options);
|
||||
TagReaderReply *reply = SaveFile(filename, metadata, save_types, save_cover_options);
|
||||
if (reply->WaitForFinished()) {
|
||||
ret = reply->message().save_file_response().success();
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Strawberry Music Player
|
||||
* This file was part of Clementine.
|
||||
* Copyright 2011, David Sansome <me@davidsansome.com>
|
||||
* Copyright 2019-2021, Jonas Kvinge <jonas@jkvinge.net>
|
||||
* Copyright 2019-2023, Jonas Kvinge <jonas@jkvinge.net>
|
||||
*
|
||||
* Strawberry is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -53,35 +53,28 @@ class TagReaderClient : public QObject {
|
||||
void Start();
|
||||
void ExitAsync();
|
||||
|
||||
enum class SaveTags {
|
||||
Off,
|
||||
On
|
||||
};
|
||||
|
||||
enum class SavePlaycount {
|
||||
Off,
|
||||
On
|
||||
};
|
||||
|
||||
enum class SaveRating {
|
||||
Off,
|
||||
On
|
||||
enum class SaveType {
|
||||
NoType = 0,
|
||||
Tags = 1,
|
||||
PlayCount = 2,
|
||||
Rating = 4,
|
||||
Cover = 8
|
||||
};
|
||||
Q_DECLARE_FLAGS(SaveTypes, SaveType)
|
||||
|
||||
class SaveCoverOptions {
|
||||
public:
|
||||
explicit SaveCoverOptions(const bool _enabled = false, const bool _is_jpeg = false, const QString &_cover_filename = QString(), const QByteArray &_cover_data = QByteArray()) : enabled(_enabled), is_jpeg(_is_jpeg), cover_filename(_cover_filename), cover_data(_cover_data) {}
|
||||
explicit SaveCoverOptions(const QString &_cover_filename) : enabled(true), is_jpeg(false), cover_filename(_cover_filename) {}
|
||||
explicit SaveCoverOptions(const QByteArray &_cover_data) : enabled(true), is_jpeg(false), cover_data(_cover_data) {}
|
||||
bool enabled;
|
||||
bool is_jpeg;
|
||||
explicit SaveCoverOptions(const QString &_cover_filename = QString(), const QByteArray &_cover_data = QByteArray(), const QString &_mime_type = QString()) : cover_filename(_cover_filename), cover_data(_cover_data), mime_type(_mime_type) {}
|
||||
explicit SaveCoverOptions(const QString &_cover_filename, const QString &_mime_type = QString()) : cover_filename(_cover_filename), mime_type(_mime_type) {}
|
||||
explicit SaveCoverOptions(const QByteArray &_cover_data, const QString &_mime_type = QString()) : cover_data(_cover_data), mime_type(_mime_type) {}
|
||||
QString cover_filename;
|
||||
QByteArray cover_data;
|
||||
QString mime_type;
|
||||
};
|
||||
|
||||
ReplyType *IsMediaFile(const QString &filename);
|
||||
ReplyType *ReadFile(const QString &filename);
|
||||
ReplyType *SaveFile(const QString &filename, const Song &metadata, const SaveTags save_tags = SaveTags::On, const SavePlaycount save_playcount = SavePlaycount::Off, const SaveRating save_rating = SaveRating::Off, const SaveCoverOptions &save_cover_options = SaveCoverOptions());
|
||||
ReplyType *SaveFile(const QString &filename, const Song &metadata, const SaveTypes types = SaveType::Tags, const SaveCoverOptions &save_cover_options = SaveCoverOptions());
|
||||
ReplyType *LoadEmbeddedArt(const QString &filename);
|
||||
ReplyType *SaveEmbeddedArt(const QString &filename, const SaveCoverOptions &save_cover_options);
|
||||
ReplyType *UpdateSongPlaycount(const Song &metadata);
|
||||
@@ -90,7 +83,7 @@ class TagReaderClient : public QObject {
|
||||
// Convenience functions that call the above functions and wait for a response.
|
||||
// These block the calling thread with a semaphore, and must NOT be called from the TagReaderClient's thread.
|
||||
void ReadFileBlocking(const QString &filename, Song *song);
|
||||
bool SaveFileBlocking(const QString &filename, const Song &metadata, const SaveTags save_tags = SaveTags::On, const SavePlaycount save_playcount = SavePlaycount::Off, const SaveRating save_rating = SaveRating::Off, const SaveCoverOptions &save_cover_options = SaveCoverOptions());
|
||||
bool SaveFileBlocking(const QString &filename, const Song &metadata, const SaveTypes types = SaveType::Tags, const SaveCoverOptions &save_cover_options = SaveCoverOptions());
|
||||
bool IsMediaFileBlocking(const QString &filename);
|
||||
QByteArray LoadEmbeddedArtBlocking(const QString &filename);
|
||||
QImage LoadEmbeddedArtAsImageBlocking(const QString &filename);
|
||||
|
||||
Reference in New Issue
Block a user