2020-09-17 17:50:17 +02:00
/*
* Strawberry Music Player
2021-03-20 21:14:47 +01:00
* Copyright 2019 - 2021 , Jonas Kvinge < jonas @ jkvinge . net >
2020-09-17 17:50:17 +02: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/>.
*
*/
# include "config.h"
# include <QObject>
2023-03-18 19:41:36 +01:00
# include <QList>
2020-09-17 17:50:17 +02:00
# include <QByteArray>
2023-03-18 19:41:36 +01:00
# include <QByteArrayList>
2020-09-17 17:50:17 +02:00
# include <QString>
# include <QUrl>
# include <QImage>
# include <QImageReader>
# include <QNetworkRequest>
# include <QNetworkReply>
# include <QJsonObject>
# include <QJsonArray>
# include <QJsonValue>
2022-10-31 06:12:02 +01:00
# include <QTimer>
2020-09-17 17:50:17 +02:00
# include "core/logging.h"
2021-01-11 16:48:46 +01:00
# include "core/networkaccessmanager.h"
2020-09-17 17:50:17 +02:00
# include "core/song.h"
# include "core/application.h"
2022-12-28 03:12:00 +01:00
# include "utilities/timeconstants.h"
2023-03-18 20:03:07 +01:00
# include "utilities/imageutils.h"
# include "utilities/coverutils.h"
2020-09-17 17:50:17 +02:00
# include "qobuzservice.h"
# include "qobuzurlhandler.h"
# include "qobuzbaserequest.h"
# include "qobuzrequest.h"
2022-10-31 06:12:02 +01:00
constexpr int QobuzRequest : : kMaxConcurrentArtistsRequests = 3 ;
constexpr int QobuzRequest : : kMaxConcurrentAlbumsRequests = 3 ;
constexpr int QobuzRequest : : kMaxConcurrentSongsRequests = 3 ;
constexpr int QobuzRequest : : kMaxConcurrentArtistAlbumsRequests = 3 ;
constexpr int QobuzRequest : : kMaxConcurrentAlbumSongsRequests = 3 ;
constexpr int QobuzRequest : : kMaxConcurrentAlbumCoverRequests = 1 ;
constexpr int QobuzRequest : : kFlushRequestsDelay = 200 ;
2020-09-17 17:50:17 +02:00
2023-02-18 14:09:27 +01:00
QobuzRequest : : QobuzRequest ( QobuzService * service , QobuzUrlHandler * url_handler , Application * app , NetworkAccessManager * network , const QueryType query_type , QObject * parent )
2020-09-17 17:50:17 +02:00
: QobuzBaseRequest ( service , network , parent ) ,
service_ ( service ) ,
url_handler_ ( url_handler ) ,
app_ ( app ) ,
network_ ( network ) ,
2022-10-31 06:12:02 +01:00
timer_flush_requests_ ( new QTimer ( this ) ) ,
2023-02-18 14:09:27 +01:00
query_type_ ( query_type ) ,
2020-09-17 17:50:17 +02:00
query_id_ ( - 1 ) ,
finished_ ( false ) ,
2022-10-31 06:12:02 +01:00
artists_requests_total_ ( 0 ) ,
2020-09-17 17:50:17 +02:00
artists_requests_active_ ( 0 ) ,
2022-10-31 06:12:02 +01:00
artists_requests_received_ ( 0 ) ,
2020-09-17 17:50:17 +02:00
artists_total_ ( 0 ) ,
artists_received_ ( 0 ) ,
2022-10-31 06:12:02 +01:00
albums_requests_total_ ( 0 ) ,
2020-09-17 17:50:17 +02:00
albums_requests_active_ ( 0 ) ,
2022-10-31 06:12:02 +01:00
albums_requests_received_ ( 0 ) ,
albums_total_ ( 0 ) ,
albums_received_ ( 0 ) ,
songs_requests_total_ ( 0 ) ,
2020-09-17 17:50:17 +02:00
songs_requests_active_ ( 0 ) ,
2022-10-31 06:12:02 +01:00
songs_requests_received_ ( 0 ) ,
songs_total_ ( 0 ) ,
songs_received_ ( 0 ) ,
artist_albums_requests_total_ ( ) ,
2020-09-17 17:50:17 +02:00
artist_albums_requests_active_ ( 0 ) ,
2022-10-31 06:12:02 +01:00
artist_albums_requests_received_ ( 0 ) ,
artist_albums_total_ ( 0 ) ,
2020-09-17 17:50:17 +02:00
artist_albums_received_ ( 0 ) ,
album_songs_requests_active_ ( 0 ) ,
2022-10-31 06:12:02 +01:00
album_songs_requests_received_ ( 0 ) ,
album_songs_requests_total_ ( 0 ) ,
album_songs_total_ ( 0 ) ,
2020-09-17 17:50:17 +02:00
album_songs_received_ ( 0 ) ,
2022-10-31 06:12:02 +01:00
album_covers_requests_total_ ( 0 ) ,
album_covers_requests_active_ ( 0 ) ,
album_covers_requests_received_ ( 0 ) ,
no_results_ ( false ) {
timer_flush_requests_ - > setInterval ( kFlushRequestsDelay ) ;
timer_flush_requests_ - > setSingleShot ( false ) ;
QObject : : connect ( timer_flush_requests_ , & QTimer : : timeout , this , & QobuzRequest : : FlushRequests ) ;
}
2020-09-17 17:50:17 +02:00
QobuzRequest : : ~ QobuzRequest ( ) {
while ( ! replies_ . isEmpty ( ) ) {
QNetworkReply * reply = replies_ . takeFirst ( ) ;
2021-01-26 16:48:04 +01:00
QObject : : disconnect ( reply , nullptr , this , nullptr ) ;
2020-09-17 17:50:17 +02:00
if ( reply - > isRunning ( ) ) reply - > abort ( ) ;
reply - > deleteLater ( ) ;
}
while ( ! album_cover_replies_ . isEmpty ( ) ) {
QNetworkReply * reply = album_cover_replies_ . takeFirst ( ) ;
2021-01-26 16:48:04 +01:00
QObject : : disconnect ( reply , nullptr , this , nullptr ) ;
2020-09-17 17:50:17 +02:00
if ( reply - > isRunning ( ) ) reply - > abort ( ) ;
reply - > deleteLater ( ) ;
}
}
void QobuzRequest : : Process ( ) {
2023-02-18 14:09:27 +01:00
switch ( query_type_ ) {
case QueryType : : Artists :
2020-09-17 17:50:17 +02:00
GetArtists ( ) ;
break ;
2023-02-18 14:09:27 +01:00
case QueryType : : Albums :
2020-09-17 17:50:17 +02:00
GetAlbums ( ) ;
break ;
2023-02-18 14:09:27 +01:00
case QueryType : : Songs :
2020-09-17 17:50:17 +02:00
GetSongs ( ) ;
break ;
2023-02-18 14:09:27 +01:00
case QueryType : : SearchArtists :
2020-09-17 17:50:17 +02:00
ArtistsSearch ( ) ;
break ;
2023-02-18 14:09:27 +01:00
case QueryType : : SearchAlbums :
2020-09-17 17:50:17 +02:00
AlbumsSearch ( ) ;
break ;
2023-02-18 14:09:27 +01:00
case QueryType : : SearchSongs :
2020-09-17 17:50:17 +02:00
SongsSearch ( ) ;
break ;
default :
Error ( " Invalid query type. " ) ;
break ;
}
}
2022-10-31 06:12:02 +01:00
void QobuzRequest : : StartRequests ( ) {
if ( ! timer_flush_requests_ - > isActive ( ) ) {
timer_flush_requests_ - > start ( ) ;
}
}
void QobuzRequest : : FlushRequests ( ) {
if ( ! artists_requests_queue_ . isEmpty ( ) ) {
FlushArtistsRequests ( ) ;
return ;
}
if ( ! albums_requests_queue_ . isEmpty ( ) ) {
FlushAlbumsRequests ( ) ;
return ;
}
if ( ! artist_albums_requests_queue_ . isEmpty ( ) ) {
FlushArtistAlbumsRequests ( ) ;
return ;
}
if ( ! album_songs_requests_queue_ . isEmpty ( ) ) {
FlushAlbumSongsRequests ( ) ;
return ;
}
if ( ! songs_requests_queue_ . isEmpty ( ) ) {
FlushSongsRequests ( ) ;
return ;
}
if ( ! album_cover_requests_queue_ . isEmpty ( ) ) {
FlushAlbumCoverRequests ( ) ;
return ;
}
timer_flush_requests_ - > stop ( ) ;
}
2020-09-17 17:50:17 +02:00
void QobuzRequest : : Search ( const int query_id , const QString & search_text ) {
query_id_ = query_id ;
search_text_ = search_text ;
}
void QobuzRequest : : GetArtists ( ) {
2022-10-31 06:12:02 +01:00
emit UpdateStatus ( query_id_ , tr ( " Receiving artists... " ) ) ;
2020-09-17 17:50:17 +02:00
emit UpdateProgress ( query_id_ , 0 ) ;
AddArtistsRequest ( ) ;
}
void QobuzRequest : : AddArtistsRequest ( const int offset , const int limit ) {
Request request ;
request . limit = limit ;
request . offset = offset ;
artists_requests_queue_ . enqueue ( request ) ;
2022-10-31 06:12:02 +01:00
+ + artists_requests_total_ ;
StartRequests ( ) ;
2020-09-17 17:50:17 +02:00
}
void QobuzRequest : : FlushArtistsRequests ( ) {
while ( ! artists_requests_queue_ . isEmpty ( ) & & artists_requests_active_ < kMaxConcurrentArtistsRequests ) {
Request request = artists_requests_queue_ . dequeue ( ) ;
ParamList params ;
2023-02-18 14:09:27 +01:00
if ( query_type_ = = QueryType : : Artists ) {
2020-09-17 17:50:17 +02:00
params < < Param ( " type " , " artists " ) ;
params < < Param ( " user_auth_token " , user_auth_token ( ) ) ;
}
2023-02-18 14:09:27 +01:00
else if ( query_type_ = = QueryType : : SearchArtists ) params < < Param ( " query " , search_text_ ) ;
2020-09-17 17:50:17 +02:00
if ( request . limit > 0 ) params < < Param ( " limit " , QString : : number ( request . limit ) ) ;
if ( request . offset > 0 ) params < < Param ( " offset " , QString : : number ( request . offset ) ) ;
QNetworkReply * reply = nullptr ;
2023-02-18 14:09:27 +01:00
if ( query_type_ = = QueryType : : Artists ) {
2020-09-17 17:50:17 +02:00
reply = CreateRequest ( QString ( " favorite/getUserFavorites " ) , params ) ;
}
2023-02-18 14:09:27 +01:00
else if ( query_type_ = = QueryType : : SearchArtists ) {
2020-09-17 17:50:17 +02:00
reply = CreateRequest ( " artist/search " , params ) ;
}
if ( ! reply ) continue ;
replies_ < < reply ;
2021-03-21 00:37:17 +01:00
QObject : : connect ( reply , & QNetworkReply : : finished , this , [ this , reply , request ] ( ) { ArtistsReplyReceived ( reply , request . limit , request . offset ) ; } ) ;
2020-09-17 17:50:17 +02:00
2022-10-31 06:12:02 +01:00
+ + artists_requests_active_ ;
2020-09-17 17:50:17 +02:00
}
}
void QobuzRequest : : GetAlbums ( ) {
2022-10-31 06:12:02 +01:00
emit UpdateStatus ( query_id_ , tr ( " Receiving albums... " ) ) ;
2020-09-17 17:50:17 +02:00
emit UpdateProgress ( query_id_ , 0 ) ;
AddAlbumsRequest ( ) ;
}
void QobuzRequest : : AddAlbumsRequest ( const int offset , const int limit ) {
Request request ;
request . limit = limit ;
request . offset = offset ;
albums_requests_queue_ . enqueue ( request ) ;
2022-10-31 06:12:02 +01:00
+ + albums_requests_total_ ;
StartRequests ( ) ;
2020-09-17 17:50:17 +02:00
}
void QobuzRequest : : FlushAlbumsRequests ( ) {
while ( ! albums_requests_queue_ . isEmpty ( ) & & albums_requests_active_ < kMaxConcurrentAlbumsRequests ) {
Request request = albums_requests_queue_ . dequeue ( ) ;
ParamList params ;
2023-02-18 14:09:27 +01:00
if ( query_type_ = = QueryType : : Albums ) {
2020-09-17 17:50:17 +02:00
params < < Param ( " type " , " albums " ) ;
params < < Param ( " user_auth_token " , user_auth_token ( ) ) ;
}
2023-02-18 14:09:27 +01:00
else if ( query_type_ = = QueryType : : SearchAlbums ) params < < Param ( " query " , search_text_ ) ;
2020-09-17 17:50:17 +02:00
if ( request . limit > 0 ) params < < Param ( " limit " , QString : : number ( request . limit ) ) ;
if ( request . offset > 0 ) params < < Param ( " offset " , QString : : number ( request . offset ) ) ;
QNetworkReply * reply = nullptr ;
2023-02-18 14:09:27 +01:00
if ( query_type_ = = QueryType : : Albums ) {
2020-09-17 17:50:17 +02:00
reply = CreateRequest ( QString ( " favorite/getUserFavorites " ) , params ) ;
}
2023-02-18 14:09:27 +01:00
else if ( query_type_ = = QueryType : : SearchAlbums ) {
2020-09-17 17:50:17 +02:00
reply = CreateRequest ( " album/search " , params ) ;
}
if ( ! reply ) continue ;
replies_ < < reply ;
2021-03-21 00:37:17 +01:00
QObject : : connect ( reply , & QNetworkReply : : finished , this , [ this , reply , request ] ( ) { AlbumsReplyReceived ( reply , request . limit , request . offset ) ; } ) ;
2020-09-17 17:50:17 +02:00
2022-10-31 06:12:02 +01:00
+ + albums_requests_active_ ;
2020-09-17 17:50:17 +02:00
}
}
void QobuzRequest : : GetSongs ( ) {
2022-10-31 06:12:02 +01:00
emit UpdateStatus ( query_id_ , tr ( " Receiving songs... " ) ) ;
2020-09-17 17:50:17 +02:00
emit UpdateProgress ( query_id_ , 0 ) ;
AddSongsRequest ( ) ;
}
void QobuzRequest : : AddSongsRequest ( const int offset , const int limit ) {
Request request ;
request . limit = limit ;
request . offset = offset ;
songs_requests_queue_ . enqueue ( request ) ;
2022-10-31 06:12:02 +01:00
+ + songs_requests_total_ ;
StartRequests ( ) ;
2020-09-17 17:50:17 +02:00
}
void QobuzRequest : : FlushSongsRequests ( ) {
while ( ! songs_requests_queue_ . isEmpty ( ) & & songs_requests_active_ < kMaxConcurrentSongsRequests ) {
Request request = songs_requests_queue_ . dequeue ( ) ;
ParamList params ;
2023-02-18 14:09:27 +01:00
if ( query_type_ = = QueryType : : Songs ) {
2020-09-17 17:50:17 +02:00
params < < Param ( " type " , " tracks " ) ;
params < < Param ( " user_auth_token " , user_auth_token ( ) ) ;
}
2023-02-18 14:09:27 +01:00
else if ( query_type_ = = QueryType : : SearchSongs ) params < < Param ( " query " , search_text_ ) ;
2020-09-17 17:50:17 +02:00
if ( request . limit > 0 ) params < < Param ( " limit " , QString : : number ( request . limit ) ) ;
if ( request . offset > 0 ) params < < Param ( " offset " , QString : : number ( request . offset ) ) ;
QNetworkReply * reply = nullptr ;
2023-02-18 14:09:27 +01:00
if ( query_type_ = = QueryType : : Songs ) {
2020-09-17 17:50:17 +02:00
reply = CreateRequest ( QString ( " favorite/getUserFavorites " ) , params ) ;
}
2023-02-18 14:09:27 +01:00
else if ( query_type_ = = QueryType : : SearchSongs ) {
2020-09-17 17:50:17 +02:00
reply = CreateRequest ( " track/search " , params ) ;
}
if ( ! reply ) continue ;
replies_ < < reply ;
2021-03-21 00:37:17 +01:00
QObject : : connect ( reply , & QNetworkReply : : finished , this , [ this , reply , request ] ( ) { SongsReplyReceived ( reply , request . limit , request . offset ) ; } ) ;
2020-09-17 17:50:17 +02:00
2022-10-31 06:12:02 +01:00
+ + songs_requests_active_ ;
2020-09-17 17:50:17 +02:00
}
}
void QobuzRequest : : ArtistsSearch ( ) {
emit UpdateStatus ( query_id_ , tr ( " Searching... " ) ) ;
emit UpdateProgress ( query_id_ , 0 ) ;
AddArtistsSearchRequest ( ) ;
}
void QobuzRequest : : AddArtistsSearchRequest ( const int offset ) {
AddArtistsRequest ( offset , service_ - > artistssearchlimit ( ) ) ;
}
void QobuzRequest : : AlbumsSearch ( ) {
emit UpdateStatus ( query_id_ , tr ( " Searching... " ) ) ;
emit UpdateProgress ( query_id_ , 0 ) ;
AddAlbumsSearchRequest ( ) ;
}
void QobuzRequest : : AddAlbumsSearchRequest ( const int offset ) {
AddAlbumsRequest ( offset , service_ - > albumssearchlimit ( ) ) ;
}
void QobuzRequest : : SongsSearch ( ) {
emit UpdateStatus ( query_id_ , tr ( " Searching... " ) ) ;
emit UpdateProgress ( query_id_ , 0 ) ;
AddSongsSearchRequest ( ) ;
}
void QobuzRequest : : AddSongsSearchRequest ( const int offset ) {
AddSongsRequest ( offset , service_ - > songssearchlimit ( ) ) ;
}
void QobuzRequest : : ArtistsReplyReceived ( QNetworkReply * reply , const int limit_requested , const int offset_requested ) {
if ( ! replies_ . contains ( reply ) ) return ;
replies_ . removeAll ( reply ) ;
2021-01-26 16:48:04 +01:00
QObject : : disconnect ( reply , nullptr , this , nullptr ) ;
2020-09-17 17:50:17 +02:00
reply - > deleteLater ( ) ;
QByteArray data = GetReplyData ( reply ) ;
- - artists_requests_active_ ;
2022-10-31 06:12:02 +01:00
+ + artists_requests_received_ ;
2020-09-17 17:50:17 +02:00
if ( finished_ ) return ;
if ( data . isEmpty ( ) ) {
ArtistsFinishCheck ( ) ;
return ;
}
QJsonObject json_obj = ExtractJsonObj ( data ) ;
if ( json_obj . isEmpty ( ) ) {
ArtistsFinishCheck ( ) ;
return ;
}
if ( ! json_obj . contains ( " artists " ) ) {
ArtistsFinishCheck ( ) ;
Error ( " Json object is missing artists. " , json_obj ) ;
return ;
}
QJsonValue value_artists = json_obj [ " artists " ] ;
if ( ! value_artists . isObject ( ) ) {
Error ( " Json artists is not an object. " , json_obj ) ;
ArtistsFinishCheck ( ) ;
return ;
}
QJsonObject obj_artists = value_artists . toObject ( ) ;
if ( ! obj_artists . contains ( " limit " ) | |
! obj_artists . contains ( " offset " ) | |
! obj_artists . contains ( " total " ) | |
! obj_artists . contains ( " items " ) ) {
ArtistsFinishCheck ( ) ;
Error ( " Json artists object is missing values. " , json_obj ) ;
return ;
}
//int limit = obj_artists["limit"].toInt();
int offset = obj_artists [ " offset " ] . toInt ( ) ;
int artists_total = obj_artists [ " total " ] . toInt ( ) ;
if ( offset_requested = = 0 ) {
artists_total_ = artists_total ;
}
else if ( artists_total ! = artists_total_ ) {
Error ( QString ( " total returned does not match previous total! %1 != %2 " ) . arg ( artists_total ) . arg ( artists_total_ ) ) ;
ArtistsFinishCheck ( ) ;
return ;
}
if ( offset ! = offset_requested ) {
Error ( QString ( " Offset returned does not match offset requested! %1 != %2 " ) . arg ( offset ) . arg ( offset_requested ) ) ;
ArtistsFinishCheck ( ) ;
return ;
}
if ( offset_requested = = 0 ) {
2022-10-31 06:12:02 +01:00
emit UpdateProgress ( query_id_ , GetProgress ( artists_received_ , artists_total_ ) ) ;
2020-09-17 17:50:17 +02:00
}
QJsonValue value_items = ExtractItems ( obj_artists ) ;
if ( ! value_items . isArray ( ) ) {
ArtistsFinishCheck ( ) ;
return ;
}
QJsonArray array_items = value_items . toArray ( ) ;
if ( array_items . isEmpty ( ) ) { // Empty array means no results
if ( offset_requested = = 0 ) no_results_ = true ;
ArtistsFinishCheck ( ) ;
return ;
}
int artists_received = 0 ;
2021-03-26 22:10:43 +01:00
for ( const QJsonValueRef value_item : array_items ) {
2020-09-17 17:50:17 +02:00
+ + artists_received ;
if ( ! value_item . isObject ( ) ) {
2021-03-26 22:10:43 +01:00
Error ( " Invalid Json reply, item not a object. " ) ;
2020-09-17 17:50:17 +02:00
continue ;
}
QJsonObject obj_item = value_item . toObject ( ) ;
if ( obj_item . contains ( " item " ) ) {
QJsonValue json_item = obj_item [ " item " ] ;
if ( ! json_item . isObject ( ) ) {
Error ( " Invalid Json reply, item not a object. " , json_item ) ;
continue ;
}
obj_item = json_item . toObject ( ) ;
}
if ( ! obj_item . contains ( " id " ) | | ! obj_item . contains ( " name " ) ) {
Error ( " Invalid Json reply, item missing id or album. " , obj_item ) ;
continue ;
}
2022-10-31 06:12:02 +01:00
Artist artist ;
2020-09-17 17:50:17 +02:00
if ( obj_item [ " id " ] . isString ( ) ) {
2022-10-31 06:12:02 +01:00
artist . artist_id = obj_item [ " id " ] . toString ( ) ;
2020-09-17 17:50:17 +02:00
}
else {
2022-10-31 06:12:02 +01:00
artist . artist_id = QString : : number ( obj_item [ " id " ] . toInt ( ) ) ;
2020-09-17 17:50:17 +02:00
}
2022-10-31 06:12:02 +01:00
artist . artist = obj_item [ " name " ] . toString ( ) ;
if ( artist_albums_requests_pending_ . contains ( artist . artist_id ) ) continue ;
ArtistAlbumsRequest request ;
request . artist = artist ;
artist_albums_requests_pending_ . insert ( artist . artist_id , request ) ;
2020-09-17 17:50:17 +02:00
}
artists_received_ + = artists_received ;
2022-10-31 06:12:02 +01:00
if ( offset_requested ! = 0 ) emit UpdateProgress ( query_id_ , GetProgress ( artists_received_ , artists_total_ ) ) ;
2020-09-17 17:50:17 +02:00
ArtistsFinishCheck ( limit_requested , offset , artists_received ) ;
}
void QobuzRequest : : ArtistsFinishCheck ( const int limit , const int offset , const int artists_received ) {
if ( finished_ ) return ;
if ( ( limit = = 0 | | limit > artists_received ) & & artists_received_ < artists_total_ ) {
int offset_next = offset + artists_received ;
if ( offset_next > 0 & & offset_next < artists_total_ ) {
2023-02-18 14:09:27 +01:00
if ( query_type_ = = QueryType : : Artists ) AddArtistsRequest ( offset_next ) ;
else if ( query_type_ = = QueryType : : SearchArtists ) AddArtistsSearchRequest ( offset_next ) ;
2020-09-17 17:50:17 +02:00
}
}
if ( artists_requests_queue_ . isEmpty ( ) & & artists_requests_active_ < = 0 ) { // Artist query is finished, get all albums for all artists.
// Get artist albums
2022-10-31 06:12:02 +01:00
QList < ArtistAlbumsRequest > requests = artist_albums_requests_pending_ . values ( ) ;
for ( const ArtistAlbumsRequest & request : requests ) {
AddArtistAlbumsRequest ( request . artist ) ;
2020-09-17 17:50:17 +02:00
}
artist_albums_requests_pending_ . clear ( ) ;
2022-10-31 06:12:02 +01:00
if ( artist_albums_requests_total_ > 0 ) {
if ( artist_albums_requests_total_ = = 1 ) emit UpdateStatus ( query_id_ , tr ( " Receiving albums for %1 artist... " ) . arg ( artist_albums_requests_total_ ) ) ;
else emit UpdateStatus ( query_id_ , tr ( " Receiving albums for %1 artists... " ) . arg ( artist_albums_requests_total_ ) ) ;
2020-09-17 17:50:17 +02:00
emit UpdateProgress ( query_id_ , 0 ) ;
}
}
FinishCheck ( ) ;
}
void QobuzRequest : : AlbumsReplyReceived ( QNetworkReply * reply , const int limit_requested , const int offset_requested ) {
2022-10-31 06:12:02 +01:00
2020-09-17 17:50:17 +02:00
- - albums_requests_active_ ;
2022-10-31 06:12:02 +01:00
+ + albums_requests_received_ ;
AlbumsReceived ( reply , Artist ( ) , limit_requested , offset_requested ) ;
2020-09-17 17:50:17 +02:00
}
2022-10-31 06:12:02 +01:00
void QobuzRequest : : AddArtistAlbumsRequest ( const Artist & artist , const int offset ) {
2020-09-17 17:50:17 +02:00
2022-10-31 06:12:02 +01:00
ArtistAlbumsRequest request ;
request . artist = artist ;
2020-09-17 17:50:17 +02:00
request . offset = offset ;
artist_albums_requests_queue_ . enqueue ( request ) ;
2022-10-31 06:12:02 +01:00
+ + artist_albums_requests_total_ ;
StartRequests ( ) ;
2020-09-17 17:50:17 +02:00
}
void QobuzRequest : : FlushArtistAlbumsRequests ( ) {
while ( ! artist_albums_requests_queue_ . isEmpty ( ) & & artist_albums_requests_active_ < kMaxConcurrentArtistAlbumsRequests ) {
2022-10-31 06:12:02 +01:00
const ArtistAlbumsRequest request = artist_albums_requests_queue_ . dequeue ( ) ;
2020-09-17 17:50:17 +02:00
2022-10-31 06:12:02 +01:00
ParamList params = ParamList ( ) < < Param ( " artist_id " , request . artist . artist_id )
2020-09-17 17:50:17 +02:00
< < Param ( " extra " , " albums " ) ;
if ( request . offset > 0 ) params < < Param ( " offset " , QString : : number ( request . offset ) ) ;
QNetworkReply * reply = CreateRequest ( QString ( " artist/get " ) , params ) ;
2022-10-31 06:12:02 +01:00
QObject : : connect ( reply , & QNetworkReply : : finished , this , [ this , reply , request ] ( ) { ArtistAlbumsReplyReceived ( reply , request . artist , request . offset ) ; } ) ;
2020-09-17 17:50:17 +02:00
replies_ < < reply ;
2022-10-31 06:12:02 +01:00
+ + artist_albums_requests_active_ ;
2020-09-17 17:50:17 +02:00
}
}
2022-10-31 06:12:02 +01:00
void QobuzRequest : : ArtistAlbumsReplyReceived ( QNetworkReply * reply , const Artist & artist , const int offset_requested ) {
2020-09-17 17:50:17 +02:00
- - artist_albums_requests_active_ ;
2022-10-31 06:12:02 +01:00
+ + artist_albums_requests_received_ ;
emit UpdateProgress ( query_id_ , GetProgress ( artist_albums_requests_received_ , artist_albums_requests_total_ ) ) ;
AlbumsReceived ( reply , artist , 0 , offset_requested ) ;
2020-09-17 17:50:17 +02:00
}
2022-10-31 06:12:02 +01:00
void QobuzRequest : : AlbumsReceived ( QNetworkReply * reply , const Artist & artist_requested , const int limit_requested , const int offset_requested ) {
2020-09-17 17:50:17 +02:00
if ( ! replies_ . contains ( reply ) ) return ;
replies_ . removeAll ( reply ) ;
2021-01-26 16:48:04 +01:00
QObject : : disconnect ( reply , nullptr , this , nullptr ) ;
2020-09-17 17:50:17 +02:00
reply - > deleteLater ( ) ;
QByteArray data = GetReplyData ( reply ) ;
if ( finished_ ) return ;
if ( data . isEmpty ( ) ) {
2022-10-31 06:12:02 +01:00
AlbumsFinishCheck ( artist_requested ) ;
2020-09-17 17:50:17 +02:00
return ;
}
QJsonObject json_obj = ExtractJsonObj ( data ) ;
if ( json_obj . isEmpty ( ) ) {
2022-10-31 06:12:02 +01:00
AlbumsFinishCheck ( artist_requested ) ;
2020-09-17 17:50:17 +02:00
return ;
}
2022-10-31 06:12:02 +01:00
Artist artist = artist_requested ;
if ( json_obj . contains ( " id " ) & & json_obj . contains ( " name " ) ) {
2020-09-17 17:50:17 +02:00
if ( json_obj [ " id " ] . isString ( ) ) {
2022-10-31 06:12:02 +01:00
artist . artist_id = json_obj [ " id " ] . toString ( ) ;
2020-09-17 17:50:17 +02:00
}
else {
2022-10-31 06:12:02 +01:00
artist . artist_id = QString : : number ( json_obj [ " id " ] . toInt ( ) ) ;
2020-09-17 17:50:17 +02:00
}
2022-10-31 06:12:02 +01:00
artist . artist = json_obj [ " name " ] . toString ( ) ;
2020-09-17 17:50:17 +02:00
}
2022-10-31 06:12:02 +01:00
if ( artist . artist_id ! = artist_requested . artist_id ) {
AlbumsFinishCheck ( artist_requested ) ;
Error ( " Artist ID returned does not match artist ID requested. " , json_obj ) ;
2020-09-17 17:50:17 +02:00
return ;
}
if ( ! json_obj . contains ( " albums " ) ) {
2022-10-31 06:12:02 +01:00
AlbumsFinishCheck ( artist_requested ) ;
2020-09-17 17:50:17 +02:00
Error ( " Json object is missing albums. " , json_obj ) ;
return ;
}
QJsonValue value_albums = json_obj [ " albums " ] ;
if ( ! value_albums . isObject ( ) ) {
Error ( " Json albums is not an object. " , json_obj ) ;
2022-10-31 06:12:02 +01:00
AlbumsFinishCheck ( artist_requested ) ;
2020-09-17 17:50:17 +02:00
return ;
}
QJsonObject obj_albums = value_albums . toObject ( ) ;
if ( ! obj_albums . contains ( " limit " ) | |
! obj_albums . contains ( " offset " ) | |
! obj_albums . contains ( " total " ) | |
! obj_albums . contains ( " items " ) ) {
2022-10-31 06:12:02 +01:00
AlbumsFinishCheck ( artist_requested ) ;
2020-09-17 17:50:17 +02:00
Error ( " Json albums object is missing values. " , json_obj ) ;
return ;
}
2022-03-21 21:54:27 +01:00
//int limit = obj_albums["limit"].toInt();
int offset = obj_albums [ " offset " ] . toInt ( ) ;
int albums_total = obj_albums [ " total " ] . toInt ( ) ;
2020-09-17 17:50:17 +02:00
if ( offset ! = offset_requested ) {
Error ( QString ( " Offset returned does not match offset requested! %1 != %2 " ) . arg ( offset ) . arg ( offset_requested ) ) ;
2022-10-31 06:12:02 +01:00
AlbumsFinishCheck ( artist_requested ) ;
2020-09-17 17:50:17 +02:00
return ;
}
QJsonValue value_items = ExtractItems ( obj_albums ) ;
if ( ! value_items . isArray ( ) ) {
2022-10-31 06:12:02 +01:00
AlbumsFinishCheck ( artist_requested ) ;
2020-09-17 17:50:17 +02:00
return ;
}
QJsonArray array_items = value_items . toArray ( ) ;
if ( array_items . isEmpty ( ) ) {
2023-02-18 14:09:27 +01:00
if ( ( query_type_ = = QueryType : : Albums | | query_type_ = = QueryType : : SearchAlbums ) & & offset_requested = = 0 ) {
2020-09-17 17:50:17 +02:00
no_results_ = true ;
}
2022-10-31 06:12:02 +01:00
AlbumsFinishCheck ( artist_requested ) ;
2020-09-17 17:50:17 +02:00
return ;
}
int albums_received = 0 ;
2022-10-31 06:12:02 +01:00
for ( const QJsonValueRef value_item : array_items ) {
2020-09-17 17:50:17 +02:00
+ + albums_received ;
2022-10-31 06:12:02 +01:00
if ( ! value_item . isObject ( ) ) {
Error ( " Invalid Json reply, item in array is not a object. " ) ;
2020-09-17 17:50:17 +02:00
continue ;
}
2022-10-31 06:12:02 +01:00
QJsonObject obj_item = value_item . toObject ( ) ;
2020-09-17 17:50:17 +02:00
if ( ! obj_item . contains ( " artist " ) | | ! obj_item . contains ( " title " ) | | ! obj_item . contains ( " id " ) ) {
Error ( " Invalid Json reply, item missing artist, title or id. " , obj_item ) ;
continue ;
}
2022-10-31 06:12:02 +01:00
Album album ;
2020-09-17 17:50:17 +02:00
if ( obj_item [ " id " ] . isString ( ) ) {
2022-10-31 06:12:02 +01:00
album . album_id = obj_item [ " id " ] . toString ( ) ;
2020-09-17 17:50:17 +02:00
}
else {
2022-10-31 06:12:02 +01:00
album . album_id = QString : : number ( obj_item [ " id " ] . toInt ( ) ) ;
2021-07-11 07:40:57 +02:00
}
2022-10-31 06:12:02 +01:00
album . album = obj_item [ " title " ] . toString ( ) ;
2020-09-17 17:50:17 +02:00
2022-10-31 06:12:02 +01:00
if ( album_songs_requests_pending_ . contains ( album . album_id ) ) continue ;
2020-09-17 17:50:17 +02:00
QJsonValue value_artist = obj_item [ " artist " ] ;
if ( ! value_artist . isObject ( ) ) {
Error ( " Invalid Json reply, item artist is not a object. " , value_artist ) ;
continue ;
}
QJsonObject obj_artist = value_artist . toObject ( ) ;
if ( ! obj_artist . contains ( " id " ) | | ! obj_artist . contains ( " name " ) ) {
Error ( " Invalid Json reply, item artist missing id or name. " , obj_artist ) ;
continue ;
}
2022-10-31 06:12:02 +01:00
Artist album_artist ;
2020-09-17 17:50:17 +02:00
if ( obj_artist [ " id " ] . isString ( ) ) {
2022-10-31 06:12:02 +01:00
album_artist . artist_id = obj_artist [ " id " ] . toString ( ) ;
2020-09-17 17:50:17 +02:00
}
else {
2022-10-31 06:12:02 +01:00
album_artist . artist_id = QString : : number ( obj_artist [ " id " ] . toInt ( ) ) ;
2020-09-17 17:50:17 +02:00
}
2022-10-31 06:12:02 +01:00
album_artist . artist = obj_artist [ " name " ] . toString ( ) ;
2020-09-17 17:50:17 +02:00
2022-10-31 06:12:02 +01:00
if ( ! artist_requested . artist_id . isEmpty ( ) & & album_artist . artist_id ! = artist_requested . artist_id ) {
qLog ( Debug ) < < " Skipping artist " < < album_artist . artist < < album_artist . artist_id < < " does not match album artist " < < artist_requested . artist_id < < artist_requested . artist ;
2020-09-17 17:50:17 +02:00
continue ;
}
2022-10-31 06:12:02 +01:00
AlbumSongsRequest request ;
request . artist = album_artist ;
2020-09-17 17:50:17 +02:00
request . album = album ;
2022-10-31 06:12:02 +01:00
album_songs_requests_pending_ . insert ( album . album_id , request ) ;
}
2020-09-17 17:50:17 +02:00
2023-02-18 14:09:27 +01:00
if ( query_type_ = = QueryType : : Albums | | query_type_ = = QueryType : : SearchAlbums ) {
2022-10-31 06:12:02 +01:00
albums_received_ + = albums_received ;
emit UpdateProgress ( query_id_ , GetProgress ( albums_received_ , albums_total_ ) ) ;
2020-09-17 17:50:17 +02:00
}
2022-10-31 06:12:02 +01:00
AlbumsFinishCheck ( artist_requested , limit_requested , offset , albums_total , albums_received ) ;
2020-09-17 17:50:17 +02:00
}
2022-10-31 06:12:02 +01:00
void QobuzRequest : : AlbumsFinishCheck ( const Artist & artist , const int limit , const int offset , const int albums_total , const int albums_received ) {
2020-09-17 17:50:17 +02:00
if ( finished_ ) return ;
if ( limit = = 0 | | limit > albums_received ) {
int offset_next = offset + albums_received ;
if ( offset_next > 0 & & offset_next < albums_total ) {
2023-02-18 14:09:27 +01:00
switch ( query_type_ ) {
case QueryType : : Albums :
2020-09-17 17:50:17 +02:00
AddAlbumsRequest ( offset_next ) ;
break ;
2023-02-18 14:09:27 +01:00
case QueryType : : SearchAlbums :
2020-09-17 17:50:17 +02:00
AddAlbumsSearchRequest ( offset_next ) ;
break ;
2023-02-18 14:09:27 +01:00
case QueryType : : Artists :
case QueryType : : SearchArtists :
2022-10-31 06:12:02 +01:00
AddArtistAlbumsRequest ( artist , offset_next ) ;
2020-09-17 17:50:17 +02:00
break ;
default :
break ;
}
}
}
if (
2022-10-31 06:12:02 +01:00
artists_requests_queue_ . isEmpty ( ) & &
artists_requests_active_ < = 0 & &
2020-09-17 17:50:17 +02:00
albums_requests_queue_ . isEmpty ( ) & &
albums_requests_active_ < = 0 & &
artist_albums_requests_queue_ . isEmpty ( ) & &
artist_albums_requests_active_ < = 0
) { // Artist albums query is finished, get all songs for all albums.
// Get songs for all the albums.
2022-10-31 06:12:02 +01:00
for ( QHash < QString , AlbumSongsRequest > : : iterator it = album_songs_requests_pending_ . begin ( ) ; it ! = album_songs_requests_pending_ . end ( ) ; + + it ) {
const AlbumSongsRequest & request = it . value ( ) ;
AddAlbumSongsRequest ( request . artist , request . album ) ;
2020-09-17 17:50:17 +02:00
}
album_songs_requests_pending_ . clear ( ) ;
2022-10-31 06:12:02 +01:00
if ( album_songs_requests_total_ > 0 ) {
if ( album_songs_requests_total_ = = 1 ) emit UpdateStatus ( query_id_ , tr ( " Receiving songs for %1 album... " ) . arg ( album_songs_requests_total_ ) ) ;
else emit UpdateStatus ( query_id_ , tr ( " Receiving songs for %1 albums... " ) . arg ( album_songs_requests_total_ ) ) ;
2020-09-17 17:50:17 +02:00
emit UpdateProgress ( query_id_ , 0 ) ;
}
}
2022-10-31 06:12:02 +01:00
GetAlbumCoversCheck ( ) ;
2020-09-17 17:50:17 +02:00
FinishCheck ( ) ;
}
void QobuzRequest : : SongsReplyReceived ( QNetworkReply * reply , const int limit_requested , const int offset_requested ) {
- - songs_requests_active_ ;
2022-10-31 06:12:02 +01:00
+ + songs_requests_received_ ;
SongsReceived ( reply , Artist ( ) , Album ( ) , limit_requested , offset_requested ) ;
2020-09-17 17:50:17 +02:00
}
2022-10-31 06:12:02 +01:00
void QobuzRequest : : AddAlbumSongsRequest ( const Artist & artist , const Album & album , const int offset ) {
2020-09-17 17:50:17 +02:00
2022-10-31 06:12:02 +01:00
AlbumSongsRequest request ;
request . artist = artist ;
2020-09-17 17:50:17 +02:00
request . album = album ;
request . offset = offset ;
album_songs_requests_queue_ . enqueue ( request ) ;
2022-10-31 06:12:02 +01:00
+ + album_songs_requests_total_ ;
StartRequests ( ) ;
2020-09-17 17:50:17 +02:00
}
void QobuzRequest : : FlushAlbumSongsRequests ( ) {
while ( ! album_songs_requests_queue_ . isEmpty ( ) & & album_songs_requests_active_ < kMaxConcurrentAlbumSongsRequests ) {
2022-10-31 06:12:02 +01:00
AlbumSongsRequest request = album_songs_requests_queue_ . dequeue ( ) ;
ParamList params = ParamList ( ) < < Param ( " album_id " , request . album . album_id ) ;
2020-09-17 17:50:17 +02:00
if ( request . offset > 0 ) params < < Param ( " offset " , QString : : number ( request . offset ) ) ;
QNetworkReply * reply = CreateRequest ( QString ( " album/get " ) , params ) ;
replies_ < < reply ;
2022-10-31 06:12:02 +01:00
QObject : : connect ( reply , & QNetworkReply : : finished , this , [ this , reply , request ] ( ) { AlbumSongsReplyReceived ( reply , request . artist , request . album , request . offset ) ; } ) ;
+ + album_songs_requests_active_ ;
2020-09-17 17:50:17 +02:00
}
}
2022-10-31 06:12:02 +01:00
void QobuzRequest : : AlbumSongsReplyReceived ( QNetworkReply * reply , const Artist & artist , const Album & album , const int offset_requested ) {
2020-09-17 17:50:17 +02:00
- - album_songs_requests_active_ ;
2022-10-31 06:12:02 +01:00
+ + album_songs_requests_received_ ;
2020-09-17 17:50:17 +02:00
if ( offset_requested = = 0 ) {
2022-10-31 06:12:02 +01:00
emit UpdateProgress ( query_id_ , GetProgress ( album_songs_requests_received_ , album_songs_requests_total_ ) ) ;
2020-09-17 17:50:17 +02:00
}
2022-10-31 06:12:02 +01:00
SongsReceived ( reply , artist , album , 0 , offset_requested ) ;
2020-09-17 17:50:17 +02:00
}
2022-10-31 06:12:02 +01:00
void QobuzRequest : : SongsReceived ( QNetworkReply * reply , const Artist & artist_requested , const Album & album_requested , const int limit_requested , const int offset_requested ) {
2020-09-17 17:50:17 +02:00
if ( ! replies_ . contains ( reply ) ) return ;
replies_ . removeAll ( reply ) ;
2022-10-31 06:12:02 +01:00
QObject : : disconnect ( reply , nullptr , this , nullptr ) ;
2020-09-17 17:50:17 +02:00
reply - > deleteLater ( ) ;
QByteArray data = GetReplyData ( reply ) ;
if ( finished_ ) return ;
if ( data . isEmpty ( ) ) {
2022-10-31 06:12:02 +01:00
SongsFinishCheck ( artist_requested , album_requested , limit_requested , offset_requested ) ;
2020-09-17 17:50:17 +02:00
return ;
}
QJsonObject json_obj = ExtractJsonObj ( data ) ;
if ( json_obj . isEmpty ( ) ) {
2022-10-31 06:12:02 +01:00
SongsFinishCheck ( artist_requested , album_requested , limit_requested , offset_requested ) ;
2020-09-17 17:50:17 +02:00
return ;
}
if ( ! json_obj . contains ( " tracks " ) ) {
Error ( " Json object is missing tracks. " , json_obj ) ;
2022-10-31 06:12:02 +01:00
SongsFinishCheck ( artist_requested , album_requested , limit_requested , offset_requested ) ;
2020-09-17 17:50:17 +02:00
return ;
}
2022-10-31 06:12:02 +01:00
Artist album_artist = artist_requested ;
Album album = album_requested ;
2020-09-17 17:50:17 +02:00
2022-10-31 06:12:02 +01:00
if ( json_obj . contains ( " id " ) & & json_obj . contains ( " title " ) ) {
2020-09-17 17:50:17 +02:00
if ( json_obj [ " id " ] . isString ( ) ) {
2022-10-31 06:12:02 +01:00
album . album_id = json_obj [ " id " ] . toString ( ) ;
2020-09-17 17:50:17 +02:00
}
else {
2022-10-31 06:12:02 +01:00
album . album_id = QString : : number ( json_obj [ " id " ] . toInt ( ) ) ;
2021-07-11 07:40:57 +02:00
}
2022-10-31 06:12:02 +01:00
album . album = json_obj [ " title " ] . toString ( ) ;
2020-09-17 17:50:17 +02:00
}
if ( json_obj . contains ( " artist " ) ) {
QJsonValue value_artist = json_obj [ " artist " ] ;
if ( ! value_artist . isObject ( ) ) {
Error ( " Invalid Json reply, album artist is not a object. " , value_artist ) ;
2022-10-31 06:12:02 +01:00
SongsFinishCheck ( artist_requested , album_requested , limit_requested , offset_requested ) ;
2020-09-17 17:50:17 +02:00
return ;
}
QJsonObject obj_artist = value_artist . toObject ( ) ;
if ( ! obj_artist . contains ( " id " ) | | ! obj_artist . contains ( " name " ) ) {
Error ( " Invalid Json reply, album artist is missing id or name. " , obj_artist ) ;
2022-10-31 06:12:02 +01:00
SongsFinishCheck ( artist_requested , album_requested , limit_requested , offset_requested ) ;
2020-09-17 17:50:17 +02:00
return ;
}
if ( obj_artist [ " id " ] . isString ( ) ) {
2022-10-31 06:12:02 +01:00
album_artist . artist_id = obj_artist [ " id " ] . toString ( ) ;
2020-09-17 17:50:17 +02:00
}
else {
2022-10-31 06:12:02 +01:00
album_artist . artist_id = QString : : number ( obj_artist [ " id " ] . toInt ( ) ) ;
2020-09-17 17:50:17 +02:00
}
2022-10-31 06:12:02 +01:00
album_artist . artist = obj_artist [ " name " ] . toString ( ) ;
2020-09-17 17:50:17 +02:00
}
if ( json_obj . contains ( " image " ) ) {
QJsonValue value_image = json_obj [ " image " ] ;
if ( ! value_image . isObject ( ) ) {
Error ( " Invalid Json reply, album image is not a object. " , value_image ) ;
2022-10-31 06:12:02 +01:00
SongsFinishCheck ( artist_requested , album_requested , limit_requested , offset_requested ) ;
2020-09-17 17:50:17 +02:00
return ;
}
QJsonObject obj_image = value_image . toObject ( ) ;
if ( ! obj_image . contains ( " large " ) ) {
Error ( " Invalid Json reply, album image is missing large. " , obj_image ) ;
2022-10-31 06:12:02 +01:00
SongsFinishCheck ( artist_requested , album_requested , limit_requested , offset_requested ) ;
2020-09-17 17:50:17 +02:00
return ;
}
QString album_image = obj_image [ " large " ] . toString ( ) ;
if ( ! album_image . isEmpty ( ) ) {
2022-10-31 06:12:02 +01:00
album . cover_url = QUrl ( album_image ) ;
2020-09-17 17:50:17 +02:00
}
}
QJsonValue value_tracks = json_obj [ " tracks " ] ;
if ( ! value_tracks . isObject ( ) ) {
Error ( " Json tracks is not an object. " , json_obj ) ;
2022-10-31 06:12:02 +01:00
SongsFinishCheck ( artist_requested , album_requested , limit_requested , offset_requested ) ;
2020-09-17 17:50:17 +02:00
return ;
}
QJsonObject obj_tracks = value_tracks . toObject ( ) ;
if ( ! obj_tracks . contains ( " limit " ) | |
! obj_tracks . contains ( " offset " ) | |
! obj_tracks . contains ( " total " ) | |
! obj_tracks . contains ( " items " ) ) {
2022-10-31 06:12:02 +01:00
SongsFinishCheck ( artist_requested , album_requested , limit_requested , offset_requested ) ;
2020-09-17 17:50:17 +02:00
Error ( " Json songs object is missing values. " , json_obj ) ;
return ;
}
//int limit = obj_tracks["limit"].toInt();
int offset = obj_tracks [ " offset " ] . toInt ( ) ;
int songs_total = obj_tracks [ " total " ] . toInt ( ) ;
if ( offset ! = offset_requested ) {
Error ( QString ( " Offset returned does not match offset requested! %1 != %2 " ) . arg ( offset ) . arg ( offset_requested ) ) ;
2022-10-31 06:12:02 +01:00
SongsFinishCheck ( album_artist , album , limit_requested , offset_requested , songs_total ) ;
2020-09-17 17:50:17 +02:00
return ;
}
QJsonValue value_items = ExtractItems ( obj_tracks ) ;
if ( ! value_items . isArray ( ) ) {
2022-10-31 06:12:02 +01:00
SongsFinishCheck ( album_artist , album , limit_requested , offset_requested , songs_total ) ;
2020-09-17 17:50:17 +02:00
return ;
}
QJsonArray array_items = value_items . toArray ( ) ;
if ( array_items . isEmpty ( ) ) {
2023-02-18 14:09:27 +01:00
if ( ( query_type_ = = QueryType : : Songs | | query_type_ = = QueryType : : SearchSongs ) & & offset_requested = = 0 ) {
2020-09-17 17:50:17 +02:00
no_results_ = true ;
}
2022-10-31 06:12:02 +01:00
SongsFinishCheck ( album_artist , album , limit_requested , offset_requested , songs_total ) ;
2020-09-17 17:50:17 +02:00
return ;
}
bool compilation = false ;
2021-07-01 02:01:38 +02:00
bool multidisc = false ;
2020-09-17 17:50:17 +02:00
SongList songs ;
int songs_received = 0 ;
2021-03-26 22:10:43 +01:00
for ( const QJsonValueRef value_item : array_items ) {
2020-09-17 17:50:17 +02:00
if ( ! value_item . isObject ( ) ) {
2021-03-26 22:10:43 +01:00
Error ( " Invalid Json reply, track is not a object. " ) ;
2020-09-17 17:50:17 +02:00
continue ;
}
QJsonObject obj_item = value_item . toObject ( ) ;
+ + songs_received ;
2023-02-18 14:09:27 +01:00
Song song ( Song : : Source : : Qobuz ) ;
2022-10-31 06:12:02 +01:00
ParseSong ( song , obj_item , album_artist , album ) ;
2020-09-17 17:50:17 +02:00
if ( ! song . is_valid ( ) ) continue ;
2021-07-01 02:01:38 +02:00
if ( song . disc ( ) > = 2 ) multidisc = true ;
2020-09-17 17:50:17 +02:00
if ( song . is_compilation ( ) ) compilation = true ;
songs < < song ;
}
2021-07-01 02:01:38 +02:00
for ( Song song : songs ) {
2020-09-17 17:50:17 +02:00
if ( compilation ) song . set_compilation_detected ( true ) ;
2021-07-01 02:01:38 +02:00
if ( ! multidisc ) song . set_disc ( 0 ) ;
songs_ . insert ( song . song_id ( ) , song ) ;
2020-09-17 17:50:17 +02:00
}
2023-02-18 14:09:27 +01:00
if ( query_type_ = = QueryType : : Songs | | query_type_ = = QueryType : : SearchSongs ) {
2022-10-31 06:12:02 +01:00
songs_received_ + = songs_received ;
emit UpdateProgress ( query_id_ , GetProgress ( songs_received_ , songs_total_ ) ) ;
}
SongsFinishCheck ( album_artist , album , limit_requested , offset_requested , songs_total , songs_received ) ;
2020-09-17 17:50:17 +02:00
}
2022-10-31 06:12:02 +01:00
void QobuzRequest : : SongsFinishCheck ( const Artist & artist , const Album & album , const int limit , const int offset , const int songs_total , const int songs_received ) {
2020-09-17 17:50:17 +02:00
if ( finished_ ) return ;
if ( limit = = 0 | | limit > songs_received ) {
int offset_next = offset + songs_received ;
if ( offset_next > 0 & & offset_next < songs_total ) {
2023-02-18 14:09:27 +01:00
switch ( query_type_ ) {
case QueryType : : Songs :
2020-09-17 17:50:17 +02:00
AddSongsRequest ( offset_next ) ;
break ;
2023-02-18 14:09:27 +01:00
case QueryType : : SearchSongs :
2020-09-17 17:50:17 +02:00
AddSongsSearchRequest ( offset_next ) ;
break ;
2023-02-18 14:09:27 +01:00
case QueryType : : Artists :
case QueryType : : SearchArtists :
case QueryType : : Albums :
case QueryType : : SearchAlbums :
2022-10-31 06:12:02 +01:00
AddAlbumSongsRequest ( artist , album , offset_next ) ;
2020-09-17 17:50:17 +02:00
break ;
default :
break ;
}
}
}
2022-10-31 06:12:02 +01:00
GetAlbumCoversCheck ( ) ;
2020-09-17 17:50:17 +02:00
FinishCheck ( ) ;
}
2022-10-31 06:12:02 +01:00
void QobuzRequest : : ParseSong ( Song & song , const QJsonObject & json_obj , const Artist & album_artist , const Album & album ) {
2020-09-17 17:50:17 +02:00
if (
! json_obj . contains ( " id " ) | |
! json_obj . contains ( " title " ) | |
! json_obj . contains ( " track_number " ) | |
! json_obj . contains ( " duration " ) | |
! json_obj . contains ( " copyright " ) | |
! json_obj . contains ( " streamable " )
) {
Error ( " Invalid Json reply, track is missing one or more values. " , json_obj ) ;
2022-10-31 06:12:02 +01:00
return ;
2020-09-17 17:50:17 +02:00
}
QString song_id ;
if ( json_obj [ " id " ] . isString ( ) ) {
song_id = json_obj [ " id " ] . toString ( ) ;
}
else {
song_id = QString : : number ( json_obj [ " id " ] . toInt ( ) ) ;
}
QString title = json_obj [ " title " ] . toString ( ) ;
int track = json_obj [ " track_number " ] . toInt ( ) ;
QString copyright = json_obj [ " copyright " ] . toString ( ) ;
2021-10-30 02:21:29 +02:00
qint64 duration = json_obj [ " duration " ] . toInt ( ) * kNsecPerSec ;
2020-09-17 17:50:17 +02:00
//bool streamable = json_obj["streamable"].toBool();
QString composer ;
QString performer ;
2022-10-31 06:12:02 +01:00
Artist song_artist = album_artist ;
Album song_album = album ;
2020-09-17 17:50:17 +02:00
if ( json_obj . contains ( " album " ) ) {
QJsonValue value_album = json_obj [ " album " ] ;
if ( ! value_album . isObject ( ) ) {
Error ( " Invalid Json reply, album is not an object. " , value_album ) ;
2022-10-31 06:12:02 +01:00
return ;
2020-09-17 17:50:17 +02:00
}
QJsonObject obj_album = value_album . toObject ( ) ;
if ( obj_album . contains ( " id " ) ) {
if ( obj_album [ " id " ] . isString ( ) ) {
2022-10-31 06:12:02 +01:00
song_album . album_id = obj_album [ " id " ] . toString ( ) ;
2020-09-17 17:50:17 +02:00
}
else {
2022-10-31 06:12:02 +01:00
song_album . album_id = QString : : number ( obj_album [ " id " ] . toInt ( ) ) ;
2021-07-11 07:40:57 +02:00
}
2020-09-17 17:50:17 +02:00
}
if ( obj_album . contains ( " title " ) ) {
2022-10-31 06:12:02 +01:00
song_album . album = obj_album [ " title " ] . toString ( ) ;
2020-09-17 17:50:17 +02:00
}
if ( obj_album . contains ( " artist " ) ) {
QJsonValue value_artist = obj_album [ " artist " ] ;
if ( ! value_artist . isObject ( ) ) {
Error ( " Invalid Json reply, album artist is not a object. " , value_artist ) ;
2022-10-31 06:12:02 +01:00
return ;
2020-09-17 17:50:17 +02:00
}
QJsonObject obj_artist = value_artist . toObject ( ) ;
if ( ! obj_artist . contains ( " id " ) | | ! obj_artist . contains ( " name " ) ) {
Error ( " Invalid Json reply, album artist is missing id or name. " , obj_artist ) ;
2022-10-31 06:12:02 +01:00
return ;
2020-09-17 17:50:17 +02:00
}
if ( obj_artist [ " id " ] . isString ( ) ) {
2022-10-31 06:12:02 +01:00
song_artist . artist_id = obj_artist [ " id " ] . toString ( ) ;
2020-09-17 17:50:17 +02:00
}
else {
2022-10-31 06:12:02 +01:00
song_artist . artist_id = QString : : number ( obj_artist [ " id " ] . toInt ( ) ) ;
2020-09-17 17:50:17 +02:00
}
2022-10-31 06:12:02 +01:00
song_artist . artist = obj_artist [ " name " ] . toString ( ) ;
2020-09-17 17:50:17 +02:00
}
if ( obj_album . contains ( " image " ) ) {
QJsonValue value_image = obj_album [ " image " ] ;
if ( ! value_image . isObject ( ) ) {
Error ( " Invalid Json reply, album image is not a object. " , value_image ) ;
2022-10-31 06:12:02 +01:00
return ;
2020-09-17 17:50:17 +02:00
}
QJsonObject obj_image = value_image . toObject ( ) ;
if ( ! obj_image . contains ( " large " ) ) {
Error ( " Invalid Json reply, album image is missing large. " , obj_image ) ;
2022-10-31 06:12:02 +01:00
return ;
2020-09-17 17:50:17 +02:00
}
QString album_image = obj_image [ " large " ] . toString ( ) ;
if ( ! album_image . isEmpty ( ) ) {
2022-10-31 06:12:02 +01:00
song_album . cover_url . setUrl ( album_image ) ;
2020-09-17 17:50:17 +02:00
}
}
}
if ( json_obj . contains ( " composer " ) ) {
QJsonValue value_composer = json_obj [ " composer " ] ;
if ( ! value_composer . isObject ( ) ) {
Error ( " Invalid Json reply, track composer is not a object. " , value_composer ) ;
2022-10-31 06:12:02 +01:00
return ;
2020-09-17 17:50:17 +02:00
}
QJsonObject obj_composer = value_composer . toObject ( ) ;
if ( ! obj_composer . contains ( " id " ) | | ! obj_composer . contains ( " name " ) ) {
Error ( " Invalid Json reply, track composer is missing id or name. " , obj_composer ) ;
2022-10-31 06:12:02 +01:00
return ;
2020-09-17 17:50:17 +02:00
}
composer = obj_composer [ " name " ] . toString ( ) ;
}
if ( json_obj . contains ( " performer " ) ) {
QJsonValue value_performer = json_obj [ " performer " ] ;
if ( ! value_performer . isObject ( ) ) {
Error ( " Invalid Json reply, track performer is not a object. " , value_performer ) ;
2022-10-31 06:12:02 +01:00
return ;
2020-09-17 17:50:17 +02:00
}
QJsonObject obj_performer = value_performer . toObject ( ) ;
if ( ! obj_performer . contains ( " id " ) | | ! obj_performer . contains ( " name " ) ) {
Error ( " Invalid Json reply, track performer is missing id or name. " , obj_performer ) ;
2022-10-31 06:12:02 +01:00
return ;
2020-09-17 17:50:17 +02:00
}
performer = obj_performer [ " name " ] . toString ( ) ;
}
//if (!streamable) {
//Warn(QString("Song %1 %2 %3 is not streamable").arg(album_artist).arg(album).arg(title));
//}
QUrl url ;
url . setScheme ( url_handler_ - > scheme ( ) ) ;
url . setPath ( song_id ) ;
title . remove ( Song : : kTitleRemoveMisc ) ;
//qLog(Debug) << "id" << song_id << "track" << track << "title" << title << "album" << album << "album artist" << album_artist << cover_url << streamable << url;
2023-02-18 14:09:27 +01:00
song . set_source ( Song : : Source : : Qobuz ) ;
2020-09-17 17:50:17 +02:00
song . set_song_id ( song_id ) ;
2022-10-31 06:12:02 +01:00
song . set_album_id ( song_album . album_id ) ;
song . set_artist_id ( song_artist . artist_id ) ;
song . set_album ( song_album . album ) ;
song . set_artist ( song_artist . artist ) ;
if ( ! album_artist . artist . isEmpty ( ) & & album_artist . artist ! = song_artist . artist ) {
song . set_albumartist ( album_artist . artist ) ;
}
2020-09-17 17:50:17 +02:00
song . set_title ( title ) ;
song . set_track ( track ) ;
song . set_url ( url ) ;
song . set_length_nanosec ( duration ) ;
2022-10-31 06:12:02 +01:00
song . set_art_automatic ( song_album . cover_url ) ;
2022-02-08 21:28:11 +01:00
song . set_performer ( performer ) ;
song . set_composer ( composer ) ;
2020-09-17 17:50:17 +02:00
song . set_comment ( copyright ) ;
song . set_directory_id ( 0 ) ;
2023-02-18 14:09:27 +01:00
song . set_filetype ( Song : : FileType : : Stream ) ;
2020-09-17 17:50:17 +02:00
song . set_filesize ( 0 ) ;
song . set_mtime ( 0 ) ;
song . set_ctime ( 0 ) ;
song . set_valid ( true ) ;
2022-10-31 06:12:02 +01:00
}
void QobuzRequest : : GetAlbumCoversCheck ( ) {
if (
! finished_ & &
service_ - > download_album_covers ( ) & &
IsQuery ( ) & &
artists_requests_queue_ . isEmpty ( ) & &
albums_requests_queue_ . isEmpty ( ) & &
songs_requests_queue_ . isEmpty ( ) & &
artist_albums_requests_queue_ . isEmpty ( ) & &
album_songs_requests_queue_ . isEmpty ( ) & &
album_cover_requests_queue_ . isEmpty ( ) & &
artist_albums_requests_pending_ . isEmpty ( ) & &
album_songs_requests_pending_ . isEmpty ( ) & &
album_covers_requests_sent_ . isEmpty ( ) & &
artists_requests_active_ < = 0 & &
albums_requests_active_ < = 0 & &
songs_requests_active_ < = 0 & &
artist_albums_requests_active_ < = 0 & &
album_songs_requests_active_ < = 0 & &
album_covers_requests_active_ < = 0
) {
GetAlbumCovers ( ) ;
}
2020-09-17 17:50:17 +02:00
}
void QobuzRequest : : GetAlbumCovers ( ) {
2021-07-12 07:34:20 +02:00
const SongList songs = songs_ . values ( ) ;
for ( const Song & song : songs ) {
2020-09-17 17:50:17 +02:00
AddAlbumCoverRequest ( song ) ;
}
2022-10-31 06:12:02 +01:00
if ( album_covers_requests_total_ = = 1 ) emit UpdateStatus ( query_id_ , tr ( " Receiving album cover for %1 album... " ) . arg ( album_covers_requests_total_ ) ) ;
else emit UpdateStatus ( query_id_ , tr ( " Receiving album covers for %1 albums... " ) . arg ( album_covers_requests_total_ ) ) ;
2020-09-17 17:50:17 +02:00
emit UpdateProgress ( query_id_ , 0 ) ;
2022-10-31 06:12:02 +01:00
StartRequests ( ) ;
2020-09-17 17:50:17 +02:00
}
2021-07-01 02:01:38 +02:00
void QobuzRequest : : AddAlbumCoverRequest ( const Song & song ) {
2020-09-17 17:50:17 +02:00
2021-02-26 21:03:51 +01:00
QUrl cover_url = song . art_automatic ( ) ;
2020-09-17 17:50:17 +02:00
if ( ! cover_url . isValid ( ) ) return ;
if ( album_covers_requests_sent_ . contains ( cover_url ) ) {
2021-07-01 02:01:38 +02:00
album_covers_requests_sent_ . insert ( cover_url , song . song_id ( ) ) ;
2020-09-17 17:50:17 +02:00
return ;
}
AlbumCoverRequest request ;
request . url = cover_url ;
2023-03-18 20:03:07 +01:00
request . filename = CoverUtils : : CoverFilePath ( CoverOptions ( ) , song . source ( ) , song . effective_albumartist ( ) , song . effective_album ( ) , song . album_id ( ) , QString ( ) , cover_url ) ;
2020-09-17 17:50:17 +02:00
if ( request . filename . isEmpty ( ) ) return ;
2021-07-01 02:01:38 +02:00
album_covers_requests_sent_ . insert ( cover_url , song . song_id ( ) ) ;
2022-10-31 06:12:02 +01:00
+ + album_covers_requests_total_ ;
2020-09-17 17:50:17 +02:00
album_cover_requests_queue_ . enqueue ( request ) ;
}
void QobuzRequest : : FlushAlbumCoverRequests ( ) {
while ( ! album_cover_requests_queue_ . isEmpty ( ) & & album_covers_requests_active_ < kMaxConcurrentAlbumCoverRequests ) {
AlbumCoverRequest request = album_cover_requests_queue_ . dequeue ( ) ;
QNetworkRequest req ( request . url ) ;
2021-07-11 09:49:38 +02:00
req . setAttribute ( QNetworkRequest : : RedirectPolicyAttribute , QNetworkRequest : : NoLessSafeRedirectPolicy ) ;
2020-09-17 17:50:17 +02:00
QNetworkReply * reply = network_ - > get ( req ) ;
album_cover_replies_ < < reply ;
2021-03-21 00:37:17 +01:00
QObject : : connect ( reply , & QNetworkReply : : finished , this , [ this , reply , request ] ( ) { AlbumCoverReceived ( reply , request . url , request . filename ) ; } ) ;
2020-09-17 17:50:17 +02:00
2022-10-31 06:12:02 +01:00
+ + album_covers_requests_active_ ;
2020-09-17 17:50:17 +02:00
}
}
void QobuzRequest : : AlbumCoverReceived ( QNetworkReply * reply , const QUrl & cover_url , const QString & filename ) {
if ( album_cover_replies_ . contains ( reply ) ) {
album_cover_replies_ . removeAll ( reply ) ;
2022-10-31 06:12:02 +01:00
QObject : : disconnect ( reply , nullptr , this , nullptr ) ;
2020-09-17 17:50:17 +02:00
reply - > deleteLater ( ) ;
}
else {
AlbumCoverFinishCheck ( ) ;
return ;
}
- - album_covers_requests_active_ ;
2022-10-31 06:12:02 +01:00
+ + album_covers_requests_received_ ;
2020-09-17 17:50:17 +02:00
if ( finished_ ) return ;
2022-10-31 06:12:02 +01:00
emit UpdateProgress ( query_id_ , GetProgress ( album_covers_requests_received_ , album_covers_requests_total_ ) ) ;
2020-09-17 17:50:17 +02:00
if ( ! album_covers_requests_sent_ . contains ( cover_url ) ) {
AlbumCoverFinishCheck ( ) ;
return ;
}
if ( reply - > error ( ) ! = QNetworkReply : : NoError ) {
Error ( QString ( " %1 (%2) " ) . arg ( reply - > errorString ( ) ) . arg ( reply - > error ( ) ) ) ;
2020-10-11 01:08:42 +02:00
if ( album_covers_requests_sent_ . contains ( cover_url ) ) album_covers_requests_sent_ . remove ( cover_url ) ;
2020-09-17 17:50:17 +02:00
AlbumCoverFinishCheck ( ) ;
return ;
}
if ( reply - > attribute ( QNetworkRequest : : HttpStatusCodeAttribute ) . toInt ( ) ! = 200 ) {
Error ( QString ( " Received HTTP code %1 for %2. " ) . arg ( reply - > attribute ( QNetworkRequest : : HttpStatusCodeAttribute ) . toInt ( ) ) . arg ( cover_url . toString ( ) ) ) ;
if ( album_covers_requests_sent_ . contains ( cover_url ) ) album_covers_requests_sent_ . remove ( cover_url ) ;
AlbumCoverFinishCheck ( ) ;
return ;
}
QString mimetype = reply - > header ( QNetworkRequest : : ContentTypeHeader ) . toString ( ) ;
2021-05-29 23:27:40 +02:00
if ( mimetype . contains ( ' ; ' ) ) {
mimetype = mimetype . left ( mimetype . indexOf ( ' ; ' ) ) ;
}
2021-02-26 21:03:51 +01:00
if ( ! ImageUtils : : SupportedImageMimeTypes ( ) . contains ( mimetype , Qt : : CaseInsensitive ) & & ! ImageUtils : : SupportedImageFormats ( ) . contains ( mimetype , Qt : : CaseInsensitive ) ) {
2021-03-21 04:47:11 +01:00
Error ( QString ( " Unsupported mimetype for image reader %1 for %2 " ) . arg ( mimetype , cover_url . toString ( ) ) ) ;
2020-09-17 17:50:17 +02:00
if ( album_covers_requests_sent_ . contains ( cover_url ) ) album_covers_requests_sent_ . remove ( cover_url ) ;
AlbumCoverFinishCheck ( ) ;
return ;
}
QByteArray data = reply - > readAll ( ) ;
2020-10-11 01:08:42 +02:00
if ( data . isEmpty ( ) ) {
2020-09-17 17:50:17 +02:00
Error ( QString ( " Received empty image data for %1 " ) . arg ( cover_url . toString ( ) ) ) ;
2020-10-11 01:08:42 +02:00
if ( album_covers_requests_sent_ . contains ( cover_url ) ) album_covers_requests_sent_ . remove ( cover_url ) ;
2020-09-17 17:50:17 +02:00
AlbumCoverFinishCheck ( ) ;
return ;
}
2020-10-11 01:08:42 +02:00
2023-03-18 19:41:36 +01:00
QByteArrayList format_list = ImageUtils : : ImageFormatsForMimeType ( mimetype . toUtf8 ( ) ) ;
2020-10-13 01:38:09 +02:00
char * format = nullptr ;
if ( ! format_list . isEmpty ( ) ) {
format = format_list . first ( ) . data ( ) ;
2020-10-11 01:08:42 +02:00
}
2020-09-17 17:50:17 +02:00
QImage image ;
if ( image . loadFromData ( data , format ) ) {
if ( image . save ( filename , format ) ) {
while ( album_covers_requests_sent_ . contains ( cover_url ) ) {
2021-07-01 02:01:38 +02:00
const QString song_id = album_covers_requests_sent_ . take ( cover_url ) ;
if ( songs_ . contains ( song_id ) ) {
songs_ [ song_id ] . set_art_automatic ( QUrl : : fromLocalFile ( filename ) ) ;
}
2020-09-17 17:50:17 +02:00
}
}
2020-10-11 01:08:42 +02:00
else {
Error ( QString ( " Error saving image data to %1 " ) . arg ( filename ) ) ;
if ( album_covers_requests_sent_ . contains ( cover_url ) ) album_covers_requests_sent_ . remove ( cover_url ) ;
}
2020-09-17 17:50:17 +02:00
}
else {
2020-10-11 01:08:42 +02:00
if ( album_covers_requests_sent_ . contains ( cover_url ) ) album_covers_requests_sent_ . remove ( cover_url ) ;
2020-09-17 17:50:17 +02:00
Error ( QString ( " Error decoding image data from %1 " ) . arg ( cover_url . toString ( ) ) ) ;
}
AlbumCoverFinishCheck ( ) ;
}
void QobuzRequest : : AlbumCoverFinishCheck ( ) {
FinishCheck ( ) ;
}
void QobuzRequest : : FinishCheck ( ) {
if (
! finished_ & &
artists_requests_queue_ . isEmpty ( ) & &
2022-10-31 06:12:02 +01:00
albums_requests_queue_ . isEmpty ( ) & &
2020-09-17 17:50:17 +02:00
songs_requests_queue_ . isEmpty ( ) & &
artist_albums_requests_queue_ . isEmpty ( ) & &
album_songs_requests_queue_ . isEmpty ( ) & &
album_cover_requests_queue_ . isEmpty ( ) & &
artist_albums_requests_pending_ . isEmpty ( ) & &
album_songs_requests_pending_ . isEmpty ( ) & &
album_covers_requests_sent_ . isEmpty ( ) & &
artists_requests_active_ < = 0 & &
albums_requests_active_ < = 0 & &
songs_requests_active_ < = 0 & &
artist_albums_requests_active_ < = 0 & &
album_songs_requests_active_ < = 0 & &
2022-10-31 06:12:02 +01:00
album_covers_requests_active_ < = 0
2020-09-17 17:50:17 +02:00
) {
2022-10-31 06:12:02 +01:00
if ( timer_flush_requests_ - > isActive ( ) ) {
timer_flush_requests_ - > stop ( ) ;
}
2020-09-17 17:50:17 +02:00
finished_ = true ;
if ( no_results_ & & songs_ . isEmpty ( ) ) {
if ( IsSearch ( ) )
2021-09-19 15:41:36 +02:00
emit Results ( query_id_ , SongMap ( ) , tr ( " No match. " ) ) ;
2020-09-17 17:50:17 +02:00
else
2021-09-19 15:41:36 +02:00
emit Results ( query_id_ , SongMap ( ) , QString ( ) ) ;
2020-09-17 17:50:17 +02:00
}
else {
if ( songs_ . isEmpty ( ) & & errors_ . isEmpty ( ) )
2021-09-19 15:41:36 +02:00
emit Results ( query_id_ , songs_ , tr ( " Unknown error " ) ) ;
2020-09-17 17:50:17 +02:00
else
2021-09-19 15:41:36 +02:00
emit Results ( query_id_ , songs_ , ErrorsToHTML ( errors_ ) ) ;
2020-09-17 17:50:17 +02:00
}
}
}
2022-10-31 06:12:02 +01:00
int QobuzRequest : : GetProgress ( const int count , const int total ) {
return static_cast < int > ( ( static_cast < float > ( count ) / static_cast < float > ( total ) ) * 100.0F ) ;
}
2020-09-17 17:50:17 +02:00
void QobuzRequest : : Error ( const QString & error , const QVariant & debug ) {
if ( ! error . isEmpty ( ) ) {
errors_ < < error ;
qLog ( Error ) < < " Qobuz: " < < error ;
}
if ( debug . isValid ( ) ) qLog ( Debug ) < < debug ;
FinishCheck ( ) ;
}
void QobuzRequest : : Warn ( const QString & error , const QVariant & debug ) {
qLog ( Error ) < < " Qobuz: " < < error ;
if ( debug . isValid ( ) ) qLog ( Debug ) < < debug ;
}