extragear/multimedia/amarok/src/collection/sqlcollection

Seb Ruiz ruiz at kde.org
Sun Jun 8 14:46:23 CEST 2008


SVN commit 818371 by seb:

Implements cover art retrieval from the file system during a media scan. This creates a new database table `images` and augments the `albums` table to add a new column `image`.
Images are stored in the database but not yet retrieved by the Meta internals.

Max: is my implementation in line with how you imagined it would be done?

CCMAIL: amarok-devel at kde.org


 M  +27 -3     DatabaseUpdater.cpp  
 M  +16 -1     ScanManager.cpp  
 M  +55 -1     ScanResultProcessor.cpp  
 M  +4 -2      ScanResultProcessor.h  


--- trunk/extragear/multimedia/amarok/src/collection/sqlcollection/DatabaseUpdater.cpp #818370:818371
@@ -90,10 +90,12 @@
         QString c = "CREATE TEMPORARY TABLE albums_temp "
                     "(id " + m_collection->idType() +
                     ",name " + m_collection->textColumnType() + " NOT NULL"
-                    ",artist INTEGER);";
+                    ",artist INTEGER" +
+                    ",image INTEGER);";
         m_collection->query( c );
         m_collection->query( "CREATE INDEX albums_temp_name ON albums_temp(name);" );
         m_collection->query( "CREATE INDEX albums_temp_artist ON albums_temp(artist);" );
+        m_collection->query( "CREATE INDEX albums_temp_image ON albums_temp(image);" );
         m_collection->query( "CREATE UNIQUE INDEX albums_temp_name_artist ON albums_temp(name,artist);" );
         //the index below should not be necessary. uncomment if a query plan shows it is
         //m_collection->query( "CREATE UNIQUE INDEX albums_artist_name ON albums(artist,name);" );
