Bug 113120

Summary: Dynamic playlist (playlist shuffle) weighted by number of songs
Product: [Applications] amarok Reporter: bonne
Component: Playlists/Saved PlaylistsAssignee: Amarok Developers <amarok-bugs-dist>
Status: RESOLVED FIXED    
Severity: wishlist CC: leon, matt+kde-bugs
Priority: NOR    
Version: 1.3.2   
Target Milestone: ---   
Platform: unspecified   
OS: Linux   
Latest Commit: Version Fixed In:
Attachments: patch to 1.3.2 to select playlists weighted by number of songs in each
Patch to 1.4-beta1 to weight playlists by number of songs

Description bonne 2005-09-23 05:02:40 UTC
Version:           1.3.2 (using KDE 3.4.1, Gentoo)
Compiler:          gcc version 3.4.3 20041125 (Gentoo 3.4.3-r1, ssp-3.4.3-0, pie-8.7.7)
OS:                Linux (x86_64) release 2.6.12-gentoo-r4

The playlist shuffle mode of dynamic playlist is very good but when adding a song it randomly selects a playlist then a song (so you get songs from short playlists much more often than songs from long playlists). 
The suggestion is to select a playlist weighted by the number of songs in that list (so that each song in the pool of songs is evenly weighted).
Comment 1 bonne 2005-09-26 14:01:41 UTC
Created attachment 12708 [details]
patch to 1.3.2 to select playlists weighted by number of songs in each

I knocked up a little patch which does exactly as I mentioned above. 
It tests the number of songs in each of the potential playlists, then randomly
chooses a number out of the total, then figures out which playlist that
corresponds to, then randomly chooses songs from that playlist. 

Ideally we could implement this such that if we are choosing more than one song
they can come from different playlists. The trick is getting it to happen
without taking too much time. 

If you are testing this patch, consider implementing a way to cache the number
of songs in smart playlists (this would significantly increase the speed by
avoiding a number of select statements every time we want to add a song).
Comment 2 bonne 2006-02-17 13:55:51 UTC
This problem is still present in 1.4-beta1
Comment 3 bonne 2006-02-21 14:41:25 UTC
Created attachment 14796 [details]
Patch to 1.4-beta1 to weight playlists by number of songs

Basically the same as before, but count() is replaced with count(url).
Comment 4 Alexandre Oliveira 2006-09-01 01:45:21 UTC
*** Bug 133336 has been marked as a duplicate of this bug. ***
Comment 5 Christian Schaarschmidt 2006-11-11 16:48:45 UTC
it would be great if the percentage could be defined by the user not only by the lenght of the playlist. e.g. 15% HipHop; 30% Pop; Rest Rock.

Furthermore, dynamic list within dynamic list and shufle between lists only:
usage:
- dynamic list based on my favorites
- ordered list by last played
both combined into:
90% favorites (random play); 10% last played (oldest first)

That would also cover Bug 124763.
Comment 6 Seb Ruiz 2006-11-13 01:15:29 UTC
SVN commit 604494 by seb:

Refactor of dynamic mode. This revised implementation solves a number of bugs. The logic of adding tracks from a dynamic mode is now delegated to the DynamicMode object, and is not done within the playlist. When a dynamic mode is loaded, a cache of 200 elements is create from the playlist sources. By caching a subset of the possible tracks to be inserted, there is no longer a requirement to execute complex SQL statements on each track change or playlist repopulation. Additionally, by grabbing random tracks from this cache, items are no longer fetched from just one source, but all of them. Once these cached tracks have been inserted into the playlist, they are removed from the cache list in order to avoid duplicating song insertions. Once the cache has been depleted, it is simply regenerated. 200 elements is approximately 12 hours worth of music, so the set should be sufficiently large to handle the user's requirements.

I've done quite a bit of regression testing, but the more the merrier :). The only feature which needs to be fixed is the Suggested mode of dynamic playlists, but this should be easily rectifiable.

BUG: 134159
BUG: 137212
BUG: 107693
BUG: 130542
BUG: 133269
BUG: 113120


 M  +233 -14   dynamicmode.cpp  
 M  +51 -6     dynamicmode.h  
 M  +12 -204   playlist.cpp  
 M  +3 -4      playlist.h  
 M  +1 -1      playlistbrowser.cpp  
Comment 7 bonne 2006-11-13 02:27:30 UTC
Is this cache really weighted by playlist length? It doesn't seem so. 
Comment 8 Seb Ruiz 2006-11-13 02:47:01 UTC
Yes, the creation of the cache does the weighting
Comment 9 bonne 2006-11-13 03:07:14 UTC
Looking at line 139 of dynamicmode.cpp:

const int itemsPerSource = CACHE_SIZE / dynamicEntries.count();

It looks like the number of items added per source is constant. I can confirm that a dynamic playlist which chooses 2 sources - one with 72 tracks and the other with 4963 tracks produces a dynamic playlist with a roughly even number of each. 
Comment 10 Seb Ruiz 2006-11-13 03:24:07 UTC
Right, I think i misunderstood you. I'll have a think about this and
the best way of doing this.

On 13 Nov 2006 02:07:15 -0000, Bonne Eggleston <b.eggleston@gmail.com> wrote:
[bugs.kde.org quoted mail]
Comment 11 bonne 2006-11-13 03:45:55 UTC
The way I did it in previous patches, was to find the total number of songs (add the length of each list together) and then randomly choose a list based on a weighted random number.
You could do a similar thing where you add length*CACHE_SIZE/total_length songs for each list when you rebuild the list. 
I would then add 1 if this number is 0 (because of integer division), so that small playlists don't always miss out. 
Comment 12 Seb Ruiz 2006-11-13 08:29:07 UTC
And how did you do it when there was a combination of static and smart playlists?

smart playlists don't have a defined number of elements.
Comment 13 bonne 2006-11-13 08:36:39 UTC
I calculated the number of items in the smart playlist. From my original patch:

+//This subs the select part of the smart playlist sql statement for a count, then counts!
+int SmartPlaylist::length()
+{
+	QString sql = m_sqlForTags;
+	sql.replace(QRegExp("SELECT.*FROM",false), "SELECT COUNT(url) FROM");
+
+	QStringList result = CollectionDB::instance()->query(sql);
+	
+	if ( ! result.isEmpty())
+		return result.first().toInt();
+	else return 0;
+}
+
Comment 14 bonne 2006-11-28 08:57:25 UTC
I submitted a change to SVN which has this functionality. Please test and let me know how it works for you. 
Comment 15 Alexandre Oliveira 2006-11-28 18:09:01 UTC
Reopen if necessary.
Comment 16 Kevin Funk 2007-02-05 01:20:11 UTC
*** Bug 124763 has been marked as a duplicate of this bug. ***