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( &currentGenre );
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