@@ -120,6 +122,13 @@
         m_collection->query( "CREATE UNIQUE INDEX years_temp_name ON years_temp(name);" );
     }
     {
+        QString create = "CREATE TEMPORARY TABLE images_temp "
+                         "(id " + m_collection->idType() +
+                         ",path " + m_collection->textColumnType() + " NOT NULL);";
+        m_collection->query( create );
+        m_collection->query( "CREATE UNIQUE INDEX images_temp_name ON images_temp(path);" );
+    }
+    {
         QString c = "CREATE TEMPORARY TABLE tracks_temp "
                     "(id " + m_collection->idType() +
                     ",url INTEGER"
@@ -156,6 +165,7 @@
     m_collection->query( "INSERT INTO artists_temp SELECT * FROM artists;" );
     m_collection->query( "INSERT INTO years_temp SELECT * FROM years;" );
     m_collection->query( "INSERT INTO albums_temp SELECT * FROM albums;" );
+    m_collection->query( "INSERT INTO images_temp SELECT * FROM images;" );
     m_collection->query( "INSERT INTO genres_temp SELECT * FROM genres;" );
     m_collection->query( "INSERT INTO composers_temp SELECT * FROM composers;" );
     m_collection->query( "INSERT INTO tracks_temp SELECT * FROM tracks;" );
@@ -173,6 +183,7 @@
 {
     m_collection->query( "DELETE FROM composers;" );
     m_collection->query( "DELETE FROM genres;" );
+    m_collection->query( "DELETE FROM images;" );
     m_collection->query( "DELETE FROM albums;" );
     m_collection->query( "DELETE FROM years;" );
     m_collection->query( "DELETE FROM artists;" );
@@ -186,6 +197,7 @@
 {
     DEBUG_BLOCK
     m_collection->query( "DROP TABLE tracks_temp;" );
+    m_collection->query( "DROP TABLE images_temp;" );
     m_collection->query( "DROP TABLE albums_temp;" );
     m_collection->query( "DROP TABLE genres_temp;" );
     m_collection->query( "DROP TABLE years_temp;" );
@@ -209,6 +221,10 @@
         artistIds += artistId;
     }
     m_collection->insert( QString ( "INSERT INTO artists SELECT * FROM artists_temp WHERE artists_temp.id NOT IN ( %1 );" ).arg( artistIds ), QString() );
+   
+    //handle images before albums
+    m_collection->query( "DELETE FROM images;" );
+    m_collection->insert( "INSERT INTO images SELECT * FROM images_temp;", NULL );
 
     QStringList albumIdList = m_collection->query( "SELECT albums.id FROM albums;" );
     //in an empty database, albumIdList is empty. This would result in a SQL query like NOT IN ( ) without
@@ -248,7 +264,6 @@
     }
     m_collection->insert( QString ( "INSERT INTO years SELECT * FROM years_temp WHERE years_temp.id NOT IN ( %1 );" ).arg( yearIds ), QString() );
 
-    //insert( "INSERT INTO images SELECT * FROM images_temp;", NULL );
     //insert( "INSERT INTO embed SELECT * FROM embed_temp;", NULL );
     //m_collection->insert( "INSERT INTO directories SELECT * FROM directories_temp;", QString() );
     //insert( "INSERT INTO uniqueid SELECT * FROM uniqueid_temp;", NULL );
@@ -332,13 +347,22 @@
         m_collection->query( "CREATE UNIQUE INDEX artists_name ON artists(name);" );
     }
     {
+        QString create = "CREATE TABLE images "
+                         "(id " + m_collection->idType() +
+                         ",path " + m_collection->textColumnType() + " NOT NULL);";
+        m_collection->query( create );
+        m_collection->query( "CREATE UNIQUE INDEX images_name ON images(path);" );
+    }
+    {
         QString c = "CREATE TABLE albums "
                     "(id " + m_collection->idType() +
                     ",name " + m_collection->textColumnType() + " NOT NULL"
-                    ",artist INTEGER);";
+                    ",artist INTEGER" +
+                    ",image INTEGER);";
         m_collection->query( c );
         m_collection->query( "CREATE INDEX albums_name ON albums(name);" );
         m_collection->query( "CREATE INDEX albums_artist ON albums(artist);" );
+        m_collection->query( "CREATE INDEX albums_image ON albums(image);" );
         m_collection->query( "CREATE UNIQUE INDEX albums_name_artist ON albums(name,artist);" );
         //the index below should not be necessary. uncomment if a query plan shows it is
         //m_collection->query( "CREATE UNIQUE INDEX albums_artist_name ON albums(artist,name);" );
--- trunk/extragear/multimedia/amarok/src/collection/sqlcollection/ScanManager.cpp #818370:818371
@@ -115,7 +115,7 @@
     *m_scanner << dirs;
     m_scanner->setOutputChannelMode( KProcess::OnlyStdoutChannel );
     connect( m_scanner, SIGNAL( readyReadStandardOutput() ), this, SLOT( slotReadReady() ) );
-    connect( m_scanner, SIGNAL( finished( int ) ), SLOT( slotFinished(  ) ) );
+    connect( m_scanner, SIGNAL( finished( int ) ), SLOT( slotFinished() ) );
     connect( m_scanner, SIGNAL( error( QProcess::ProcessError ) ), SLOT( slotError( QProcess::ProcessError ) ) );
     m_scanner->start();
     if( m_parser )
@@ -486,6 +486,21 @@
                 {
                     //TODO handle playlist
                 }
+                else if( localname == "image" )
+                {
+                    QXmlStreamAttributes attrs = m_reader.attributes();
+                    debug() << "Received an image tag: " << attrs.value( "list" ).toString() << " : " << attrs.value( "path" ).toString();
+                    // Deserialize CoverBundle list
+                    QStringList list = attrs.value( "list" ).toString().split( "AMAROK_MAGIC" );
+                    QList< QPair<QString, QString> > covers;
+                    
+                    for( int i = 0; i < list.count(); i += 2 )
+                        covers += qMakePair( list[i], list[i + 1] );
+
+                    debug() << "Adding image: " << attrs.value( "path" ).toString();
+                    processor.addImage( attrs.value( "path" ).toString(), covers );
+                    debug() << "Image added!";
+                }
             }
         }
     }
