Bug 249395 - Wrong sort order in m3u playlist
Summary: Wrong sort order in m3u playlist
Status: RESOLVED FIXED
Alias: None
Product: k3b
Classification: Applications
Component: Audio Project (show other bugs)
Version: 2.0.1
Platform: openSUSE Linux
: NOR normal
Target Milestone: ---
Assignee: Michał Małek
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-08-29 12:39 UTC by helmut.suessmuth
Modified: 2012-04-11 23:09 UTC (History)
4 users (show)

See Also:
Latest Commit:
Version Fixed In: 2.0.2


Attachments
screen shots (742.47 KB, application/vnd.oasis.opendocument.text)
2010-08-29 12:41 UTC, helmut.suessmuth
Details

Note You need to log in before you can comment on or make changes to this bug.
Description helmut.suessmuth 2010-08-29 12:39:47 UTC
Version:           unspecified (using KDE 4.4.4) 
OS:                Linux

After ripping with k3b the playlist file contains the tracks in the wrong sort order.

Example: Ripping CD "Motörhead, Speed Not Comfort, Disc 1" with k3b (output format mp3 with playlist m3u)
Expected: sort order of tracks in playlist as on CD, starting with "Shoot You In The Back" followed by "Dirty Love" and so on.
What I get is a completely different order:
#EXTM3U
#EXTINF:252,Motörhead - Nightmare
Motörhead/Speed Not Comfort (Disc 1)/Nightmare.mp3
#EXTINF:293,Motörhead - Dirty Love
Motörhead/Speed Not Comfort (Disc 1)/Dirty Love.mp3
#EXTINF:233,Motörhead - Treat Me Nice
Motörhead/Speed Not Comfort (Disc 1)/Treat Me Nice.mp3
#EXTINF:191,Motörhead - Shoot You In The Back
Motörhead/Speed Not Comfort (Disc 1)/Shoot You In The Back.mp3
#EXTINF:223,Motörhead - Bump On Your Back
Motörhead/Speed Not Comfort (Disc 1)/Bump On Your Back.mp3
#EXTINF:216,Motörhead - Bomber
Motörhead/Speed Not Comfort (Disc 1)/Bomber.mp3
#EXTINF:220,Motörhead - Waltz Of The Vampire
Motörhead/Speed Not Comfort (Disc 1)/Waltz Of The Vampire.mp3
#EXTINF:255,Motörhead - Love Me Like A Reptile
Motörhead/Speed Not Comfort (Disc 1)/Love Me Like A Reptile.mp3
#EXTINF:275,Motörhead - Stone Dead Forever
Motörhead/Speed Not Comfort (Disc 1)/Stone Dead Forever.mp3
#EXTINF:186,Motörhead - Fast  And Loose
Motörhead/Speed Not Comfort (Disc 1)/Fast  And Loose.mp3
#EXTINF:191,Motörhead - You Ain't Gonna Live Forever
Motörhead/Speed Not Comfort (Disc 1)/You Ain't Gonna Live Forever.mp3
#EXTINF:196,Motörhead - Sharpshooter
Motörhead/Speed Not Comfort (Disc 1)/Sharpshooter.mp3
#EXTINF:210,Motörhead - Love Me Like A Reptile (Alternative Version)
Motörhead/Speed Not Comfort (Disc 1)/Love Me Like A Reptile (Alternative Version).mp3
#EXTINF:191,Motörhead - The Hammer
Motörhead/Speed Not Comfort (Disc 1)/The Hammer.mp3


Devices
-----------------------
HL-DT-ST DVDRAM GH22LS50 TL01 (/dev/sr0, CD-R, CD-RW, CD-ROM, DVD-ROM, DVD-R, DVD-RW, DVD-R doppelschichtig, DVD+R, DVD+RW, DVD+R doppelschichtig) [DVD-ROM, DVD-R sequenziell, Zweischichtige DVD-R sequenziell, Zweischicht-DVD-R-Sprung, DVD-RAM, DVD-RW Eingeschränktes Überbrennen, DVD-RW sequenziell, DVD+RW, DVD+R, Zweischichtige DVD+R, CD-ROM, CD-R, CD-RW] [SAO, TAO, RAW, SAO/R96P, SAO/R96R, RAW/R16, RAW/R96P, RAW/R96R, Eingeschränktes Überschreiben, Sprung zwischen DVD-Schichten] [%7]

