2018-08-29 21:42:24 +02:00
/*
* Strawberry Music Player
2021-03-20 21:14:47 +01:00
* Copyright 2018 - 2021 , Jonas Kvinge < jonas @ jkvinge . net >
2018-08-29 21:42:24 +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"
2020-05-08 18:35:36 +02:00
# include <algorithm>
2018-08-29 21:42:24 +02:00
# include <QObject>
# include <QTimer>
# include <QList>
# include <QtDebug>
# include "core/logging.h"
# include "lyricsfetcher.h"
# include "lyricsfetchersearch.h"
# include "lyricsprovider.h"
# include "lyricsproviders.h"
2020-05-08 18:35:36 +02:00
const int LyricsFetcherSearch : : kSearchTimeoutMs = 3000 ;
const int LyricsFetcherSearch : : kGoodLyricsLength = 60 ;
const float LyricsFetcherSearch : : kHighScore = 2.5 ;
2018-08-29 21:42:24 +02:00
2020-05-08 18:35:36 +02:00
LyricsFetcherSearch : : LyricsFetcherSearch ( const LyricsSearchRequest & request , QObject * parent )
2018-08-29 21:42:24 +02:00
: QObject ( parent ) ,
request_ ( request ) ,
cancel_requested_ ( false ) {
2021-01-26 16:48:04 +01:00
QTimer : : singleShot ( kSearchTimeoutMs , this , & LyricsFetcherSearch : : TerminateSearch ) ;
2018-08-29 21:42:24 +02:00
}
void LyricsFetcherSearch : : TerminateSearch ( ) {
2021-03-21 04:47:11 +01:00
QList < int > keys = pending_requests_ . keys ( ) ;
for ( const int id : keys ) {
2018-08-29 21:42:24 +02:00
pending_requests_ . take ( id ) - > CancelSearch ( id ) ;
}
AllProvidersFinished ( ) ;
}
void LyricsFetcherSearch : : Start ( LyricsProviders * lyrics_providers ) {
2020-09-10 17:17:55 +02:00
// Ignore Radio Paradise "commercial" break.
2021-07-13 23:18:12 +02:00
if ( request_ . artist . compare ( " commercial-free " , Qt : : CaseInsensitive ) = = 0 & & request_ . title . compare ( " listener-supported " , Qt : : CaseInsensitive ) = = 0 ) {
2020-09-10 17:17:55 +02:00
TerminateSearch ( ) ;
return ;
}
2020-05-08 18:35:36 +02:00
QList < LyricsProvider * > lyrics_providers_sorted = lyrics_providers - > List ( ) ;
std : : stable_sort ( lyrics_providers_sorted . begin ( ) , lyrics_providers_sorted . end ( ) , ProviderCompareOrder ) ;
for ( LyricsProvider * provider : lyrics_providers_sorted ) {
if ( ! provider - > is_enabled ( ) | | ! provider - > IsAuthenticated ( ) ) continue ;
2021-01-26 16:48:04 +01:00
QObject : : connect ( provider , & LyricsProvider : : SearchFinished , this , & LyricsFetcherSearch : : ProviderSearchFinished ) ;
2018-08-29 21:42:24 +02:00
const int id = lyrics_providers - > NextId ( ) ;
const bool success = provider - > StartSearch ( request_ . artist , request_ . album , request_ . title , id ) ;
if ( success ) pending_requests_ [ id ] = provider ;
}
if ( pending_requests_ . isEmpty ( ) ) TerminateSearch ( ) ;
}
2019-06-23 18:34:03 +02:00
void LyricsFetcherSearch : : ProviderSearchFinished ( const quint64 id , const LyricsSearchResults & results ) {
2018-08-29 21:42:24 +02:00
if ( ! pending_requests_ . contains ( id ) ) return ;
LyricsProvider * provider = pending_requests_ . take ( id ) ;
LyricsSearchResults results_copy ( results ) ;
2020-05-08 18:35:36 +02:00
float higest_score = 0.0 ;
2021-08-23 21:21:08 +02:00
for ( int i = 0 ; i < results_copy . count ( ) ; + + i ) {
2018-08-29 21:42:24 +02:00
results_copy [ i ] . provider = provider - > name ( ) ;
2020-05-08 18:35:36 +02:00
results_copy [ i ] . score = 0.0 ;
2021-07-13 23:18:12 +02:00
if ( results_copy [ i ] . artist . compare ( request_ . artist , Qt : : CaseInsensitive ) = = 0 ) {
2020-05-08 18:35:36 +02:00
results_copy [ i ] . score + = 0.5 ;
}
2021-07-13 23:18:12 +02:00
if ( results_copy [ i ] . album . compare ( request_ . album , Qt : : CaseInsensitive ) = = 0 ) {
2020-05-08 18:35:36 +02:00
results_copy [ i ] . score + = 0.5 ;
}
2021-07-13 23:18:12 +02:00
if ( results_copy [ i ] . title . compare ( request_ . title , Qt : : CaseInsensitive ) = = 0 ) {
2020-05-08 18:35:36 +02:00
results_copy [ i ] . score + = 0.5 ;
}
2021-07-13 23:18:12 +02:00
if ( results_copy [ i ] . artist . compare ( request_ . artist , Qt : : CaseInsensitive ) ! = 0 & & results_copy [ i ] . title . compare ( request_ . title , Qt : : CaseInsensitive ) ! = 0 ) {
2020-05-08 18:35:36 +02:00
results_copy [ i ] . score - = 1.5 ;
}
if ( results_copy [ i ] . lyrics . length ( ) > kGoodLyricsLength ) results_copy [ i ] . score + = 1.0 ;
if ( results_copy [ i ] . score > higest_score ) higest_score = results_copy [ i ] . score ;
2018-08-29 21:42:24 +02:00
}
results_ . append ( results_copy ) ;
2020-05-08 18:35:36 +02:00
std : : stable_sort ( results_ . begin ( ) , results_ . end ( ) , LyricsSearchResultCompareScore ) ;
2018-08-29 21:42:24 +02:00
if ( ! pending_requests_ . isEmpty ( ) ) {
2021-07-11 09:49:38 +02:00
if ( ! results_ . isEmpty ( ) & & higest_score > = kHighScore ) { // Highest score, no need to wait for other providers.
2020-05-08 18:35:36 +02:00
qLog ( Debug ) < < " Got lyrics with high score from " < < results_ . last ( ) . provider < < " for " < < request_ . artist < < request_ . title < < " score " < < results_ . last ( ) . score < < " finishing search. " ;
TerminateSearch ( ) ;
}
else {
return ;
}
2018-08-29 21:42:24 +02:00
return ;
}
AllProvidersFinished ( ) ;
}
void LyricsFetcherSearch : : AllProvidersFinished ( ) {
if ( cancel_requested_ ) return ;
if ( ! results_ . isEmpty ( ) ) {
2020-05-08 18:35:36 +02:00
qLog ( Debug ) < < " Using lyrics from " < < results_ . last ( ) . provider < < " for " < < request_ . artist < < request_ . title < < " with score " < < results_ . last ( ) . score ;
emit LyricsFetched ( request_ . id , results_ . last ( ) . provider , results_ . last ( ) . lyrics ) ;
2018-08-29 21:42:24 +02:00
}
2020-05-08 18:35:36 +02:00
2018-08-29 21:42:24 +02:00
emit SearchFinished ( request_ . id , results_ ) ;
}
void LyricsFetcherSearch : : Cancel ( ) {
cancel_requested_ = true ;
if ( ! pending_requests_ . isEmpty ( ) ) {
TerminateSearch ( ) ;
}
}
2020-05-08 18:35:36 +02:00
bool LyricsFetcherSearch : : ProviderCompareOrder ( LyricsProvider * a , LyricsProvider * b ) {
return a - > order ( ) < b - > order ( ) ;
}
bool LyricsFetcherSearch : : LyricsSearchResultCompareScore ( const LyricsSearchResult & a , const LyricsSearchResult & b ) {
return a . score < b . score ;
}