--- trunk/extragear/multimedia/amarok/src/collection/sqlcollection/ScanResultProcessor.cpp #818370:818371
@@ -1,5 +1,6 @@
 /*
  *  Copyright (c) 2007 Maximilian Kossick <maximilian.kossick at googlemail.com>
+ *  Copyright (c) 2008 Seb Ruiz <ruiz at kde.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -81,6 +82,25 @@
     }
 }
 
+void 
+ScanResultProcessor::addImage( const QString &path, const QList< QPair<QString, QString> > covers )
+{
+    QList< QPair<QString,QString> >::ConstIterator it = covers.begin();
+    for( ; it != covers.end(); it++ )
+    {
+        QPair<QString,QString> key = (*it);
+        if( key.first.isEmpty() || key.second.isEmpty() )
+            continue;
+
+        int artist = artistId( key.first );
+        int album  = albumId( key.second, artist );
+       
+        // Will automatically add the image path to the database
+        int image  = imageId( path, album );
+        debug() << "Added image id " << image << " with path: " << path;
+    }
+}
+
 void
 ScanResultProcessor::commit()
 {
@@ -240,7 +260,6 @@
 void
 ScanResultProcessor::addTrack( const QVariantMap &trackData, int albumArtistId )
 {
-
     //amarok 1 stored all tracks of a compilation in different directories.
     //when using its "Organize Collection" feature
     //try to detect these cases
@@ -380,6 +399,41 @@
     }
 }
 
+int
+ScanResultProcessor::imageId( const QString &image, int albumId )
+{
+    DEBUG_BLOCK
+    // assume the album is valid
+    if( albumId < 0 )
+        return -1;
+
+    QPair<QString, int> key( image, albumId );
+    if( m_images.contains( key ) )
+        return m_images.value( key );
+
+    QString query = QString( "SELECT images_temp.id FROM images_temp INNER JOIN albums_temp ON albums_temp.image = images_temp.id WHERE images_temp.path = '%1' AND albums_temp.id = %2;" )
+                        .arg( m_collection->escape( image ) ).arg( QString::number( albumId ) );
+    QStringList res = m_collection->query( query );
+    if( res.isEmpty() )
+    {
+        QString insert = QString( "INSERT INTO images_temp( path ) VALUES ('%1');" ).arg( m_collection->escape( image ) );
+        int id = m_collection->insert( insert, "images_temp" );
+        m_images.insert( key, id );
+
+        // Make sure the album table is up to date
+        QString update = QString( "UPDATE albums_temp SET image = %1 WHERE id = %2" )
+                            .arg( QString::number( id ) ).arg( QString::number( albumId ) );
+        m_collection->query( update );
+        return id;
+    }
+    else
+    {
+        int id = res[0].toInt();
+        m_images.insert( key, id );
+        return id;
+    }
+}
+
 int 
 ScanResultProcessor::albumId( const QString &album, int artistId )
 {
--- trunk/extragear/multimedia/amarok/src/collection/sqlcollection/ScanResultProcessor.h #818370:818371
@@ -1,5 +1,6 @@
 /*
  *  Copyright (c) 2007 Maximilian Kossick <maximilian.kossick at googlemail.com>
+ *  Copyright (c) 2008 Seb Ruiz <ruiz at kde.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -30,7 +31,6 @@
 
 class ScanResultProcessor
 {
-
     public:
         enum ScanType
         {
@@ -42,19 +42,20 @@
         ~ScanResultProcessor();
 
         void addDirectory( const QString &dir, uint mtime );
+        void addImage( const QString &path, const QList< QPair<QString, QString> > );
         void setScanType( ScanType type );
         void processDirectory( const QList<QVariantMap > &data );
         void commit();
         void rollback();
 
     private:
-
         void addTrack( const QVariantMap &trackData, int albumArtistId );
 
         int artistId( const QString &artist );
         int genreId( const QString &genre );
         int composerId( const QString &composer );
         int yearId( const QString &year );
+        int imageId( const QString &image, int albumId );
         int albumId( const QString &album, int artistId );
         int urlId( const QString &url );
         int directoryId( const QString &dir );
@@ -73,6 +74,7 @@
         QMap<QString, int> m_year;
         QMap<QString, int> m_composer;
         QMap<QPair<QString, int>, int> m_albums;
+        QMap<QPair<QString, int>, int> m_images;
         QMap<QString, int> m_directories;
 
         QHash<QString, uint> m_filesInDirs;


More information about the Amarok-devel mailing list