2018-02-27 18:06:05 +01:00
/*
* Strawberry Music Player
* This file was part of Clementine .
* Copyright 2010 , David Sansome < me @ davidsansome . com >
2021-03-20 21:14:47 +01:00
* Copyright 2018 - 2021 , Jonas Kvinge < jonas @ jkvinge . net >
2018-02-27 18:06:05 +01:00
*
* Strawberry is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* Strawberry is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with Strawberry . If not , see < http : //www.gnu.org/licenses/>.
2018-05-01 00:41:33 +02:00
*
2018-02-27 18:06:05 +01:00
*/
# include "config.h"
2018-05-01 00:41:33 +02:00
# include <memory>
2018-10-19 20:18:46 +02:00
# include <algorithm>
2018-05-01 00:41:33 +02:00
# include <QObject>
# include <QMainWindow>
# include <QWidget>
2021-02-26 21:03:51 +01:00
# include <QtConcurrent>
# include <QFuture>
# include <QFutureWatcher>
2020-04-06 22:30:03 +02:00
# include <QScreen>
# include <QWindow>
2018-05-01 00:41:33 +02:00
# include <QItemSelectionModel>
# include <QListWidgetItem>
# include <QFile>
# include <QSet>
# include <QVariant>
# include <QString>
# include <QStringBuilder>
# include <QStringList>
# include <QUrl>
# include <QImage>
2021-03-07 23:03:02 +01:00
# include <QImageWriter>
2018-05-01 00:41:33 +02:00
# include <QPixmap>
# include <QPainter>
2020-02-08 15:03:11 +01:00
# include <QTimer>
# include <QMenu>
# include <QAction>
# include <QActionGroup>
2018-05-01 00:41:33 +02:00
# include <QShortcut>
# include <QSplitter>
# include <QStatusBar>
2018-02-27 18:06:05 +01:00
# include <QLabel>
# include <QListWidget>
# include <QMessageBox>
# include <QProgressBar>
2018-05-01 00:41:33 +02:00
# include <QPushButton>
# include <QToolButton>
# include <QKeySequence>
2018-02-27 18:06:05 +01:00
# include <QSettings>
2020-02-08 15:03:11 +01:00
# include <QFlags>
# include <QSize>
# include <QtEvents>
2018-02-27 18:06:05 +01:00
2022-12-28 03:12:00 +01:00
# include "utilities/strutils.h"
# include "utilities/fileutils.h"
# include "utilities/imageutils.h"
# include "utilities/mimeutils.h"
2018-02-27 18:06:05 +01:00
# include "core/application.h"
# include "core/iconloader.h"
2021-02-26 21:03:51 +01:00
# include "core/tagreaderclient.h"
2021-04-10 03:20:25 +02:00
# include "core/database.h"
2022-05-13 18:15:04 +02:00
# include "core/sqlrow.h"
2018-05-01 00:41:33 +02:00
# include "widgets/forcescrollperpixel.h"
2019-05-08 23:34:44 +02:00
# include "widgets/qsearchfield.h"
2018-02-27 18:06:05 +01:00
# include "collection/collectionbackend.h"
# include "collection/collectionquery.h"
# include "playlist/songmimedata.h"
2021-02-26 21:03:51 +01:00
# include "settings/collectionsettingspage.h"
2018-05-01 00:41:33 +02:00
# include "coverproviders.h"
# include "albumcovermanager.h"
# include "albumcoversearcher.h"
# include "albumcoverchoicecontroller.h"
# include "albumcoverexport.h"
# include "albumcoverexporter.h"
# include "albumcoverfetcher.h"
# include "albumcoverloader.h"
2020-04-20 18:03:18 +02:00
# include "albumcoverloaderresult.h"
2018-05-01 00:41:33 +02:00
# include "coversearchstatistics.h"
# include "coversearchstatisticsdialog.h"
2021-02-26 21:03:51 +01:00
# include "albumcoverimageresult.h"
2018-05-01 00:41:33 +02:00
# include "ui_albumcovermanager.h"
2018-02-27 18:06:05 +01:00
const char * AlbumCoverManager : : kSettingsGroup = " CoverManager " ;
2020-04-06 22:30:03 +02:00
AlbumCoverManager : : AlbumCoverManager ( Application * app , CollectionBackend * collection_backend , QMainWindow * mainwindow , QWidget * parent )
2018-02-27 18:06:05 +01:00
: QMainWindow ( parent ) ,
ui_ ( new Ui_CoverManager ) ,
2020-04-06 22:30:03 +02:00
mainwindow_ ( mainwindow ) ,
2018-02-27 18:06:05 +01:00
app_ ( app ) ,
2021-02-26 21:03:51 +01:00
collection_backend_ ( collection_backend ) ,
2018-02-27 18:06:05 +01:00
album_cover_choice_controller_ ( new AlbumCoverChoiceController ( this ) ) ,
2021-06-20 23:53:28 +02:00
filter_all_ ( nullptr ) ,
filter_with_covers_ ( nullptr ) ,
filter_without_covers_ ( nullptr ) ,
2020-04-06 22:30:03 +02:00
cover_fetcher_ ( new AlbumCoverFetcher ( app_ - > cover_providers ( ) , this ) ) ,
2018-02-27 18:06:05 +01:00
cover_searcher_ ( nullptr ) ,
cover_export_ ( nullptr ) ,
cover_exporter_ ( new AlbumCoverExporter ( this ) ) ,
2019-10-20 00:17:28 +02:00
artist_icon_ ( IconLoader : : Load ( " folder-sound " ) ) ,
all_artists_icon_ ( IconLoader : : Load ( " library-music " ) ) ,
2021-02-26 21:03:51 +01:00
image_nocover_thumbnail_ ( ImageUtils : : GenerateNoCoverImage ( QSize ( 120 , 120 ) ) ) ,
icon_nocover_item_ ( QPixmap : : fromImage ( image_nocover_thumbnail_ ) ) ,
2018-02-27 18:06:05 +01:00
context_menu_ ( new QMenu ( this ) ) ,
progress_bar_ ( new QProgressBar ( this ) ) ,
abort_progress_ ( new QPushButton ( this ) ) ,
jobs_ ( 0 ) ,
2021-02-26 21:03:51 +01:00
all_artists_ ( nullptr ) {
2018-02-27 18:06:05 +01:00
ui_ - > setupUi ( this ) ;
ui_ - > albums - > set_cover_manager ( this ) ;
// Icons
2019-10-20 00:17:28 +02:00
ui_ - > action_fetch - > setIcon ( IconLoader : : Load ( " download " ) ) ;
ui_ - > export_covers - > setIcon ( IconLoader : : Load ( " document-save " ) ) ;
ui_ - > view - > setIcon ( IconLoader : : Load ( " view-choose " ) ) ;
ui_ - > button_fetch - > setIcon ( IconLoader : : Load ( " download " ) ) ;
ui_ - > action_add_to_playlist - > setIcon ( IconLoader : : Load ( " media-playback-start " ) ) ;
ui_ - > action_load - > setIcon ( IconLoader : : Load ( " media-playback-start " ) ) ;
2018-02-27 18:06:05 +01:00
2019-07-07 21:14:24 +02:00
album_cover_choice_controller_ - > Init ( app_ ) ;
2018-02-27 18:06:05 +01:00
2021-02-26 21:03:51 +01:00
cover_searcher_ = new AlbumCoverSearcher ( icon_nocover_item_ , app_ , this ) ;
2018-02-27 18:06:05 +01:00
cover_export_ = new AlbumCoverExport ( this ) ;
// Set up the status bar
statusBar ( ) - > addPermanentWidget ( progress_bar_ ) ;
statusBar ( ) - > addPermanentWidget ( abort_progress_ ) ;
progress_bar_ - > hide ( ) ;
abort_progress_ - > hide ( ) ;
abort_progress_ - > setText ( tr ( " Abort " ) ) ;
2021-01-26 16:48:04 +01:00
QObject : : connect ( abort_progress_ , & QPushButton : : clicked , this , & AlbumCoverManager : : CancelRequests ) ;
2018-02-27 18:06:05 +01:00
ui_ - > albums - > setAttribute ( Qt : : WA_MacShowFocusRect , false ) ;
ui_ - > artists - > setAttribute ( Qt : : WA_MacShowFocusRect , false ) ;
QShortcut * close = new QShortcut ( QKeySequence : : Close , this ) ;
2021-01-26 16:48:04 +01:00
QObject : : connect ( close , & QShortcut : : activated , this , & AlbumCoverManager : : close ) ;
2018-02-27 18:06:05 +01:00
2021-02-26 21:03:51 +01:00
cover_loader_options_ . scale_output_image_ = true ;
cover_loader_options_ . pad_output_image_ = true ;
cover_loader_options_ . desired_height_ = 120 ;
cover_loader_options_ . create_thumbnail_ = false ;
2018-02-27 18:06:05 +01:00
EnableCoversButtons ( ) ;
}
AlbumCoverManager : : ~ AlbumCoverManager ( ) {
2020-04-06 22:30:03 +02:00
2018-02-27 18:06:05 +01:00
CancelRequests ( ) ;
delete ui_ ;
2020-04-06 22:30:03 +02:00
2018-02-27 18:06:05 +01:00
}
void AlbumCoverManager : : Init ( ) {
// View menu
QActionGroup * filter_group = new QActionGroup ( this ) ;
filter_all_ = filter_group - > addAction ( tr ( " All albums " ) ) ;
filter_with_covers_ = filter_group - > addAction ( tr ( " Albums with covers " ) ) ;
filter_without_covers_ = filter_group - > addAction ( tr ( " Albums without covers " ) ) ;
filter_all_ - > setCheckable ( true ) ;
filter_with_covers_ - > setCheckable ( true ) ;
filter_without_covers_ - > setCheckable ( true ) ;
filter_group - > setExclusive ( true ) ;
filter_all_ - > setChecked ( true ) ;
QMenu * view_menu = new QMenu ( this ) ;
view_menu - > addActions ( filter_group - > actions ( ) ) ;
ui_ - > view - > setMenu ( view_menu ) ;
// Context menu
QList < QAction * > actions = album_cover_choice_controller_ - > GetAllActions ( ) ;
2021-09-19 19:31:34 +02:00
QObject : : connect ( album_cover_choice_controller_ , & AlbumCoverChoiceController : : Error , this , & AlbumCoverManager : : Error ) ;
2021-01-26 16:48:04 +01:00
QObject : : connect ( album_cover_choice_controller_ - > cover_from_file_action ( ) , & QAction : : triggered , this , & AlbumCoverManager : : LoadCoverFromFile ) ;
QObject : : connect ( album_cover_choice_controller_ - > cover_to_file_action ( ) , & QAction : : triggered , this , & AlbumCoverManager : : SaveCoverToFile ) ;
QObject : : connect ( album_cover_choice_controller_ - > cover_from_url_action ( ) , & QAction : : triggered , this , & AlbumCoverManager : : LoadCoverFromURL ) ;
QObject : : connect ( album_cover_choice_controller_ - > search_for_cover_action ( ) , & QAction : : triggered , this , & AlbumCoverManager : : SearchForCover ) ;
QObject : : connect ( album_cover_choice_controller_ - > unset_cover_action ( ) , & QAction : : triggered , this , & AlbumCoverManager : : UnsetCover ) ;
2021-02-26 21:03:51 +01:00
QObject : : connect ( album_cover_choice_controller_ - > clear_cover_action ( ) , & QAction : : triggered , this , & AlbumCoverManager : : ClearCover ) ;
QObject : : connect ( album_cover_choice_controller_ - > delete_cover_action ( ) , & QAction : : triggered , this , & AlbumCoverManager : : DeleteCover ) ;
2021-01-26 16:48:04 +01:00
QObject : : connect ( album_cover_choice_controller_ - > show_cover_action ( ) , & QAction : : triggered , this , & AlbumCoverManager : : ShowCover ) ;
2018-02-27 18:06:05 +01:00
2021-01-26 16:48:04 +01:00
QObject : : connect ( cover_exporter_ , & AlbumCoverExporter : : AlbumCoversExportUpdate , this , & AlbumCoverManager : : UpdateExportStatus ) ;
2018-02-27 18:06:05 +01:00
context_menu_ - > addActions ( actions ) ;
context_menu_ - > addSeparator ( ) ;
context_menu_ - > addAction ( ui_ - > action_load ) ;
context_menu_ - > addAction ( ui_ - > action_add_to_playlist ) ;
ui_ - > albums - > installEventFilter ( this ) ;
// Connections
2021-01-26 16:48:04 +01:00
QObject : : connect ( ui_ - > artists , & QListWidget : : currentItemChanged , this , & AlbumCoverManager : : ArtistChanged ) ;
QObject : : connect ( ui_ - > filter , & QSearchField : : textChanged , this , & AlbumCoverManager : : UpdateFilter ) ;
QObject : : connect ( filter_group , & QActionGroup : : triggered , this , & AlbumCoverManager : : UpdateFilter ) ;
QObject : : connect ( ui_ - > view , & QToolButton : : clicked , ui_ - > view , & QToolButton : : showMenu ) ;
QObject : : connect ( ui_ - > button_fetch , & QPushButton : : clicked , this , & AlbumCoverManager : : FetchAlbumCovers ) ;
QObject : : connect ( ui_ - > export_covers , & QPushButton : : clicked , this , & AlbumCoverManager : : ExportCovers ) ;
QObject : : connect ( cover_fetcher_ , & AlbumCoverFetcher : : AlbumCoverFetched , this , & AlbumCoverManager : : AlbumCoverFetched ) ;
QObject : : connect ( ui_ - > action_fetch , & QAction : : triggered , this , & AlbumCoverManager : : FetchSingleCover ) ;
QObject : : connect ( ui_ - > albums , & QListWidget : : doubleClicked , this , & AlbumCoverManager : : AlbumDoubleClicked ) ;
QObject : : connect ( ui_ - > action_add_to_playlist , & QAction : : triggered , this , & AlbumCoverManager : : AddSelectedToPlaylist ) ;
QObject : : connect ( ui_ - > action_load , & QAction : : triggered , this , & AlbumCoverManager : : LoadSelectedToPlaylist ) ;
2018-02-27 18:06:05 +01:00
// Restore settings
QSettings s ;
s . beginGroup ( kSettingsGroup ) ;
2021-02-26 21:03:51 +01:00
if ( s . contains ( " geometry " ) ) {
restoreGeometry ( s . value ( " geometry " ) . toByteArray ( ) ) ;
}
2021-07-12 13:45:51 +02:00
if ( ! s . contains ( " splitter_state " ) | | ! ui_ - > splitter - > restoreState ( s . value ( " splitter_state " ) . toByteArray ( ) ) ) {
2018-02-27 18:06:05 +01:00
// Sensible default size for the artists view
ui_ - > splitter - > setSizes ( QList < int > ( ) < < 200 < < width ( ) - 200 ) ;
}
2021-02-26 21:03:51 +01:00
s . endGroup ( ) ;
2021-01-26 16:48:04 +01:00
QObject : : connect ( app_ - > album_cover_loader ( ) , & AlbumCoverLoader : : AlbumCoverLoaded , this , & AlbumCoverManager : : AlbumCoverLoaded ) ;
2021-02-26 21:03:51 +01:00
QObject : : connect ( app_ - > album_cover_loader ( ) , & AlbumCoverLoader : : SaveEmbeddedCoverAsyncFinished , this , & AlbumCoverManager : : SaveEmbeddedCoverAsyncFinished ) ;
2018-02-27 18:06:05 +01:00
cover_searcher_ - > Init ( cover_fetcher_ ) ;
new ForceScrollPerPixel ( ui_ - > albums , this ) ;
}
2021-02-26 21:03:51 +01:00
void AlbumCoverManager : : showEvent ( QShowEvent * e ) {
2020-04-06 22:30:03 +02:00
2021-02-26 21:03:51 +01:00
if ( ! e - > spontaneous ( ) ) {
LoadGeometry ( ) ;
2021-03-07 00:54:20 +01:00
album_cover_choice_controller_ - > ReloadSettings ( ) ;
2021-02-26 21:03:51 +01:00
Reset ( ) ;
}
2020-04-06 22:30:03 +02:00
2021-03-15 22:38:06 +01:00
QMainWindow : : showEvent ( e ) ;
2018-02-27 18:06:05 +01:00
}
void AlbumCoverManager : : closeEvent ( QCloseEvent * e ) {
2018-03-05 21:05:30 +01:00
2018-02-27 18:06:05 +01:00
if ( ! cover_fetching_tasks_ . isEmpty ( ) ) {
std : : unique_ptr < QMessageBox > message_box ( new QMessageBox ( QMessageBox : : Question , tr ( " Really cancel? " ) , tr ( " Closing this window will stop searching for album covers. " ) , QMessageBox : : Abort , this ) ) ;
message_box - > addButton ( tr ( " Don't stop! " ) , QMessageBox : : AcceptRole ) ;
if ( message_box - > exec ( ) ! = QMessageBox : : Abort ) {
e - > ignore ( ) ;
return ;
}
}
2021-02-26 21:03:51 +01:00
SaveSettings ( ) ;
2020-04-06 22:30:03 +02:00
// Cancel any outstanding requests
CancelRequests ( ) ;
2020-05-10 11:50:05 +02:00
ui_ - > artists - > clear ( ) ;
ui_ - > albums - > clear ( ) ;
2021-03-15 22:38:06 +01:00
QMainWindow : : closeEvent ( e ) ;
2020-04-06 22:30:03 +02:00
}
void AlbumCoverManager : : LoadGeometry ( ) {
2018-02-27 18:06:05 +01:00
QSettings s ;
s . beginGroup ( kSettingsGroup ) ;
2020-04-06 22:30:03 +02:00
if ( s . contains ( " geometry " ) ) {
restoreGeometry ( s . value ( " geometry " ) . toByteArray ( ) ) ;
}
if ( s . contains ( " splitter_state " ) ) {
ui_ - > splitter - > restoreState ( s . value ( " splitter_state " ) . toByteArray ( ) ) ;
}
else {
// Sensible default size for the artists view
ui_ - > splitter - > setSizes ( QList < int > ( ) < < 200 < < width ( ) - 200 ) ;
}
s . endGroup ( ) ;
// Center the window on the same screen as the mainwindow.
2020-04-06 23:14:23 +02:00
# if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
QScreen * screen = mainwindow_ - > screen ( ) ;
2020-04-06 22:30:03 +02:00
# else
2020-04-06 23:14:23 +02:00
QScreen * screen = ( mainwindow_ - > window ( ) & & mainwindow_ - > window ( ) - > windowHandle ( ) ? mainwindow_ - > window ( ) - > windowHandle ( ) - > screen ( ) : nullptr ) ;
2020-04-06 22:30:03 +02:00
# endif
if ( screen ) {
const QRect sr = screen - > availableGeometry ( ) ;
const QRect wr ( { } , size ( ) . boundedTo ( sr . size ( ) ) ) ;
resize ( wr . size ( ) ) ;
move ( sr . center ( ) - wr . center ( ) ) ;
}
2018-02-27 18:06:05 +01:00
2020-04-06 22:30:03 +02:00
}
2021-02-26 21:03:51 +01:00
void AlbumCoverManager : : SaveSettings ( ) {
2020-04-06 22:30:03 +02:00
QSettings s ;
s . beginGroup ( kSettingsGroup ) ;
2018-02-27 18:06:05 +01:00
s . setValue ( " geometry " , saveGeometry ( ) ) ;
s . setValue ( " splitter_state " , ui_ - > splitter - > saveState ( ) ) ;
2023-02-18 14:09:27 +01:00
s . setValue ( " save_cover_type " , static_cast < int > ( album_cover_choice_controller_ - > get_save_album_cover_type ( ) ) ) ;
2020-04-06 22:30:03 +02:00
s . endGroup ( ) ;
2018-02-27 18:06:05 +01:00
}
void AlbumCoverManager : : CancelRequests ( ) {
2019-12-21 18:22:18 +01:00
# if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
2019-12-30 02:28:54 +01:00
app_ - > album_cover_loader ( ) - > CancelTasks ( QSet < quint64 > ( cover_loading_tasks_ . keyBegin ( ) , cover_loading_tasks_ . keyEnd ( ) ) ) ;
2019-12-21 18:22:18 +01:00
# else
2018-02-27 18:06:05 +01:00
app_ - > album_cover_loader ( ) - > CancelTasks ( QSet < quint64 > : : fromList ( cover_loading_tasks_ . keys ( ) ) ) ;
2019-12-21 18:22:18 +01:00
# endif
2018-02-27 18:06:05 +01:00
cover_loading_tasks_ . clear ( ) ;
2021-02-26 21:03:51 +01:00
cover_save_tasks_ . clear ( ) ;
cover_save_tasks2_ . clear ( ) ;
2018-02-27 18:06:05 +01:00
cover_exporter_ - > Cancel ( ) ;
cover_fetching_tasks_ . clear ( ) ;
cover_fetcher_ - > Clear ( ) ;
progress_bar_ - > hide ( ) ;
abort_progress_ - > hide ( ) ;
statusBar ( ) - > clearMessage ( ) ;
EnableCoversButtons ( ) ;
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
}
static bool CompareNocase ( const QString & left , const QString & right ) {
return QString : : localeAwareCompare ( left , right ) < 0 ;
}
static bool CompareAlbumNameNocase ( const CollectionBackend : : Album & left , const CollectionBackend : : Album & right ) {
2021-02-26 21:03:51 +01:00
return CompareNocase ( left . album , right . album ) ;
2018-02-27 18:06:05 +01:00
}
void AlbumCoverManager : : Reset ( ) {
2018-05-01 00:41:33 +02:00
2018-02-27 18:06:05 +01:00
EnableCoversButtons ( ) ;
ui_ - > artists - > clear ( ) ;
2021-02-26 21:03:51 +01:00
all_artists_ = new QListWidgetItem ( all_artists_icon_ , tr ( " All artists " ) , ui_ - > artists , All_Artists ) ;
new AlbumItem ( artist_icon_ , tr ( " Various artists " ) , ui_ - > artists , Various_Artists ) ;
2018-02-27 18:06:05 +01:00
QStringList artists ( collection_backend_ - > GetAllArtistsWithAlbums ( ) ) ;
2018-10-19 20:18:46 +02:00
std : : stable_sort ( artists . begin ( ) , artists . end ( ) , CompareNocase ) ;
2018-02-27 18:06:05 +01:00
for ( const QString & artist : artists ) {
if ( artist . isEmpty ( ) ) continue ;
new QListWidgetItem ( artist_icon_ , artist , ui_ - > artists , Specific_Artist ) ;
}
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
}
void AlbumCoverManager : : EnableCoversButtons ( ) {
2018-03-05 21:05:30 +01:00
ui_ - > button_fetch - > setEnabled ( app_ - > cover_providers ( ) - > HasAnyProviders ( ) ) ;
2018-02-27 18:06:05 +01:00
ui_ - > export_covers - > setEnabled ( true ) ;
}
void AlbumCoverManager : : DisableCoversButtons ( ) {
2018-03-05 21:05:30 +01:00
ui_ - > button_fetch - > setEnabled ( false ) ;
2018-02-27 18:06:05 +01:00
ui_ - > export_covers - > setEnabled ( false ) ;
}
void AlbumCoverManager : : ArtistChanged ( QListWidgetItem * current ) {
if ( ! current ) return ;
ui_ - > albums - > clear ( ) ;
context_menu_items_ . clear ( ) ;
CancelRequests ( ) ;
// Get the list of albums. How we do it depends on what thing we have selected in the artist list.
CollectionBackend : : AlbumList albums ;
switch ( current - > type ( ) ) {
case Various_Artists : albums = collection_backend_ - > GetCompilationAlbums ( ) ; break ;
case Specific_Artist : albums = collection_backend_ - > GetAlbumsByArtist ( current - > text ( ) ) ; break ;
case All_Artists :
default : albums = collection_backend_ - > GetAllAlbums ( ) ; break ;
}
// Sort by album name. The list is already sorted by sqlite but it was done case sensitively.
2018-10-19 20:18:46 +02:00
std : : stable_sort ( albums . begin ( ) , albums . end ( ) , CompareAlbumNameNocase ) ;
2018-02-27 18:06:05 +01:00
for ( const CollectionBackend : : Album & info : albums ) {
2021-02-26 21:03:51 +01:00
2018-02-27 18:06:05 +01:00
// Don't show songs without an album, obviously
2021-02-26 21:03:51 +01:00
if ( info . album . isEmpty ( ) ) continue ;
2018-02-27 18:06:05 +01:00
2021-02-26 21:03:51 +01:00
QString display_text ;
if ( current - > type ( ) = = Specific_Artist ) {
display_text = info . album ;
}
else {
display_text = info . album_artist + " - " + info . album ;
}
AlbumItem * item = new AlbumItem ( icon_nocover_item_ , display_text , ui_ - > albums ) ;
item - > setData ( Role_AlbumArtist , info . album_artist ) ;
item - > setData ( Role_Album , info . album ) ;
2023-02-18 14:09:27 +01:00
item - > setData ( Role_Filetype , QVariant : : fromValue ( info . filetype ) ) ;
2021-02-26 21:03:51 +01:00
item - > setData ( Role_CuePath , info . cue_path ) ;
2018-02-27 18:06:05 +01:00
item - > setData ( Qt : : TextAlignmentRole , QVariant ( Qt : : AlignTop | Qt : : AlignHCenter ) ) ;
item - > setFlags ( Qt : : ItemIsSelectable | Qt : : ItemIsEnabled | Qt : : ItemIsDragEnabled ) ;
2021-02-26 21:03:51 +01:00
item - > urls = info . urls ;
2018-02-27 18:06:05 +01:00
2021-02-26 21:03:51 +01:00
if ( info . album_artist . isEmpty ( ) ) {
item - > setToolTip ( info . album ) ;
2018-02-27 18:06:05 +01:00
}
else {
2021-02-26 21:03:51 +01:00
item - > setToolTip ( info . album_artist + " - " + info . album ) ;
2018-02-27 18:06:05 +01:00
}
if ( ! info . art_automatic . isEmpty ( ) | | ! info . art_manual . isEmpty ( ) ) {
item - > setData ( Role_PathAutomatic , info . art_automatic ) ;
item - > setData ( Role_PathManual , info . art_manual ) ;
2021-02-26 21:03:51 +01:00
quint64 id = app_ - > album_cover_loader ( ) - > LoadImageAsync ( cover_loader_options_ , info . art_automatic , info . art_manual , info . urls . first ( ) ) ;
2018-02-27 18:06:05 +01:00
cover_loading_tasks_ [ id ] = item ;
}
2021-02-26 21:03:51 +01:00
2018-02-27 18:06:05 +01:00
}
UpdateFilter ( ) ;
}
2020-04-20 18:03:18 +02:00
void AlbumCoverManager : : AlbumCoverLoaded ( const quint64 id , const AlbumCoverLoaderResult & result ) {
2019-09-15 20:27:32 +02:00
2018-02-27 18:06:05 +01:00
if ( ! cover_loading_tasks_ . contains ( id ) ) return ;
2021-02-26 21:03:51 +01:00
AlbumItem * item = cover_loading_tasks_ . take ( id ) ;
2018-02-27 18:06:05 +01:00
2021-02-26 21:03:51 +01:00
if ( ! result . success | | result . image_scaled . isNull ( ) | | result . type = = AlbumCoverLoaderResult : : Type_ManuallyUnset ) {
item - > setIcon ( icon_nocover_item_ ) ;
}
else {
item - > setIcon ( QPixmap : : fromImage ( result . image_scaled ) ) ;
}
//item->setData(Role_Image, result.image_original);
//item->setData(Role_ImageData, result.image_data);
2018-02-27 18:06:05 +01:00
UpdateFilter ( ) ;
2018-03-04 14:10:50 +01:00
2018-02-27 18:06:05 +01:00
}
void AlbumCoverManager : : UpdateFilter ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
const QString filter = ui_ - > filter - > text ( ) . toLower ( ) ;
const bool hide_with_covers = filter_without_covers_ - > isChecked ( ) ;
const bool hide_without_covers = filter_with_covers_ - > isChecked ( ) ;
2023-02-18 14:09:27 +01:00
HideCovers hide_covers = HideCovers : : None ;
2018-02-27 18:06:05 +01:00
if ( hide_with_covers ) {
2023-02-18 14:09:27 +01:00
hide_covers = HideCovers : : WithCovers ;
2018-02-27 18:06:05 +01:00
}
else if ( hide_without_covers ) {
2023-02-18 14:09:27 +01:00
hide_covers = HideCovers : : WithoutCovers ;
2018-02-27 18:06:05 +01:00
}
qint32 total_count = 0 ;
qint32 without_cover = 0 ;
for ( int i = 0 ; i < ui_ - > albums - > count ( ) ; + + i ) {
2021-02-26 21:03:51 +01:00
AlbumItem * item = static_cast < AlbumItem * > ( ui_ - > albums - > item ( i ) ) ;
2023-02-18 14:09:27 +01:00
bool should_hide = ShouldHide ( * item , filter , hide_covers ) ;
2018-02-27 18:06:05 +01:00
item - > setHidden ( should_hide ) ;
if ( ! should_hide ) {
2021-02-26 21:03:51 +01:00
+ + total_count ;
2018-02-27 18:06:05 +01:00
if ( ! ItemHasCover ( * item ) ) {
2021-02-26 21:03:51 +01:00
+ + without_cover ;
2018-02-27 18:06:05 +01:00
}
}
}
ui_ - > total_albums - > setText ( QString : : number ( total_count ) ) ;
ui_ - > without_cover - > setText ( QString : : number ( without_cover ) ) ;
}
2023-02-18 14:09:27 +01:00
bool AlbumCoverManager : : ShouldHide ( const AlbumItem & item , const QString & filter , const HideCovers hide_covers ) const {
2018-02-27 18:06:05 +01:00
bool has_cover = ItemHasCover ( item ) ;
2023-02-18 14:09:27 +01:00
if ( hide_covers = = HideCovers : : WithCovers & & has_cover ) {
2018-02-27 18:06:05 +01:00
return true ;
}
2023-02-18 14:09:27 +01:00
else if ( hide_covers = = HideCovers : : WithoutCovers & & ! has_cover ) {
2018-02-27 18:06:05 +01:00
return true ;
}
if ( filter . isEmpty ( ) ) {
return false ;
}
QStringList query = filter . split ( ' ' ) ;
for ( const QString & s : query ) {
bool in_text = item . text ( ) . contains ( s , Qt : : CaseInsensitive ) ;
2021-02-26 21:03:51 +01:00
bool in_albumartist = item . data ( Role_AlbumArtist ) . toString ( ) . contains ( s , Qt : : CaseInsensitive ) ;
if ( ! in_text & & ! in_albumartist ) {
2018-02-27 18:06:05 +01:00
return true ;
}
}
return false ;
}
void AlbumCoverManager : : FetchAlbumCovers ( ) {
for ( int i = 0 ; i < ui_ - > albums - > count ( ) ; + + i ) {
2021-02-26 21:03:51 +01:00
AlbumItem * item = static_cast < AlbumItem * > ( ui_ - > albums - > item ( i ) ) ;
2018-02-27 18:06:05 +01:00
if ( item - > isHidden ( ) ) continue ;
if ( ItemHasCover ( * item ) ) continue ;
2021-02-26 21:03:51 +01:00
quint64 id = cover_fetcher_ - > FetchAlbumCover ( item - > data ( Role_AlbumArtist ) . toString ( ) , item - > data ( Role_Album ) . toString ( ) , QString ( ) , true ) ;
2018-02-27 18:06:05 +01:00
cover_fetching_tasks_ [ id ] = item ;
jobs_ + + ;
}
2018-03-05 21:05:30 +01:00
if ( ! cover_fetching_tasks_ . isEmpty ( ) ) ui_ - > button_fetch - > setEnabled ( false ) ;
2018-02-27 18:06:05 +01:00
progress_bar_ - > setMaximum ( jobs_ ) ;
progress_bar_ - > show ( ) ;
abort_progress_ - > show ( ) ;
fetch_statistics_ = CoverSearchStatistics ( ) ;
UpdateStatusText ( ) ;
}
2021-02-26 21:03:51 +01:00
void AlbumCoverManager : : AlbumCoverFetched ( const quint64 id , const AlbumCoverImageResult & result , const CoverSearchStatistics & statistics ) {
2018-02-27 18:06:05 +01:00
2021-02-26 21:03:51 +01:00
if ( ! cover_fetching_tasks_ . contains ( id ) ) return ;
2018-02-27 18:06:05 +01:00
2021-02-26 21:03:51 +01:00
AlbumItem * item = cover_fetching_tasks_ . take ( id ) ;
if ( ! result . image . isNull ( ) ) {
SaveAndSetCover ( item , result ) ;
2018-02-27 18:06:05 +01:00
}
if ( cover_fetching_tasks_ . isEmpty ( ) ) {
EnableCoversButtons ( ) ;
}
fetch_statistics_ + = statistics ;
UpdateStatusText ( ) ;
2018-03-05 21:05:30 +01:00
2018-02-27 18:06:05 +01:00
}
void AlbumCoverManager : : UpdateStatusText ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
QString message = tr ( " Got %1 covers out of %2 (%3 failed) " )
. arg ( fetch_statistics_ . chosen_images_ )
. arg ( jobs_ )
. arg ( fetch_statistics_ . missing_images_ ) ;
2021-06-22 13:54:58 +02:00
if ( fetch_statistics_ . bytes_transferred_ > 0 ) {
2018-02-27 18:06:05 +01:00
message + = " , " + tr ( " %1 transferred " ) . arg ( Utilities : : PrettySize ( fetch_statistics_ . bytes_transferred_ ) ) ;
}
statusBar ( ) - > showMessage ( message ) ;
2021-03-21 18:53:02 +01:00
progress_bar_ - > setValue ( static_cast < int > ( fetch_statistics_ . chosen_images_ + fetch_statistics_ . missing_images_ ) ) ;
2018-02-27 18:06:05 +01:00
if ( cover_fetching_tasks_ . isEmpty ( ) ) {
2021-01-26 16:48:04 +01:00
QTimer : : singleShot ( 2000 , statusBar ( ) , & QStatusBar : : clearMessage ) ;
2018-02-27 18:06:05 +01:00
progress_bar_ - > hide ( ) ;
abort_progress_ - > hide ( ) ;
CoverSearchStatisticsDialog * dialog = new CoverSearchStatisticsDialog ( this ) ;
dialog - > setAttribute ( Qt : : WA_DeleteOnClose ) ;
dialog - > Show ( fetch_statistics_ ) ;
jobs_ = 0 ;
}
}
2021-02-26 21:03:51 +01:00
bool AlbumCoverManager : : eventFilter ( QObject * obj , QEvent * e ) {
2018-02-27 18:06:05 +01:00
2021-02-26 21:03:51 +01:00
if ( obj = = ui_ - > albums & & e - > type ( ) = = QEvent : : ContextMenu ) {
2018-02-27 18:06:05 +01:00
context_menu_items_ = ui_ - > albums - > selectedItems ( ) ;
2021-06-20 19:04:08 +02:00
if ( context_menu_items_ . isEmpty ( ) ) return QMainWindow : : eventFilter ( obj , e ) ;
2018-02-27 18:06:05 +01:00
bool some_with_covers = false ;
2021-03-07 03:43:49 +01:00
bool some_unset = false ;
bool some_clear = false ;
2018-02-27 18:06:05 +01:00
for ( QListWidgetItem * item : context_menu_items_ ) {
2021-02-26 21:03:51 +01:00
AlbumItem * album_item = static_cast < AlbumItem * > ( item ) ;
if ( ItemHasCover ( * album_item ) ) some_with_covers = true ;
2021-03-07 03:43:49 +01:00
if ( album_item - > data ( Role_PathManual ) . toUrl ( ) . path ( ) = = Song : : kManuallyUnsetCover ) {
some_unset = true ;
}
else if ( album_item - > data ( Role_PathAutomatic ) . toUrl ( ) . isEmpty ( ) & & album_item - > data ( Role_PathManual ) . toUrl ( ) . isEmpty ( ) ) {
some_clear = true ;
}
2018-02-27 18:06:05 +01:00
}
2021-02-26 21:03:51 +01:00
album_cover_choice_controller_ - > show_cover_action ( ) - > setEnabled ( some_with_covers & & context_menu_items_ . size ( ) = = 1 ) ;
album_cover_choice_controller_ - > cover_to_file_action ( ) - > setEnabled ( some_with_covers ) ;
2018-02-27 18:06:05 +01:00
album_cover_choice_controller_ - > cover_from_file_action ( ) - > setEnabled ( context_menu_items_ . size ( ) = = 1 ) ;
album_cover_choice_controller_ - > cover_from_url_action ( ) - > setEnabled ( context_menu_items_ . size ( ) = = 1 ) ;
album_cover_choice_controller_ - > search_for_cover_action ( ) - > setEnabled ( app_ - > cover_providers ( ) - > HasAnyProviders ( ) ) ;
2021-03-07 03:43:49 +01:00
album_cover_choice_controller_ - > unset_cover_action ( ) - > setEnabled ( some_with_covers | | some_clear ) ;
album_cover_choice_controller_ - > clear_cover_action ( ) - > setEnabled ( some_with_covers | | some_unset ) ;
2021-02-26 21:03:51 +01:00
album_cover_choice_controller_ - > delete_cover_action ( ) - > setEnabled ( some_with_covers ) ;
2018-02-27 18:06:05 +01:00
2021-02-26 21:03:51 +01:00
QContextMenuEvent * context_menu_event = static_cast < QContextMenuEvent * > ( e ) ;
context_menu_ - > popup ( context_menu_event - > globalPos ( ) ) ;
2018-02-27 18:06:05 +01:00
return true ;
}
2021-06-20 19:04:08 +02:00
2021-02-26 21:03:51 +01:00
return QMainWindow : : eventFilter ( obj , e ) ;
2018-02-27 18:06:05 +01:00
}
Song AlbumCoverManager : : GetSingleSelectionAsSong ( ) {
return context_menu_items_ . size ( ) ! = 1 ? Song ( ) : ItemAsSong ( context_menu_items_ [ 0 ] ) ;
}
Song AlbumCoverManager : : GetFirstSelectedAsSong ( ) {
return context_menu_items_ . isEmpty ( ) ? Song ( ) : ItemAsSong ( context_menu_items_ [ 0 ] ) ;
}
2021-02-26 21:03:51 +01:00
Song AlbumCoverManager : : ItemAsSong ( AlbumItem * item ) {
2018-10-02 00:38:52 +02:00
2023-02-18 14:09:27 +01:00
Song result ( Song : : Source : : Collection ) ;
2018-02-27 18:06:05 +01:00
2021-02-26 21:03:51 +01:00
QString title = item - > data ( Role_Album ) . toString ( ) ;
QString artist_name = item - > data ( Role_AlbumArtist ) . toString ( ) ;
2018-02-27 18:06:05 +01:00
if ( ! artist_name . isEmpty ( ) ) {
result . set_title ( artist_name + " - " + title ) ;
}
else {
result . set_title ( title ) ;
}
2021-02-26 21:03:51 +01:00
result . set_artist ( item - > data ( Role_AlbumArtist ) . toString ( ) ) ;
result . set_albumartist ( item - > data ( Role_AlbumArtist ) . toString ( ) ) ;
result . set_album ( item - > data ( Role_Album ) . toString ( ) ) ;
2018-02-27 18:06:05 +01:00
2022-06-13 00:23:42 +02:00
result . set_filetype ( static_cast < Song : : FileType > ( item - > data ( Role_Filetype ) . toInt ( ) ) ) ;
2021-02-26 21:03:51 +01:00
result . set_url ( item - > urls . first ( ) ) ;
result . set_cue_path ( item - > data ( Role_CuePath ) . toString ( ) ) ;
2018-02-27 18:06:05 +01:00
2019-07-07 21:14:24 +02:00
result . set_art_automatic ( item - > data ( Role_PathAutomatic ) . toUrl ( ) ) ;
result . set_art_manual ( item - > data ( Role_PathManual ) . toUrl ( ) ) ;
2018-02-27 18:06:05 +01:00
// force validity
result . set_valid ( true ) ;
result . set_id ( 0 ) ;
return result ;
}
void AlbumCoverManager : : ShowCover ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
Song song = GetSingleSelectionAsSong ( ) ;
if ( ! song . is_valid ( ) ) return ;
album_cover_choice_controller_ - > ShowCover ( song ) ;
2020-12-07 17:23:08 +01:00
2018-02-27 18:06:05 +01:00
}
void AlbumCoverManager : : FetchSingleCover ( ) {
2018-03-05 21:05:30 +01:00
2018-02-27 18:06:05 +01:00
for ( QListWidgetItem * item : context_menu_items_ ) {
2021-02-26 21:03:51 +01:00
AlbumItem * album_item = static_cast < AlbumItem * > ( item ) ;
quint64 id = cover_fetcher_ - > FetchAlbumCover ( album_item - > data ( Role_AlbumArtist ) . toString ( ) , album_item - > data ( Role_Album ) . toString ( ) , QString ( ) , false ) ;
cover_fetching_tasks_ [ id ] = album_item ;
2018-02-27 18:06:05 +01:00
jobs_ + + ;
}
progress_bar_ - > setMaximum ( jobs_ ) ;
progress_bar_ - > show ( ) ;
abort_progress_ - > show ( ) ;
UpdateStatusText ( ) ;
2018-03-05 21:05:30 +01:00
}
2018-02-27 18:06:05 +01:00
2021-02-26 21:03:51 +01:00
void AlbumCoverManager : : UpdateCoverInList ( AlbumItem * item , const QUrl & cover_url ) {
2018-10-02 00:38:52 +02:00
2019-07-07 21:14:24 +02:00
quint64 id = app_ - > album_cover_loader ( ) - > LoadImageAsync ( cover_loader_options_ , QUrl ( ) , cover_url ) ;
item - > setData ( Role_PathManual , cover_url ) ;
2018-02-27 18:06:05 +01:00
cover_loading_tasks_ [ id ] = item ;
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
}
void AlbumCoverManager : : LoadCoverFromFile ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
Song song = GetSingleSelectionAsSong ( ) ;
if ( ! song . is_valid ( ) ) return ;
2021-02-26 21:03:51 +01:00
AlbumCoverImageResult result = album_cover_choice_controller_ - > LoadImageFromFile ( & song ) ;
if ( ! result . image . isNull ( ) ) {
SaveImageToAlbums ( & song , result ) ;
2018-02-27 18:06:05 +01:00
}
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
}
void AlbumCoverManager : : SaveCoverToFile ( ) {
2018-03-05 21:05:30 +01:00
2018-02-27 18:06:05 +01:00
Song song = GetSingleSelectionAsSong ( ) ;
2021-02-26 21:03:51 +01:00
if ( ! song . is_valid ( ) | | song . has_manually_unset_cover ( ) ) return ;
2018-02-27 18:06:05 +01:00
2021-02-26 21:03:51 +01:00
AlbumCoverImageResult result ;
2018-02-27 18:06:05 +01:00
2018-05-01 00:41:33 +02:00
// Load the image from disk
2021-02-26 21:03:51 +01:00
if ( ! song . art_manual ( ) . isEmpty ( ) & & ! song . has_manually_unset_cover ( ) & & song . art_manual ( ) . isLocalFile ( ) & & QFile : : exists ( song . art_manual ( ) . toLocalFile ( ) ) ) {
result . image_data = Utilities : : ReadDataFromFile ( song . art_manual ( ) . toLocalFile ( ) ) ;
2018-02-27 18:06:05 +01:00
}
2021-02-26 21:03:51 +01:00
else if ( ! song . art_manual ( ) . isEmpty ( ) & & ! song . art_manual ( ) . path ( ) . isEmpty ( ) & & song . art_manual ( ) . scheme ( ) . isEmpty ( ) & & QFile : : exists ( song . art_manual ( ) . path ( ) ) ) {
result . image_data = Utilities : : ReadDataFromFile ( song . art_manual ( ) . path ( ) ) ;
}
else if ( song . has_embedded_cover ( ) ) {
result . image_data = TagReaderClient : : Instance ( ) - > LoadEmbeddedArtBlocking ( song . url ( ) . toLocalFile ( ) ) ;
}
else if ( ! song . art_automatic ( ) . isEmpty ( ) & & song . art_automatic ( ) . isLocalFile ( ) & & QFile : : exists ( song . art_automatic ( ) . toLocalFile ( ) ) ) {
result . image_data = Utilities : : ReadDataFromFile ( song . art_automatic ( ) . toLocalFile ( ) ) ;
}
else if ( ! song . art_automatic ( ) . isEmpty ( ) & & ! song . art_automatic ( ) . path ( ) . isEmpty ( ) & & song . art_automatic ( ) . scheme ( ) . isEmpty ( ) & & QFile : : exists ( song . art_automatic ( ) . path ( ) ) ) {
result . image_data = Utilities : : ReadDataFromFile ( song . art_automatic ( ) . path ( ) ) ;
2018-02-27 18:06:05 +01:00
}
2021-02-26 21:03:51 +01:00
if ( ! result . is_valid ( ) ) return ;
result . mime_type = Utilities : : MimeTypeFromData ( result . image_data ) ;
if ( ! result . image_data . isEmpty ( ) ) {
result . image . loadFromData ( result . image_data ) ;
}
album_cover_choice_controller_ - > SaveCoverToFileManual ( song , result ) ;
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
}
void AlbumCoverManager : : LoadCoverFromURL ( ) {
2018-03-05 21:05:30 +01:00
2018-02-27 18:06:05 +01:00
Song song = GetSingleSelectionAsSong ( ) ;
if ( ! song . is_valid ( ) ) return ;
2021-02-26 21:03:51 +01:00
AlbumCoverImageResult result = album_cover_choice_controller_ - > LoadImageFromURL ( ) ;
if ( result . is_valid ( ) ) {
SaveImageToAlbums ( & song , result ) ;
2018-02-27 18:06:05 +01:00
}
2018-03-05 21:05:30 +01:00
2018-02-27 18:06:05 +01:00
}
void AlbumCoverManager : : SearchForCover ( ) {
2018-03-05 21:05:30 +01:00
2018-02-27 18:06:05 +01:00
Song song = GetFirstSelectedAsSong ( ) ;
if ( ! song . is_valid ( ) ) return ;
2021-02-26 21:03:51 +01:00
AlbumCoverImageResult result = album_cover_choice_controller_ - > SearchForImage ( & song ) ;
if ( result . is_valid ( ) ) {
SaveImageToAlbums ( & song , result ) ;
}
2018-02-27 18:06:05 +01:00
2021-02-26 21:03:51 +01:00
}
void AlbumCoverManager : : SaveImageToAlbums ( Song * song , const AlbumCoverImageResult & result ) {
2021-03-16 17:18:11 +01:00
QUrl cover_url = result . cover_url ;
2021-02-26 21:03:51 +01:00
switch ( album_cover_choice_controller_ - > get_save_album_cover_type ( ) ) {
2023-03-18 20:03:07 +01:00
case CoverOptions : : CoverType : : Cache :
case CoverOptions : : CoverType : : Album :
2021-03-16 17:18:11 +01:00
if ( cover_url . isEmpty ( ) | | ! cover_url . isValid ( ) | | ! cover_url . isLocalFile ( ) ) {
cover_url = album_cover_choice_controller_ - > SaveCoverToFileAutomatic ( song , result ) ;
}
2021-02-26 21:03:51 +01:00
break ;
2023-03-18 20:03:07 +01:00
case CoverOptions : : CoverType : : Embedded :
2021-02-26 21:03:51 +01:00
cover_url = QUrl : : fromLocalFile ( Song : : kEmbeddedCover ) ;
break ;
}
2018-02-27 18:06:05 +01:00
2018-05-01 00:41:33 +02:00
// Force the found cover on all of the selected items
2021-02-26 21:03:51 +01:00
QList < QUrl > urls ;
QList < AlbumItem * > album_items ;
for ( QListWidgetItem * item : context_menu_items_ ) {
AlbumItem * album_item = static_cast < AlbumItem * > ( item ) ;
switch ( album_cover_choice_controller_ - > get_save_album_cover_type ( ) ) {
2023-03-18 20:03:07 +01:00
case CoverOptions : : CoverType : : Cache :
case CoverOptions : : CoverType : : Album : {
2021-02-26 21:03:51 +01:00
Song current_song = ItemAsSong ( album_item ) ;
album_cover_choice_controller_ - > SaveArtManualToSong ( & current_song , cover_url ) ;
UpdateCoverInList ( album_item , cover_url ) ;
break ;
}
2023-03-18 20:03:07 +01:00
case CoverOptions : : CoverType : : Embedded : {
2021-02-26 21:03:51 +01:00
urls < < album_item - > urls ;
album_items < < album_item ;
break ;
}
2018-02-27 18:06:05 +01:00
}
2021-02-26 21:03:51 +01:00
}
2018-02-27 18:06:05 +01:00
2023-03-18 20:03:07 +01:00
if ( album_cover_choice_controller_ - > get_save_album_cover_type ( ) = = CoverOptions : : CoverType : : Embedded & & ! urls . isEmpty ( ) ) {
2021-02-26 21:03:51 +01:00
quint64 id = - 1 ;
if ( result . is_jpeg ( ) ) {
id = app_ - > album_cover_loader ( ) - > SaveEmbeddedCoverAsync ( urls , result . image_data ) ;
}
else {
id = app_ - > album_cover_loader ( ) - > SaveEmbeddedCoverAsync ( urls , result . image ) ;
}
for ( AlbumItem * album_item : album_items ) {
cover_save_tasks_ . insert ( id , album_item ) ;
}
2018-02-27 18:06:05 +01:00
}
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
}
void AlbumCoverManager : : UnsetCover ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
Song song = GetFirstSelectedAsSong ( ) ;
if ( ! song . is_valid ( ) ) return ;
2021-02-26 21:03:51 +01:00
AlbumItem * first_album_item = static_cast < AlbumItem * > ( context_menu_items_ [ 0 ] ) ;
2018-02-27 18:06:05 +01:00
2019-07-07 21:14:24 +02:00
QUrl cover_url = album_cover_choice_controller_ - > UnsetCover ( & song ) ;
2018-02-27 18:06:05 +01:00
2018-05-01 00:41:33 +02:00
// Force the 'none' cover on all of the selected items
2021-02-26 21:03:51 +01:00
for ( QListWidgetItem * item : context_menu_items_ ) {
AlbumItem * album_item = static_cast < AlbumItem * > ( item ) ;
album_item - > setIcon ( icon_nocover_item_ ) ;
album_item - > setData ( Role_PathManual , cover_url ) ;
// Don't save the first one twice
if ( album_item ! = first_album_item ) {
Song current_song = ItemAsSong ( album_item ) ;
album_cover_choice_controller_ - > SaveArtManualToSong ( & current_song , cover_url ) ;
}
}
}
void AlbumCoverManager : : ClearCover ( ) {
Song song = GetFirstSelectedAsSong ( ) ;
if ( ! song . is_valid ( ) ) return ;
AlbumItem * first_album_item = static_cast < AlbumItem * > ( context_menu_items_ [ 0 ] ) ;
album_cover_choice_controller_ - > ClearCover ( & song ) ;
// Force the 'none' cover on all of the selected items
for ( QListWidgetItem * item : context_menu_items_ ) {
AlbumItem * album_item = static_cast < AlbumItem * > ( item ) ;
album_item - > setIcon ( icon_nocover_item_ ) ;
album_item - > setData ( Role_PathManual , QUrl ( ) ) ;
2018-02-27 18:06:05 +01:00
2018-05-01 00:41:33 +02:00
// Don't save the first one twice
2021-02-26 21:03:51 +01:00
if ( album_item ! = first_album_item ) {
Song current_song = ItemAsSong ( album_item ) ;
album_cover_choice_controller_ - > SaveArtManualToSong ( & current_song , QUrl ( ) , false ) ;
}
}
}
void AlbumCoverManager : : DeleteCover ( ) {
for ( QListWidgetItem * item : context_menu_items_ ) {
AlbumItem * album_item = static_cast < AlbumItem * > ( item ) ;
2021-03-07 03:43:49 +01:00
Song song = ItemAsSong ( album_item ) ;
album_cover_choice_controller_ - > DeleteCover ( & song ) ;
2021-02-26 21:03:51 +01:00
album_item - > setIcon ( icon_nocover_item_ ) ;
album_item - > setData ( Role_PathManual , QUrl ( ) ) ;
2021-03-07 03:43:49 +01:00
album_item - > setData ( Role_PathAutomatic , QUrl ( ) ) ;
2018-02-27 18:06:05 +01:00
}
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
}
2021-01-26 16:48:04 +01:00
SongList AlbumCoverManager : : GetSongsInAlbum ( const QModelIndex & idx ) const {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
SongList ret ;
2021-04-10 03:20:25 +02:00
QMutexLocker l ( collection_backend_ - > db ( ) - > Mutex ( ) ) ;
QSqlDatabase db ( collection_backend_ - > db ( ) - > Connect ( ) ) ;
CollectionQuery q ( db , collection_backend_ - > songs_table ( ) , collection_backend_ - > fts_table ( ) ) ;
2018-02-27 18:06:05 +01:00
q . SetColumnSpec ( " ROWID, " + Song : : kColumnSpec ) ;
2021-02-26 21:03:51 +01:00
q . AddWhere ( " album " , idx . data ( Role_Album ) . toString ( ) ) ;
2018-02-27 18:06:05 +01:00
q . SetOrderBy ( " disc, track, title " ) ;
2021-02-26 21:03:51 +01:00
QString albumartist = idx . data ( Role_AlbumArtist ) . toString ( ) ;
2018-02-27 18:06:05 +01:00
if ( ! albumartist . isEmpty ( ) ) {
2021-02-26 21:03:51 +01:00
q . AddWhere ( " effective_albumartist " , albumartist ) ;
2018-02-27 18:06:05 +01:00
}
2021-02-26 21:03:51 +01:00
q . AddCompilationRequirement ( albumartist . isEmpty ( ) ) ;
2018-02-27 18:06:05 +01:00
2021-04-10 03:20:25 +02:00
if ( ! q . Exec ( ) ) return ret ;
2018-02-27 18:06:05 +01:00
while ( q . Next ( ) ) {
Song song ;
song . InitFromQuery ( q , true ) ;
ret < < song ;
}
return ret ;
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
}
SongList AlbumCoverManager : : GetSongsInAlbums ( const QModelIndexList & indexes ) const {
SongList ret ;
2021-01-26 16:48:04 +01:00
for ( const QModelIndex & idx : indexes ) {
ret < < GetSongsInAlbum ( idx ) ;
2018-02-27 18:06:05 +01:00
}
return ret ;
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
}
SongMimeData * AlbumCoverManager : : GetMimeDataForAlbums ( const QModelIndexList & indexes ) const {
SongList songs = GetSongsInAlbums ( indexes ) ;
if ( songs . isEmpty ( ) ) return nullptr ;
2020-04-23 21:08:28 +02:00
SongMimeData * mimedata = new SongMimeData ;
mimedata - > backend = collection_backend_ ;
mimedata - > songs = songs ;
return mimedata ;
2018-02-27 18:06:05 +01:00
}
2020-12-07 17:23:08 +01:00
void AlbumCoverManager : : AlbumDoubleClicked ( const QModelIndex & idx ) {
2018-02-27 18:06:05 +01:00
2021-02-26 21:03:51 +01:00
AlbumItem * item = static_cast < AlbumItem * > ( idx . internalPointer ( ) ) ;
2020-12-07 17:23:08 +01:00
if ( ! item ) return ;
album_cover_choice_controller_ - > ShowCover ( ItemAsSong ( item ) ) ;
2018-02-27 18:06:05 +01:00
}
void AlbumCoverManager : : AddSelectedToPlaylist ( ) {
emit AddToPlaylist ( GetMimeDataForAlbums ( ui_ - > albums - > selectionModel ( ) - > selectedIndexes ( ) ) ) ;
}
void AlbumCoverManager : : LoadSelectedToPlaylist ( ) {
2020-04-23 21:08:28 +02:00
SongMimeData * mimedata = GetMimeDataForAlbums ( ui_ - > albums - > selectionModel ( ) - > selectedIndexes ( ) ) ;
if ( mimedata ) {
mimedata - > clear_first_ = true ;
emit AddToPlaylist ( mimedata ) ;
2018-02-27 18:06:05 +01:00
}
}
2021-02-26 21:03:51 +01:00
void AlbumCoverManager : : SaveAndSetCover ( AlbumItem * item , const AlbumCoverImageResult & result ) {
2018-10-02 00:38:52 +02:00
2021-02-26 21:03:51 +01:00
const QString albumartist = item - > data ( Role_AlbumArtist ) . toString ( ) ;
const QString album = item - > data ( Role_Album ) . toString ( ) ;
const QList < QUrl > & urls = item - > urls ;
2022-06-13 00:23:42 +02:00
const Song : : FileType filetype = static_cast < Song : : FileType > ( item - > data ( Role_Filetype ) . toInt ( ) ) ;
2021-02-26 21:03:51 +01:00
const bool has_cue = ! item - > data ( Role_CuePath ) . toString ( ) . isEmpty ( ) ;
2018-02-27 18:06:05 +01:00
2023-03-18 20:03:07 +01:00
if ( album_cover_choice_controller_ - > get_save_album_cover_type ( ) = = CoverOptions : : CoverType : : Embedded & & Song : : save_embedded_cover_supported ( filetype ) & & ! has_cue ) {
2021-02-26 21:03:51 +01:00
if ( result . is_jpeg ( ) ) {
quint64 id = app_ - > album_cover_loader ( ) - > SaveEmbeddedCoverAsync ( urls , result . image_data ) ;
cover_save_tasks_ . insert ( id , item ) ;
}
2021-03-07 23:03:02 +01:00
else if ( ! result . image . isNull ( ) ) {
2021-02-26 21:03:51 +01:00
quint64 id = app_ - > album_cover_loader ( ) - > SaveEmbeddedCoverAsync ( urls , result . image ) ;
cover_save_tasks_ . insert ( id , item ) ;
}
2021-03-07 23:03:02 +01:00
else if ( ! result . cover_url . isEmpty ( ) & & result . cover_url . isLocalFile ( ) ) {
quint64 id = app_ - > album_cover_loader ( ) - > SaveEmbeddedCoverAsync ( urls , result . cover_url . toLocalFile ( ) ) ;
cover_save_tasks_ . insert ( id , item ) ;
}
2021-02-26 21:03:51 +01:00
}
else {
2021-03-07 23:03:02 +01:00
QUrl cover_url ;
2021-03-16 17:18:11 +01:00
if ( ! result . cover_url . isEmpty ( ) & & result . cover_url . isValid ( ) & & result . cover_url . isLocalFile ( ) ) {
2021-03-07 23:03:02 +01:00
cover_url = result . cover_url ;
}
2021-03-16 17:18:11 +01:00
else if ( ! result . image_data . isEmpty ( ) | | ! result . image . isNull ( ) ) {
2023-02-18 14:09:27 +01:00
cover_url = album_cover_choice_controller_ - > SaveCoverToFileAutomatic ( Song : : Source : : Collection , albumartist , album , QString ( ) , urls . first ( ) . adjusted ( QUrl : : RemoveFilename ) . path ( ) , result , false ) ;
2021-03-16 17:18:11 +01:00
}
2018-02-27 18:06:05 +01:00
2021-02-26 21:03:51 +01:00
if ( cover_url . isEmpty ( ) ) return ;
2018-02-27 18:06:05 +01:00
2021-02-26 21:03:51 +01:00
// Save the image in the database
collection_backend_ - > UpdateManualAlbumArtAsync ( albumartist , album , cover_url ) ;
// Update the icon in our list
UpdateCoverInList ( item , cover_url ) ;
}
2018-04-06 22:13:11 +02:00
2018-02-27 18:06:05 +01:00
}
void AlbumCoverManager : : ExportCovers ( ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
AlbumCoverExport : : DialogResult result = cover_export_ - > Exec ( ) ;
if ( result . cancelled_ ) {
return ;
}
DisableCoversButtons ( ) ;
cover_exporter_ - > SetDialogResult ( result ) ;
for ( int i = 0 ; i < ui_ - > albums - > count ( ) ; + + i ) {
2021-02-26 21:03:51 +01:00
AlbumItem * item = static_cast < AlbumItem * > ( ui_ - > albums - > item ( i ) ) ;
2018-02-27 18:06:05 +01:00
// skip hidden and coverless albums
if ( item - > isHidden ( ) | | ! ItemHasCover ( * item ) ) {
continue ;
}
cover_exporter_ - > AddExportRequest ( ItemAsSong ( item ) ) ;
}
if ( cover_exporter_ - > request_count ( ) > 0 ) {
progress_bar_ - > setMaximum ( cover_exporter_ - > request_count ( ) ) ;
progress_bar_ - > show ( ) ;
abort_progress_ - > show ( ) ;
cover_exporter_ - > StartExporting ( ) ;
}
else {
QMessageBox msg ;
msg . setWindowTitle ( tr ( " Export finished " ) ) ;
msg . setText ( tr ( " No covers to export. " ) ) ;
msg . exec ( ) ;
}
}
2020-06-14 18:58:24 +02:00
void AlbumCoverManager : : UpdateExportStatus ( const int exported , const int skipped , const int max ) {
2018-10-02 00:38:52 +02:00
2018-02-27 18:06:05 +01:00
progress_bar_ - > setValue ( exported ) ;
QString message = tr ( " Exported %1 covers out of %2 (%3 skipped) " )
. arg ( exported )
. arg ( max )
. arg ( skipped ) ;
statusBar ( ) - > showMessage ( message ) ;
2018-05-01 00:41:33 +02:00
// End of the current process
2018-02-27 18:06:05 +01:00
if ( exported + skipped > = max ) {
2021-01-26 16:48:04 +01:00
QTimer : : singleShot ( 2000 , statusBar ( ) , & QStatusBar : : clearMessage ) ;
2018-02-27 18:06:05 +01:00
progress_bar_ - > hide ( ) ;
abort_progress_ - > hide ( ) ;
EnableCoversButtons ( ) ;
QMessageBox msg ;
msg . setWindowTitle ( tr ( " Export finished " ) ) ;
msg . setText ( message ) ;
msg . exec ( ) ;
}
}
2021-02-26 21:03:51 +01:00
bool AlbumCoverManager : : ItemHasCover ( const AlbumItem & item ) const {
return item . icon ( ) . cacheKey ( ) ! = icon_nocover_item_ . cacheKey ( ) ;
2018-02-27 18:06:05 +01:00
}
2021-02-26 21:03:51 +01:00
void AlbumCoverManager : : SaveEmbeddedCoverAsyncFinished ( quint64 id , const bool success ) {
while ( cover_save_tasks_ . contains ( id ) ) {
AlbumItem * album_item = cover_save_tasks_ . take ( id ) ;
if ( ! success ) continue ;
album_item - > setData ( Role_PathAutomatic , QUrl : : fromLocalFile ( Song : : kEmbeddedCover ) ) ;
Song song = ItemAsSong ( album_item ) ;
album_cover_choice_controller_ - > SaveArtAutomaticToSong ( & song , QUrl : : fromLocalFile ( Song : : kEmbeddedCover ) ) ;
quint64 cover_load_id = app_ - > album_cover_loader ( ) - > LoadImageAsync ( cover_loader_options_ , album_item - > data ( Role_PathAutomatic ) . toUrl ( ) , album_item - > data ( Role_PathManual ) . toUrl ( ) , album_item - > urls . first ( ) ) ;
cover_loading_tasks_ [ cover_load_id ] = album_item ;
}
2018-02-27 18:06:05 +01:00
}