File indexing completed on 2024-05-05 04:48:36
0001 /**************************************************************************************** 0002 * Copyright (c) 2010 Sergey Ivanov <123kash@gmail.com> * 0003 * * 0004 * This program is free software; you can redistribute it and/or modify it under * 0005 * the terms of the GNU General Public License as published by the Free Software * 0006 * Foundation; either version 2 of the License, or (at your option) any later * 0007 * version. * 0008 * * 0009 * This program is distributed in the hope that it will be useful, but WITHOUT ANY * 0010 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * 0011 * PARTICULAR PURPOSE. See the GNU General Public License for more details. * 0012 * * 0013 * You should have received a copy of the GNU General Public License along with * 0014 * this program. If not, see <http://www.gnu.org/licenses/>. * 0015 ****************************************************************************************/ 0016 0017 #define DEBUG_PREFIX "MusicDNSFinder" 0018 0019 #include "MusicDNSFinder.h" 0020 0021 #include "core/meta/Meta.h" 0022 #include "core/support/Debug.h" 0023 0024 #include <ThreadWeaver/Queue> 0025 0026 #include <QNetworkAccessManager> 0027 #include <QUrlQuery> 0028 0029 MusicDNSFinder::MusicDNSFinder( QObject *parent, 0030 const QString &host, const int port, const QString &pathPrefix, 0031 const QString &clietnId, const QString &clientVersion ) 0032 : QObject( parent ) 0033 , mdns_host( host ) 0034 , mdns_port( port ) 0035 , mdns_pathPrefix( pathPrefix ) 0036 , mdns_clientId( clietnId ) 0037 , mdns_clientVersion( clientVersion ) 0038 { 0039 DEBUG_BLOCK 0040 debug() << "Initiating MusicDNS search:"; 0041 debug() << "\tHost:\t\t" << mdns_host; 0042 debug() << "\tPort:\t\t" << mdns_port; 0043 debug() << "\tPath Prefix:\t" << mdns_pathPrefix; 0044 debug() << "\tClient ID:\t" << mdns_clientId; 0045 debug() << "\tClient version:\t" << mdns_clientVersion; 0046 net = The::networkAccessManager(); 0047 0048 _timer = new QTimer( this ); 0049 _timer->setInterval( 1000 ); 0050 0051 decodingComplete = false; 0052 0053 connect( net, &NetworkAccessManagerProxy::finished, this, &MusicDNSFinder::gotReply ); 0054 connect( _timer, &QTimer::timeout, this, &MusicDNSFinder::sendNewRequest ); 0055 } 0056 0057 void 0058 MusicDNSFinder::run( const Meta::TrackList &tracks ) 0059 { 0060 MusicDNSAudioDecoder *decoder = new MusicDNSAudioDecoder( tracks ); 0061 connect( decoder, &MusicDNSAudioDecoder::trackDecoded, 0062 this, &MusicDNSFinder::trackDecoded ); 0063 connect( decoder, &MusicDNSAudioDecoder::done, 0064 this, &MusicDNSFinder::decodingDone ); 0065 0066 ThreadWeaver::Queue::instance()->enqueue( QSharedPointer<ThreadWeaver::Job>(decoder) ); 0067 0068 _timer->start(); 0069 } 0070 0071 void MusicDNSFinder::sendNewRequest() 0072 { 0073 DEBUG_BLOCK 0074 if( m_requests.isEmpty() ) 0075 { 0076 checkDone(); 0077 return; 0078 } 0079 QPair < Meta::TrackPtr, QNetworkRequest > req = m_requests.takeFirst(); 0080 QNetworkReply *reply = net->get( req.second ); 0081 m_replyes.insert( reply, req.first ); 0082 connect( reply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::errorOccurred), 0083 this, &MusicDNSFinder::replyError ); 0084 debug() << "Request sent: " << req.second.url().toString(); 0085 } 0086 0087 void 0088 MusicDNSFinder::gotReply( QNetworkReply *reply ) 0089 { 0090 DEBUG_BLOCK 0091 if( reply->error() == QNetworkReply::NoError && m_replyes.contains( reply ) ) 0092 { 0093 QString document( reply->readAll() ); 0094 MusicDNSXmlParser *parser = new MusicDNSXmlParser( document ); 0095 if( !m_replyes.value( reply ).isNull() ) 0096 m_parsers.insert( parser, m_replyes.value( reply ) ); 0097 0098 connect( parser, &MusicDNSXmlParser::done, this, &MusicDNSFinder::parsingDone ); 0099 ThreadWeaver::Queue::instance()->enqueue( QSharedPointer<ThreadWeaver::Job>(parser) ); 0100 } 0101 0102 m_replyes.remove( reply ); 0103 reply->deleteLater(); 0104 checkDone(); 0105 } 0106 0107 void 0108 MusicDNSFinder::replyError( QNetworkReply::NetworkError code ) 0109 { 0110 DEBUG_BLOCK 0111 QNetworkReply *reply = qobject_cast< QNetworkReply * >( sender() ); 0112 if( !reply ) 0113 return; 0114 0115 if( !m_replyes.contains( reply ) || code == QNetworkReply::NoError ) 0116 return; 0117 0118 disconnect( reply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::errorOccurred), 0119 this, &MusicDNSFinder::replyError ); 0120 0121 debug() << "Error occurred during network request: " << reply->errorString(); 0122 m_replyes.remove( reply ); 0123 reply->deleteLater(); 0124 checkDone(); 0125 } 0126 0127 void 0128 MusicDNSFinder::parsingDone( ThreadWeaver::JobPointer _parser ) 0129 { 0130 DEBUG_BLOCK 0131 0132 MusicDNSXmlParser *parser = dynamic_cast< MusicDNSXmlParser * >( _parser.data() ); 0133 disconnect( parser, &MusicDNSXmlParser::done, this, &MusicDNSFinder::parsingDone ); 0134 if( m_parsers.contains( parser ) ) 0135 { 0136 bool found = false; 0137 foreach( QString PUID, parser->puid() ) 0138 if( PUID != "00000000-0000-0000-0000-000000000000" ) 0139 { 0140 found = true; 0141 emit trackFound( m_parsers.value( parser ), PUID ); 0142 break; 0143 } 0144 0145 if( !found ) 0146 emit progressStep(); 0147 0148 m_parsers.remove( parser ); 0149 } 0150 0151 parser->deleteLater(); 0152 checkDone(); 0153 } 0154 0155 void 0156 MusicDNSFinder::trackDecoded( const Meta::TrackPtr track, const QString fingerprint ) 0157 { 0158 DEBUG_BLOCK 0159 if( fingerprint.isEmpty() ) 0160 return; 0161 m_requests.append( qMakePair( track, compileRequest( fingerprint, track ) ) ); 0162 } 0163 0164 void 0165 MusicDNSFinder::decodingDone( ThreadWeaver::JobPointer _decoder ) 0166 { 0167 DEBUG_BLOCK 0168 MusicDNSAudioDecoder *decoder = dynamic_cast<MusicDNSAudioDecoder*>(_decoder.data()); 0169 disconnect( decoder, &MusicDNSAudioDecoder::trackDecoded, 0170 this, &MusicDNSFinder::trackDecoded ); 0171 disconnect( decoder, &MusicDNSAudioDecoder::done, 0172 this, &MusicDNSFinder::decodingDone ); 0173 decoder->deleteLater(); 0174 decodingComplete = true; 0175 checkDone(); 0176 } 0177 0178 void 0179 MusicDNSFinder::checkDone() 0180 { 0181 if( m_parsers.isEmpty() && m_requests.isEmpty() && m_replyes.isEmpty() && decodingComplete ) 0182 { 0183 debug() << "There is no any queued requests. Stopping timer."; 0184 _timer->stop(); 0185 emit done(); 0186 } 0187 } 0188 0189 QNetworkRequest 0190 MusicDNSFinder::compileRequest( const QString &fingerprint, const Meta::TrackPtr track ) 0191 { 0192 QUrl url; 0193 QUrlQuery query; 0194 url.setScheme( "http" ); 0195 url.setHost( mdns_host ); 0196 url.setPort( mdns_port ); 0197 url.setPath( mdns_pathPrefix+"/track/" ); 0198 query.addQueryItem( "gnr", "" ); 0199 query.addQueryItem( "art", track->artist().isNull()?"":track->artist()->name() ); 0200 query.addQueryItem( "rmd", "0" ); 0201 query.addQueryItem( "cid", mdns_clientId ); 0202 query.addQueryItem( "alb", track->album().isNull()?"":track->album()->name() ); 0203 query.addQueryItem( "fmt", "" ); 0204 query.addQueryItem( "brt", QString::number( track->bitrate() ) ); 0205 query.addQueryItem( "cvr", mdns_clientVersion ); 0206 query.addQueryItem( "fpt", fingerprint ); 0207 query.addQueryItem( "ttl", track->name().isNull()?track->playableUrl().fileName().remove( 0208 QRegExp( "^.*(\\.+(?:\\w{2,5}))$" ) ):track->name() ); 0209 query.addQueryItem( "tnm", "" ); 0210 query.addQueryItem( "lkt", "" ); 0211 query.addQueryItem( "dur", QString::number( track->length() ) ); 0212 query.addQueryItem( "yrr", "" ); 0213 url.setQuery( query ); 0214 0215 QNetworkRequest req( url ); 0216 req.setRawHeader( "User-Agent" , "Amarok" ); 0217 req.setRawHeader( "Connection", "Keep-Alive" ); 0218 0219 if( !_timer->isActive() ) 0220 _timer->start(); 0221 0222 return req; 0223 } 0224