System
-----------------------
K3b Version: 2.0.1
KDE Version: 4.4.4 (KDE 4.4.4) "release 2"
QT Version:  4.6.3
Kernel:      2.6.34-12-desktop

Reproducible: Always

Steps to Reproduce:
Ripping the same CD twice.
Note: This behavior is new and not previously occurred with older versions!

Actual Results:  
#EXTM3U
#EXTINF:252,Motörhead - Nightmare
Motörhead/Speed Not Comfort (Disc 1)/Nightmare.mp3
#EXTINF:293,Motörhead - Dirty Love
Motörhead/Speed Not Comfort (Disc 1)/Dirty Love.mp3
#EXTINF:233,Motörhead - Treat Me Nice
Motörhead/Speed Not Comfort (Disc 1)/Treat Me Nice.mp3
#EXTINF:191,Motörhead - Shoot You In The Back
Motörhead/Speed Not Comfort (Disc 1)/Shoot You In The Back.mp3
#EXTINF:223,Motörhead - Bump On Your Back
Motörhead/Speed Not Comfort (Disc 1)/Bump On Your Back.mp3
#EXTINF:216,Motörhead - Bomber
Motörhead/Speed Not Comfort (Disc 1)/Bomber.mp3
#EXTINF:220,Motörhead - Waltz Of The Vampire
Motörhead/Speed Not Comfort (Disc 1)/Waltz Of The Vampire.mp3
#EXTINF:255,Motörhead - Love Me Like A Reptile
Motörhead/Speed Not Comfort (Disc 1)/Love Me Like A Reptile.mp3
#EXTINF:275,Motörhead - Stone Dead Forever
Motörhead/Speed Not Comfort (Disc 1)/Stone Dead Forever.mp3
#EXTINF:186,Motörhead - Fast  And Loose
Motörhead/Speed Not Comfort (Disc 1)/Fast  And Loose.mp3
#EXTINF:191,Motörhead - You Ain't Gonna Live Forever
Motörhead/Speed Not Comfort (Disc 1)/You Ain't Gonna Live Forever.mp3
#EXTINF:196,Motörhead - Sharpshooter
Motörhead/Speed Not Comfort (Disc 1)/Sharpshooter.mp3
#EXTINF:210,Motörhead - Love Me Like A Reptile (Alternative Version)
Motörhead/Speed Not Comfort (Disc 1)/Love Me Like A Reptile (Alternative Version).mp3
#EXTINF:191,Motörhead - The Hammer
Motörhead/Speed Not Comfort (Disc 1)/The Hammer.mp3

Expected Results:  
Expected: sort order of tracks in playlist as on CD, starting with "Shoot You In The Back" followed by "Dirty Love", "Bump On Your Back", "Love Me Like A Reptile" and so on.

See screen shots in attached file.
Comment 1 helmut.suessmuth 2010-08-29 12:41:40 UTC
Created attachment 51079 [details]
screen shots
Comment 2 Nicos Gollan 2010-11-27 15:36:03 UTC
I can confirm this with k3b 2.0.1 from Debian unstable. Generated playlists are more or less randomly sorted.
Comment 3 Bill Wayson 2010-12-17 21:35:43 UTC
I can confirm this in 32-bit openSUSE 11.3, k3b version 2.0.1 from packman.links2linux.de (2.0.1-1.pm.2.36-i586), kde 4.4.4 "release 3", qt4 4.6.3, and kernel 2.6.34.7-0.5-desktop.  The sorting does appear to be random even though the songs are ripped in track order.  If it matters, the songs were saved in flac format.
Comment 4 Michał Małek 2010-12-21 09:16:37 UTC
commit 36bd5a3863677271f4e8d38679e8c7465e0e2622
branch 2.0
Author: Michal Malek <michalm@jabster.pl>
Date:   Tue Dec 21 09:11:39 2010 +0100

    Fixed playlist sort order
    BUG: 249395

