extragear/multimedia/amarok/src

Seb Ruiz me at sebruiz.net
Wed Nov 15 08:26:49 UTC 2006


SVN commit 605064 by seb:

Here are some more fixes for the new dynamic mode. SmartPlaylist class has a new function, isTimeOrdered(), which will return true if the query is ordered based on a time criteria. This is especially important for dynamic playlists, because if we don't respect this then some playlists such as "Last Played" become meaningless. When we process a time based playlist, we don't change the order criteria, just grab the tracks and return a random selection from these to add to the cache. Conversely, there are some tracks such as "Never Played" which have ordering to ensure they are displayed alphabetically to the playlist. Since alphabetising is of no importance in dynamic mode, we can ignore it and just ORDER BY rand();.
Please comment if you think my logic is mistaken.

CCMAIL: amarok at kde.org
BUG: 137339


 M  +40 -20    dynamicmode.cpp  
 M  +12 -0     playlistbrowseritem.cpp  
 M  +5 -4      playlistbrowseritem.h  


--- trunk/extragear/multimedia/amarok/src/dynamicmode.cpp #605063:605064
@@ -223,21 +223,25 @@
         return KURL::List();
 
     bool useDirect = true;
+    const bool hasTimeOrder = item->isTimeOrdered();
+    debug() << "The smart playlist: " << item->name() << ", time order? " << hasTimeOrder << endl;
+
     QString sql = item->query();
 
     // FIXME: All this SQL magic out of collectiondb is not a good thing
-    // Many smart playlists require a special ordering in order to be effective (eg, last played).
-    // We respect this, so if there is no order by statement, we add a random ordering and use the result
-    // without further processing
+
+    // if there is no ordering, add random ordering
     if ( sql.find( QString("ORDER BY"), false ) == -1 )
     {
         QRegExp limit( "(LIMIT.*)?;$" );
-        sql.replace( limit, QString(" ORDER BY %1 LIMIT %2 OFFSET 0;").arg( CollectionDB::instance()->randomFunc() ).arg( songCount ) );
+        sql.replace( limit, QString(" ORDER BY %1 LIMIT %2 OFFSET 0;")
+                            .arg( CollectionDB::instance()->randomFunc() )
+                            .arg( songCount ) );
     }
     else
     {
-        // we don't want stupid limits such as LIMIT 5 OFFSET 0 which would return the same results always
-        uint first=0, limit=0;
+        uint limit=0, offset=0;
+
         QRegExp limitSearch( "LIMIT.*(\\d+).*OFFSET.*(\\d+)" );
         int findLocation = sql.find( limitSearch, false );
         if( findLocation == -1 ) //not found, let's find out the higher limit the hard way
@@ -253,25 +257,41 @@
         {   // There's a Limit, so we've got to respect it.
             limitSearch.search( sql );
             // capturedTexts() gives us the strings that were matched by each subexpression
-            first = limitSearch.capturedTexts()[2].toInt();
-            limit = limitSearch.capturedTexts()[1].toInt();
+            offset = limitSearch.capturedTexts()[2].toInt();
+            limit  = limitSearch.capturedTexts()[1].toInt();
         }
-        if ( limit <= songCount )
-            // The list is even smaller than the number of songs we want :-(
-            songCount = limit;
-        else
-            // Let's get a random limit, repecting the original one.
-            first += KApplication::random() % (limit - songCount);
 
-        if( findLocation == -1 ) // there is no limit
+        // we must be ordering by some other arbitrary query.
+        // we can scrap it, since it won't affect our result
+        if( !hasTimeOrder )
         {
-            QRegExp limit( ";$" );
-            sql.replace( limit, QString(" LIMIT %1 OFFSET %2;" ).arg( songCount*5 ).arg( first ) );
-            useDirect = false;
+            // We can mess with the limits if the smart playlist is not orderd by a time criteria
+            // Why? We can have a smart playlist which is ordered by name or by some other quality which
+            // is meaningless in dynamic mode
+            QRegExp orderLimit( "(ORDER BY.*)?;$" );
+
+            sql.replace( orderLimit, QString(" ORDER BY %1 LIMIT %2 OFFSET 0;")
+                                        .arg( CollectionDB::instance()->randomFunc() )
+                                        .arg( songCount ) );
         }
-        else
-            sql.replace( limitSearch, QString(" LIMIT %1 OFFSET %2;" ).arg( songCount ).arg( first ) );
+        else // time ordered criteria, only mess with the limits
+        {
+            debug() << "time based criteria used!" << endl;
+            if ( limit <= songCount ) // The list is even smaller than the number of songs we want :-(
+                songCount = limit;
+            else
+                // Let's get a random limit, repecting the original one.
+                offset += KApplication::random() % (limit - songCount);
 
+            if( findLocation == -1 ) // there is no limit
+            {
+                QRegExp queryEnd( ";$" ); // find the end of the query an add a limit
+                sql.replace( queryEnd, QString(" LIMIT %1 OFFSET %2;" ).arg( songCount*5 ).arg( offset ) );
+                useDirect = false;
+            }
+            else // there is a limit, so find it and replace it
+                sql.replace( limitSearch, QString(" LIMIT %1 OFFSET %2;" ).arg( songCount ).arg( offset ) );
+        }
     }
 
     // only return the fields that we need
--- trunk/extragear/multimedia/amarok/src/playlistbrowseritem.cpp #605063:605064
@@ -3427,7 +3427,19 @@
     m_dynamic = enable;
 }
 
+bool SmartPlaylist::isTimeOrdered()
+{
+    // matches statistics.createdate (firstplayed) and tags.createdate (modified date)
+    QRegExp createDate( "ORDER BY.*createdate" );
+    // matches last played
+    QRegExp accessDate( "ORDER BY.*accessdate" );
 
+    const QString sql = query();
+
+    return ! ( ( sql.find( createDate, false ) == -1 ) /*not create ordered*/ &&
+               ( sql.find( accessDate, false ) == -1 ) /*not access ordered*/ );
+}
+
 void SmartPlaylist::slotDoubleClicked()
 {
     if( !query().isEmpty() )
--- trunk/extragear/multimedia/amarok/src/playlistbrowseritem.h #605063:605064
@@ -543,11 +543,12 @@
                          const QString &urls, const QString &tags );
         SmartPlaylist( QListViewItem *parent, QListViewItem *after, const QDomElement &xmlDefinition );
 
-        bool        isDynamic()  const { return m_dynamic; }
-        bool        isEditable() const { return !m_xml.isNull(); }
+        bool        isDynamic()     const { return m_dynamic; }
+        bool        isEditable()    const { return !m_xml.isNull(); }
+        bool        isTimeOrdered(); //returns yes if the ordering is based on a time attribute
         QString     query();
-        QString     title()      const { return m_title; }
-        QDomElement xml()        const { return m_xml;   }
+        QString     title()         const { return m_title; }
+        QDomElement xml()           const { return m_xml;   }
 
         void  setDynamic( bool );
         void  setXml( const QDomElement &xml );



More information about the Amarok mailing list