File indexing completed on 2024-05-19 04:50:19
0001 /**************************************************************************************** 0002 * Copyright (c) 2006,2007 Nikolaj Hald Nielsen <nhn@kde.org> * 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 #include "MagnatuneXmlParser.h" 0018 0019 #include "core/support/Amarok.h" 0020 #include "core/support/Debug.h" 0021 #include "core/support/Components.h" 0022 #include "core/logger/Logger.h" 0023 0024 #include <KCompressionDevice> 0025 #include <KLocalizedString> 0026 0027 #include <QDomDocument> 0028 #include <QFile> 0029 0030 using namespace Meta; 0031 0032 MagnatuneXmlParser::MagnatuneXmlParser( const QString &filename ) 0033 : QObject() 0034 , ThreadWeaver::Job() 0035 { 0036 m_sFileName = filename; 0037 connect( this, &MagnatuneXmlParser::done, this, &MagnatuneXmlParser::completeJob ); 0038 } 0039 0040 0041 MagnatuneXmlParser::~MagnatuneXmlParser() 0042 { 0043 QFile(m_sFileName).remove(); 0044 qDeleteAll(m_currentAlbumTracksList); 0045 } 0046 0047 void 0048 MagnatuneXmlParser::run(ThreadWeaver::JobPointer self, ThreadWeaver::Thread *thread) 0049 { 0050 Q_UNUSED(self); 0051 Q_UNUSED(thread); 0052 readConfigFile( m_sFileName ); 0053 } 0054 0055 void 0056 MagnatuneXmlParser::defaultBegin(const ThreadWeaver::JobPointer& self, ThreadWeaver::Thread *thread) 0057 { 0058 Q_EMIT started(self); 0059 ThreadWeaver::Job::defaultBegin(self, thread); 0060 } 0061 0062 void 0063 MagnatuneXmlParser::defaultEnd(const ThreadWeaver::JobPointer& self, ThreadWeaver::Thread *thread) 0064 { 0065 ThreadWeaver::Job::defaultEnd(self, thread); 0066 if (!self->success()) { 0067 Q_EMIT failed(self); 0068 } 0069 Q_EMIT done(self); 0070 } 0071 0072 void 0073 MagnatuneXmlParser::completeJob( ) 0074 { 0075 Amarok::Logger::longMessage( 0076 i18ncp( "First part of: Magnatune.com database update complete. Database contains 3 tracks on 4 albums from 5 artists.", 0077 "Magnatune.com database update complete. Database contains 1 track on ", 0078 "Magnatune.com database update complete. Database contains %1 tracks on ", 0079 m_nNumberOfTracks) 0080 + i18ncp( "Middle part of: Magnatune.com database update complete. Database contains 3 tracks on 4 albums from 5 artists.", 0081 "1 album from ", "%1 albums from ", m_nNumberOfAlbums) 0082 + i18ncp( "Last part of: Magnatune.com database update complete. Database contains 3 tracks on 4 albums from 5 artists.", 0083 "1 artist.", "%1 artists.", m_nNumberOfArtists ) 0084 , Amarok::Logger::Information ); 0085 0086 Q_EMIT doneParsing(); 0087 deleteLater(); 0088 } 0089 0090 void 0091 MagnatuneXmlParser::readConfigFile( const QString &filename ) 0092 { 0093 DEBUG_BLOCK 0094 m_nNumberOfTracks = 0; 0095 m_nNumberOfAlbums = 0; 0096 m_nNumberOfArtists = 0; 0097 0098 QDomDocument doc( "config" ); 0099 0100 if ( !QFile::exists( filename ) ) 0101 { 0102 debug() << "Magnatune xml file does not exist"; 0103 return; 0104 } 0105 0106 KCompressionDevice device( filename, KCompressionDevice::BZip2 ); 0107 if ( !device.open( QIODevice::ReadOnly ) ) { 0108 debug() << "MagnatuneXmlParser::readConfigFile error reading file"; 0109 return ; 0110 } 0111 if ( !doc.setContent( &device ) ) 0112 { 0113 debug() << "MagnatuneXmlParser::readConfigFile error parsing file"; 0114 device.close(); 0115 return ; 0116 } 0117 device.close(); 0118 0119 m_dbHandler->destroyDatabase(); 0120 m_dbHandler->createDatabase(); 0121 0122 //run through all the elements 0123 QDomElement docElem = doc.documentElement(); 0124 0125 m_dbHandler->begin(); //start transaction (MAJOR speedup!!) 0126 parseElement( docElem ); 0127 m_dbHandler->commit(); //complete transaction 0128 0129 return; 0130 } 0131 0132 0133 void 0134 MagnatuneXmlParser::parseElement( const QDomElement &e ) 0135 { 0136 QString sElementName = e.tagName(); 0137 0138 sElementName == "Album" ? 0139 parseAlbum( e ) : 0140 parseChildren( e ); 0141 } 0142 0143 0144 void 0145 MagnatuneXmlParser::parseChildren( const QDomElement &e ) 0146 { 0147 QDomNode n = e.firstChild(); 0148 0149 while ( !n.isNull() ) 0150 { 0151 if ( n.isElement() ) 0152 parseElement( n.toElement() ); 0153 0154 n = n.nextSibling(); 0155 } 0156 } 0157 0158 void 0159 MagnatuneXmlParser::parseAlbum( const QDomElement &e ) 0160 { 0161 //DEBUG_BLOCK 0162 0163 QString name; 0164 QString albumCode; 0165 QStringList magnatuneGenres; 0166 int launchYear = 0; 0167 QString coverUrl; 0168 QString description; 0169 QString artistName; 0170 QString artistDescription; 0171 QUrl artistPhotoUrl; 0172 QString mp3Genre; 0173 QUrl artistPageUrl; 0174 0175 0176 QDomNode n = e.firstChild(); 0177 QDomElement childElement; 0178 0179 while ( !n.isNull() ) 0180 { 0181 if ( n.isElement() ) 0182 { 0183 childElement = n.toElement(); 0184 0185 QString sElementName = childElement.tagName(); 0186 0187 0188 if ( sElementName == "albumname" ) 0189 //printf(("|--+" + childElement.text() + "\n").toLatin1()); 0190 //m_currentAlbumItem = new MagnatuneListViewAlbumItem( m_currentArtistItem); 0191 name = childElement.text(); 0192 0193 0194 else if ( sElementName == "albumsku" ) 0195 albumCode = childElement.text(); 0196 0197 else if ( sElementName == "magnatunegenres" ) 0198 magnatuneGenres = childElement.text().split(',', Qt::SkipEmptyParts); 0199 0200 else if ( sElementName == "launchdate" ) 0201 { 0202 QString dateString = childElement.text(); 0203 QDate date = QDate::fromString( dateString, Qt::ISODate ); 0204 launchYear = date.year(); 0205 } 0206 0207 else if ( sElementName == "cover_small" ) 0208 coverUrl = childElement.text(); 0209 0210 else if ( sElementName == "artist" ) 0211 artistName = childElement.text(); 0212 0213 else if ( sElementName == "artistdesc" ) 0214 artistDescription = childElement.text(); 0215 0216 else if ( sElementName == "artistphoto" ) 0217 artistPhotoUrl = QUrl( childElement.text() ); 0218 0219 else if ( sElementName == "mp3genre" ) 0220 mp3Genre = childElement.text(); 0221 0222 else if ( sElementName == "home" ) 0223 artistPageUrl = QUrl( childElement.text() ); 0224 0225 else if ( sElementName == "Track" ) 0226 parseTrack( childElement ); 0227 0228 else if ( sElementName == "album_notes" ) 0229 description = childElement.text(); 0230 0231 } 0232 0233 n = n.nextSibling(); 0234 } 0235 0236 m_pCurrentAlbum.reset(new MagnatuneAlbum( name )); 0237 m_pCurrentAlbum->setAlbumCode( albumCode); 0238 m_pCurrentAlbum->setLaunchYear( launchYear ); 0239 m_pCurrentAlbum->setCoverUrl( coverUrl ); 0240 m_pCurrentAlbum->setDescription( description ); 0241 0242 0243 // now we should have gathered all info about current album (and artist)... 0244 //Time to add stuff to the database 0245 0246 //check if artist already exists, if not, create him/her/them/it 0247 0248 0249 int artistId; 0250 0251 0252 0253 if ( artistNameIdMap.contains( artistName ) ) 0254 { 0255 artistId = artistNameIdMap.value( artistName ); 0256 } else { 0257 //does not exist, lets create it... 0258 m_pCurrentArtist.reset(new MagnatuneArtist( artistName )); 0259 m_pCurrentArtist->setDescription( artistDescription ); 0260 m_pCurrentArtist->setPhotoUrl( artistPhotoUrl ); 0261 m_pCurrentArtist->setMagnatuneUrl( artistPageUrl ); 0262 0263 //this is tricky in postgresql, returns id as 0 (we are within a transaction, might be the cause...) 0264 artistId = m_dbHandler->insertArtist( m_pCurrentArtist.data() ); 0265 0266 m_nNumberOfArtists++; 0267 0268 if ( artistId == 0 ) 0269 { 0270 artistId = m_dbHandler->getArtistIdByExactName( m_pCurrentArtist->name() ); 0271 } 0272 0273 m_pCurrentArtist->setId( artistId ); 0274 0275 artistNameIdMap.insert( m_pCurrentArtist->name() , artistId ); 0276 0277 0278 } 0279 0280 m_pCurrentAlbum->setArtistId( artistId ); 0281 int albumId = m_dbHandler->insertAlbum( m_pCurrentAlbum.data() ); 0282 if ( albumId == 0 ) // again, postgres can play tricks on us... 0283 { 0284 albumId = m_dbHandler->getAlbumIdByAlbumCode( m_pCurrentAlbum->albumCode() ); 0285 } 0286 0287 m_pCurrentAlbum->setId( albumId ); 0288 0289 m_nNumberOfAlbums++; 0290 0291 QList<Meta::MagnatuneTrack*>::iterator it; 0292 for ( it = m_currentAlbumTracksList.begin(); it != m_currentAlbumTracksList.end(); ++it ) 0293 { 0294 0295 ( *it )->setAlbumId( m_pCurrentAlbum->id() ); 0296 ( *it )->setArtistId( artistId ); 0297 int trackId = m_dbHandler->insertTrack( ( *it ) ); 0298 0299 0300 m_dbHandler->insertMoods( trackId, ( *it )->moods() ); 0301 0302 m_nNumberOfTracks++; 0303 } 0304 0305 0306 // handle genres 0307 0308 foreach( const QString &genreName, magnatuneGenres ) { 0309 0310 //debug() << "inserting genre with album_id = " << albumId << " and name = " << genreName; 0311 ServiceGenre currentGenre( genreName ); 0312 currentGenre.setAlbumId( albumId ); 0313 m_dbHandler->insertGenre( ¤tGenre ); 0314 0315 } 0316 0317 magnatuneGenres.clear(); 0318 0319 qDeleteAll(m_currentAlbumTracksList); 0320 m_currentAlbumTracksList.clear(); 0321 } 0322 0323 0324 0325 void 0326 MagnatuneXmlParser::parseTrack( const QDomElement &e ) 0327 { 0328 //DEBUG_BLOCK 0329 m_currentTrackMoodList.clear(); 0330 0331 0332 QDomElement childElement; 0333 0334 MagnatuneTrack * pCurrentTrack = new MagnatuneTrack( QString() ); 0335 0336 QDomNode n = e.firstChild(); 0337 0338 while ( !n.isNull() ) 0339 { 0340 0341 if ( n.isElement() ) 0342 { 0343 0344 childElement = n.toElement(); 0345 0346 QString sElementName = childElement.tagName(); 0347 0348 0349 if ( sElementName == "trackname" ) 0350 { 0351 pCurrentTrack->setTitle( childElement.text() ); 0352 } 0353 else if ( sElementName == "url" ) 0354 { 0355 pCurrentTrack->setUidUrl( childElement.text() ); 0356 } 0357 else if ( sElementName == "oggurl" ) 0358 { 0359 pCurrentTrack->setOggUrl( childElement.text() ); 0360 } 0361 else if ( sElementName == "mp3lofi" ) 0362 { 0363 pCurrentTrack->setLofiUrl( childElement.text() ); 0364 } 0365 else if ( sElementName == "tracknum" ) 0366 { 0367 pCurrentTrack->setTrackNumber( childElement.text().toInt() ); 0368 } 0369 else if ( sElementName == "seconds" ) 0370 { 0371 pCurrentTrack->setLength( childElement.text().toInt() ); 0372 } 0373 else if ( sElementName == "moods" ) 0374 { 0375 parseMoods( childElement ); 0376 } 0377 } 0378 n = n.nextSibling(); 0379 } 0380 0381 pCurrentTrack->setMoods( m_currentTrackMoodList ); 0382 m_currentAlbumTracksList.append( pCurrentTrack ); 0383 0384 } 0385 0386 void MagnatuneXmlParser::parseMoods( const QDomElement &e ) 0387 { 0388 //DEBUG_BLOCK 0389 QDomNode n = e.firstChild(); 0390 0391 QDomElement childElement; 0392 0393 while ( !n.isNull() ) 0394 { 0395 0396 if ( n.isElement() ) 0397 { 0398 0399 childElement = n.toElement(); 0400 0401 QString sElementName = childElement.tagName(); 0402 0403 if ( sElementName == "mood" ) 0404 { 0405 m_currentTrackMoodList.append( childElement.text() ); 0406 } 0407 else 0408 { 0409 //error, should not be here.... 0410 } 0411 0412 } 0413 n = n.nextSibling(); 0414 } 0415 0416 } 0417 0418 void MagnatuneXmlParser::setDbHandler(MagnatuneDatabaseHandler * dbHandler) 0419 { 0420 m_dbHandler = dbHandler; 0421 } 0422 0423