diff --git a/ChangeLog b/ChangeLog
index 15c2e4a..0d92c68 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -7,6 +7,7 @@ Bugfixes:
  * Crash on closing dialog after succesful audio CD ripping (241630)
  * Crash on device detection (249371)
  * Crash when showing settings window (238819)
+ * Fixed playlist sort order (249395)
 
 2.0.1
 =====
diff --git a/src/rip/k3baudioripjob.cpp b/src/rip/k3baudioripjob.cpp
index beae533..74d9060 100644
--- a/src/rip/k3baudioripjob.cpp
+++ b/src/rip/k3baudioripjob.cpp
@@ -40,6 +40,22 @@
 #include <KStandardDirs>
 
 
+namespace
+{
+
+    struct SortByTrackNumber
+    {
+        SortByTrackNumber( K3b::AudioRipJob::Tracks const& tracks ) : m_tracks( tracks ) {}
+
+        bool operator()( QString const& lhs, QString const& rhs )
+        {
+            return m_tracks.value( lhs ) < m_tracks.value( rhs );
+        }
+
+        K3b::AudioRipJob::Tracks const& m_tracks;
+    };
+
+} // namespace
 
 
 class K3b::AudioRipJob::Private
@@ -242,7 +258,7 @@ bool K3b::AudioRipJob::run()
     d->overallSectorsRead = 0;
     d->overallSectorsToRead = 0;
     d->lengths.clear();
-    
+
     Q_FOREACH( const QString& filename, d->tracks.keys().toSet() ) {
         d->lengths.insert( filename, 0 );
         Q_FOREACH( int track, d->tracks.values( filename ) ) {
@@ -263,7 +279,7 @@ bool K3b::AudioRipJob::run()
         }
         lastFilename = d->currentTrack.key();
     }
-    
+
     if( d->encoder ) {
         d->encoder->closeFile();
     }
@@ -312,7 +328,7 @@ bool K3b::AudioRipJob::ripTrack( int track, const QString& filename, const QStri
             emit infoMessage( i18n("Unable to create folder %1", dir), K3b::Job::MessageError );
             return false;
         }
-        
+
         // Close the previous file if the new filename is different
         if( prevFilename != filename ) {
             if( d->encoder )
@@ -343,7 +359,7 @@ bool K3b::AudioRipJob::ripTrack( int track, const QString& filename, const QStri
                     metaData.insert( AudioEncoder::META_TRACK_TITLE, d->cddbEntry.get( KCDDB::Title ) );
                     metaData.insert( AudioEncoder::META_TRACK_COMMENT, d->cddbEntry.get( KCDDB::Comment ) );
                 }
-                
+
                 isOpen = d->encoder->openFile( d->fileType, filename, d->lengths[ filename ], metaData );
                 if( !isOpen )
                     emit infoMessage( d->encoder->lastErrorString(), K3b::Job::MessageError );
@@ -433,14 +449,19 @@ bool K3b::AudioRipJob::writePlaylist()
         // format descriptor
         t << "#EXTM3U" << endl;
 
-        Q_FOREACH( const QString& filename, d->tracks.keys().toSet() ) {
-            
+        // Get list of the ripped filenames sorted by track number
+        QStringList filenames = d->tracks.keys();
+        filenames.removeDuplicates();
+        qSort( filenames.begin(), filenames.end(), SortByTrackNumber( d->tracks ) );
+
+        Q_FOREACH( const QString& filename, filenames ) {
+
             // extra info
             t << "#EXTINF:" << d->lengths[filename].totalFrames()/75 << ",";
-            
+
             QVariant artist;
             QVariant title;
-        
+
             QList<int> trackNums = d->tracks.values( filename );
             if( trackNums.count() == 1 ) {
                 int trackIndex = trackNums.first()-1;
@@ -451,7 +472,7 @@ bool K3b::AudioRipJob::writePlaylist()
                 artist = d->cddbEntry.get( KCDDB::Artist );
                 title = d->cddbEntry.get( KCDDB::Title );
             }
-            
+
             if( !artist.toString().isEmpty() && !title.toString().isEmpty() ) {
                 t << artist.toString() << " - " << title.toString() << endl;
             }
@@ -460,7 +481,7 @@ bool K3b::AudioRipJob::writePlaylist()
                                   filename.length() - filename.lastIndexOf('/') - 5)
                 << endl; // filename without extension
             }
-        
+
             // filename
             if( d->relativePathInPlaylist )
                 t << findRelativePath( filename, playlistDir ) << endl;
@@ -490,7 +511,7 @@ bool K3b::AudioRipJob::writeCueFile()
         text.setPerformer( d->cddbEntry.get( KCDDB::Artist ).toString() );
         text.setTitle( d->cddbEntry.get( KCDDB::Title ).toString() );
         K3b::Msf currentSector;
-        
+
         QList<int> trackNums = d->tracks.values( filename );
         for( int i = 0; i < trackNums.size(); ++i ) {
             int trackNum = trackNums[ i ];
@@ -510,7 +531,7 @@ bool K3b::AudioRipJob::writeCueFile()
         // we always use a relative filename here
         QString imageFile = filename.section( '/', -1 );
         cueWriter.setImage( imageFile, ( d->fileType.isEmpty() ? QString("WAVE") : d->fileType ) );
-        
+
         // use the same base name as the image file
         QString cueFile = filename;
         cueFile.truncate( cueFile.lastIndexOf('.') );
Comment 5 Michał Małek 2010-12-21 09:16:38 UTC
commit 1894adad227f87a55c6bc650dc5ef7a605c045bd
branch master
Author: Michal Malek <michalm@jabster.pl>
Date:   Tue Dec 21 09:11:39 2010 +0100

    Fixed playlist sort order
    BUG: 249395

diff --git a/ChangeLog b/ChangeLog
index ba6ccaf..de69f3b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -17,6 +17,7 @@ Bugfixes:
  * Crash on closing dialog after succesful audio CD ripping (241630)
  * Crash on device detection (249371)
  * Crash when showing settings window (238819)
+ * Fixed playlist sort order (249395)
 
 2.0.1
 =====
diff --git a/src/rip/k3baudioripjob.cpp b/src/rip/k3baudioripjob.cpp
index beae533..74d9060 100644
--- a/src/rip/k3baudioripjob.cpp
+++ b/src/rip/k3baudioripjob.cpp
@@ -40,6 +40,22 @@
 #include <KStandardDirs>
 
 
+namespace
+{
+
+    struct SortByTrackNumber
+    {
+        SortByTrackNumber( K3b::AudioRipJob::Tracks const& tracks ) : m_tracks( tracks ) {}
+
+        bool operator()( QString const& lhs, QString const& rhs )
+        {
+            return m_tracks.value( lhs ) < m_tracks.value( rhs );
+        }
+
+        K3b::AudioRipJob::Tracks const& m_tracks;
+    };
+
+} // namespace
 
 
 class K3b::AudioRipJob::Private
@@ -242,7 +258,7 @@ bool K3b::AudioRipJob::run()
     d->overallSectorsRead = 0;
     d->overallSectorsToRead = 0;
     d->lengths.clear();
-    
+
     Q_FOREACH( const QString& filename, d->tracks.keys().toSet() ) {
         d->lengths.insert( filename, 0 );
         Q_FOREACH( int track, d->tracks.values( filename ) ) {
@@ -263,7 +279,7 @@ bool K3b::AudioRipJob::run()
         }
         lastFilename = d->currentTrack.key();
     }
-    
+
     if( d->encoder ) {
         d->encoder->closeFile();
     }
@@ -312,7 +328,7 @@ bool K3b::AudioRipJob::ripTrack( int track, const QString& filename, const QStri
             emit infoMessage( i18n("Unable to create folder %1", dir), K3b::Job::MessageError );
             return false;
         }
-        
+
         // Close the previous file if the new filename is different
         if( prevFilename != filename ) {
             if( d->encoder )
@@ -343,7 +359,7 @@ bool K3b::AudioRipJob::ripTrack( int track, const QString& filename, const QStri
                     metaData.insert( AudioEncoder::META_TRACK_TITLE, d->cddbEntry.get( KCDDB::Title ) );
                     metaData.insert( AudioEncoder::META_TRACK_COMMENT, d->cddbEntry.get( KCDDB::Comment ) );
                 }
-                
+
                 isOpen = d->encoder->openFile( d->fileType, filename, d->lengths[ filename ], metaData );
                 if( !isOpen )
                     emit infoMessage( d->encoder->lastErrorString(), K3b::Job::MessageError );
@@ -433,14 +449,19 @@ bool K3b::AudioRipJob::writePlaylist()
         // format descriptor
         t << "#EXTM3U" << endl;
 
-        Q_FOREACH( const QString& filename, d->tracks.keys().toSet() ) {
-            
+        // Get list of the ripped filenames sorted by track number
+        QStringList filenames = d->tracks.keys();
+        filenames.removeDuplicates();
+        qSort( filenames.begin(), filenames.end(), SortByTrackNumber( d->tracks ) );
+
+        Q_FOREACH( const QString& filename, filenames ) {
+
             // extra info
             t << "#EXTINF:" << d->lengths[filename].totalFrames()/75 << ",";
-            
+
             QVariant artist;
             QVariant title;
-        
+
             QList<int> trackNums = d->tracks.values( filename );
             if( trackNums.count() == 1 ) {
                 int trackIndex = trackNums.first()-1;
@@ -451,7 +472,7 @@ bool K3b::AudioRipJob::writePlaylist()
                 artist = d->cddbEntry.get( KCDDB::Artist );
                 title = d->cddbEntry.get( KCDDB::Title );
             }
-            
+
             if( !artist.toString().isEmpty() && !title.toString().isEmpty() ) {
                 t << artist.toString() << " - " << title.toString() << endl;
             }
@@ -460,7 +481,7 @@ bool K3b::AudioRipJob::writePlaylist()
                                   filename.length() - filename.lastIndexOf('/') - 5)
                 << endl; // filename without extension
             }
-        
+
             // filename
             if( d->relativePathInPlaylist )
                 t << findRelativePath( filename, playlistDir ) << endl;
@@ -490,7 +511,7 @@ bool K3b::AudioRipJob::writeCueFile()
         text.setPerformer( d->cddbEntry.get( KCDDB::Artist ).toString() );
         text.setTitle( d->cddbEntry.get( KCDDB::Title ).toString() );
         K3b::Msf currentSector;
-        
+
         QList<int> trackNums = d->tracks.values( filename );
         for( int i = 0; i < trackNums.size(); ++i ) {
             int trackNum = trackNums[ i ];
@@ -510,7 +531,7 @@ bool K3b::AudioRipJob::writeCueFile()
         // we always use a relative filename here
         QString imageFile = filename.section( '/', -1 );
         cueWriter.setImage( imageFile, ( d->fileType.isEmpty() ? QString("WAVE") : d->fileType ) );
-        
+
         // use the same base name as the image file
         QString cueFile = filename;
         cueFile.truncate( cueFile.lastIndexOf('.') );
Comment 6 AndyTZZ 2012-04-11 23:09:39 UTC
HI. 
Is failing again, but this time ripping from a CD works fine. The problem is when convertion process is from a CD image compressed in flac, let say CDImage.flac file with its CDimage.cue file, to a list of separated ogg/mp3 files. in this case the order of songs in the m3u file is still wrong.

Thank!!