[banshee] Implement random by album and artist (BGO #348582)



commit 1013f9f9ad81c4468a89ef0b74e60a6e84780d7d
Author: Gabriel Burt <gabriel burt gmail com>
Date:   Tue Jun 2 20:30:07 2009 -0500

    Implement random by album and artist (BGO #348582)
    
    The long-insensitive options for Shuffle by Artist and Album in the
    random dropdown are finally enabled!
---
 .../DatabaseTrackListModel.cs                      |  121 ++++++++++++++++++-
 .../Banshee.Collection/MemoryTrackListModel.cs     |    2 +-
 .../Banshee.Collection/TrackListModel.cs           |    2 +-
 .../PlaybackControllerService.cs                   |    7 +-
 .../Banshee.Gui/PlaybackShuffleActions.cs          |    2 -
 5 files changed, 119 insertions(+), 15 deletions(-)

diff --git a/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs b/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs
index 20a2c8d..fdd1f77 100644
--- a/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs
+++ b/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs
@@ -42,6 +42,7 @@ using Hyena.Query;
 using Banshee.Base;
 using Banshee.Query;
 using Banshee.Database;
+using Banshee.PlaybackController;
 
 namespace Banshee.Collection.Database
 {       
@@ -336,23 +337,34 @@ namespace Banshee.Collection.Database
             }
         }
 
+#region Get random methods
+
+        private const string random_condition = "AND LastStreamError = 0 AND (LastPlayedStamp < ? OR LastPlayedStamp IS NULL) AND (LastSkippedStamp < ? OR LastSkippedStamp IS NULL)";
+        private static string random_fragment = String.Format ("{0} ORDER BY RANDOM()", random_condition);
+        private static string random_by_album_fragment = String.Format ("AND CoreTracks.AlbumID = ? {0} ORDER BY DiscNumber ASC, TrackNumber ASC", random_condition);
+        private static string random_by_artist_fragment = String.Format ("AND CoreAlbums.ArtistID = ? {0} ORDER BY CoreAlbums.TitleSortKey ASC, DiscNumber ASC, TrackNumber ASC", random_condition);
+
         private DateTime random_began_at = DateTime.MinValue;
         private DateTime last_random = DateTime.MinValue;
-        private static string random_fragment = "AND (LastPlayedStamp < ? OR LastPlayedStamp IS NULL) AND (LastSkippedStamp < ? OR LastSkippedStamp IS NULL) ORDER BY RANDOM()";
-        public override TrackInfo GetRandom (DateTime notPlayedSince, bool repeat)
+        private int? random_album_id;
+        private int? random_artist_id;
+
+        public override TrackInfo GetRandom (DateTime notPlayedSince, PlaybackShuffleMode mode, bool repeat)
         {
             lock (this) {
-                if (Count == 0)
+                if (Count == 0) {
                     return null;
+                }
 
-                if (random_began_at < notPlayedSince)
+                if (random_began_at < notPlayedSince) {
                     random_began_at = last_random = notPlayedSince;
+                }
 
-                TrackInfo track = cache.GetSingle (random_fragment, random_began_at, random_began_at);
-
+                TrackInfo track = GetRandomTrack (mode, repeat);
                 if (track == null && repeat) {
                     random_began_at = last_random;
-                    track = cache.GetSingle (random_fragment, random_began_at, random_began_at);
+                    random_album_id = random_artist_id = null;
+                    track = GetRandomTrack (mode, repeat);
                 }
 
                 last_random = DateTime.Now;
@@ -360,6 +372,101 @@ namespace Banshee.Collection.Database
             }
         }
 
+        private TrackInfo GetRandomTrack (PlaybackShuffleMode mode, bool repeat)
+        {
+            if (mode == PlaybackShuffleMode.Album) {
+                random_artist_id = null;
+                if (random_album_id == null) {
+                    random_album_id = GetRandomAlbumId (random_began_at);
+                    if (random_album_id == null && repeat) {
+                        random_began_at = last_random;
+                        random_album_id = GetRandomAlbumId (random_began_at);
+                    }
+                }
+
+                if (random_album_id != null) {
+                    return cache.GetSingle (random_by_album_fragment, (int)random_album_id, random_began_at, random_began_at);
+                }
+            } else if (mode == PlaybackShuffleMode.Artist) {
+                random_album_id = null;
+                if (random_artist_id == null) {
+                    random_artist_id = GetRandomArtistId (random_began_at);
+                    if (random_artist_id == null && repeat) {
+                        random_began_at = last_random;
+                        random_artist_id = GetRandomArtistId (random_began_at);
+                    }
+                }
+
+                if (random_artist_id != null) {
+                    return cache.GetSingle (random_by_artist_fragment, (int)random_artist_id, random_began_at, random_began_at);
+                }
+            } else {
+                random_album_id = random_artist_id = null;
+            }
+
+            return cache.GetSingle (random_fragment, random_began_at, random_began_at);
+        }
+
+        private int? GetRandomAlbumId (DateTime stamp)
+        {
+            // Get a new Album that hasn't been played since y
+            int? album_id = null;
+            var reader = connection.Query (@"
+                    SELECT a.AlbumID, a.Title, MAX(t.LastPlayedStamp) as LastPlayed, MAX(t.LastSkippedStamp) as LastSkipped
+                    FROM CoreTracks t, CoreAlbums a, CoreCache c
+                    WHERE
+                        c.ModelID = ? AND
+                        t.TrackID = c.ItemID AND
+                        t.AlbumID = a.AlbumID AND
+                        t.LastStreamError = 0
+                    GROUP BY t.AlbumID
+                    HAVING
+                        (LastPlayed < ? OR LastPlayed IS NULL) AND
+                        (LastSkipped < ? OR LastSkipped IS NULL)
+                    ORDER BY RANDOM()
+                    LIMIT 1",
+                CacheId, stamp, stamp
+            );
+
+            if (reader.Read ()) {
+                album_id = Convert.ToInt32 (reader[0]);
+            }
+
+            reader.Dispose ();
+            return album_id;
+        }
+
+        private int? GetRandomArtistId (DateTime stamp)
+        {
+            // Get a new Artist that hasn't been played since y
+            int? artist_id = null;
+            var reader = connection.Query (@"
+                    SELECT a.ArtistID, a.ArtistName, MAX(t.LastPlayedStamp) as LastPlayed, MAX(t.LastSkippedStamp) as LastSkipped
+                    FROM CoreTracks t, CoreAlbums a, CoreCache c
+                    WHERE
+                        c.ModelID = ? AND
+                        t.TrackID = c.ItemID AND
+                        t.AlbumID = a.AlbumID AND
+                        t.LastStreamError = 0
+                    GROUP BY a.ArtistID
+                    HAVING
+                        (LastPlayed < ? OR LastPlayed IS NULL) AND
+                        (LastSkipped < ? OR LastSkipped IS NULL)
+                    ORDER BY RANDOM()
+                    LIMIT 1",
+                CacheId, stamp, stamp
+            );
+
+            if (reader.Read ()) {
+                artist_id = Convert.ToInt32 (reader[0]);
+            }
+
+            reader.Dispose ();
+            return artist_id;
+        }
+
+#endregion
+
         public override TrackInfo this[int index] {
             get {
                 lock (this) {
diff --git a/src/Core/Banshee.Services/Banshee.Collection/MemoryTrackListModel.cs b/src/Core/Banshee.Services/Banshee.Collection/MemoryTrackListModel.cs
index 75748c0..8f12c32 100644
--- a/src/Core/Banshee.Services/Banshee.Collection/MemoryTrackListModel.cs
+++ b/src/Core/Banshee.Services/Banshee.Collection/MemoryTrackListModel.cs
@@ -81,7 +81,7 @@ namespace Banshee.Collection
             get { lock (this) { return (index >= 0 && index < tracks.Count) ? tracks[index] : null; } }
         }
 
-        public override TrackInfo GetRandom (DateTime since, bool repeat)
+        public override TrackInfo GetRandom (DateTime since, Banshee.PlaybackController.PlaybackShuffleMode mode, bool repeat)
         {
             if (Count == 0)
                 return null;
diff --git a/src/Core/Banshee.Services/Banshee.Collection/TrackListModel.cs b/src/Core/Banshee.Services/Banshee.Collection/TrackListModel.cs
index 2201482..3b0e700 100644
--- a/src/Core/Banshee.Services/Banshee.Collection/TrackListModel.cs
+++ b/src/Core/Banshee.Services/Banshee.Collection/TrackListModel.cs
@@ -51,6 +51,6 @@ namespace Banshee.Collection
         
         public abstract int IndexOf (TrackInfo track);
 
-        public abstract TrackInfo GetRandom (DateTime notPlayedSince, bool repeat);
+        public abstract TrackInfo GetRandom (DateTime notPlayedSince, Banshee.PlaybackController.PlaybackShuffleMode mode, bool repeat);
     }
 }
diff --git a/src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs b/src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs
index f903542..da5fa71 100644
--- a/src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs
+++ b/src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs
@@ -311,7 +311,7 @@ namespace Banshee.PlaybackController
             Log.DebugFormat ("Querying model for track to play in {0}:{1} mode", ShuffleMode, direction);
             return ShuffleMode == PlaybackShuffleMode.Linear
                 ? QueryTrackLinear (direction, restart)
-                : QueryTrackRandom (restart);
+                : QueryTrackRandom (ShuffleMode, restart);
         }
         
         private TrackInfo QueryTrackLinear (Direction direction, bool restart)
@@ -340,10 +340,9 @@ namespace Banshee.PlaybackController
             }
         }
         
-        private TrackInfo QueryTrackRandom (bool restart)
+        private TrackInfo QueryTrackRandom (PlaybackShuffleMode mode, bool restart)
         {
-            return Source.TrackModel.GetRandom (source_set_at, restart);
-            //return Source.TrackModel[random.Next (0, Source.TrackModel.Count - 1)];
+            return Source.TrackModel.GetRandom (source_set_at, mode, restart);
         }
         
         private void QueuePlayTrack ()
diff --git a/src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackShuffleActions.cs b/src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackShuffleActions.cs
index faeec9c..983335d 100644
--- a/src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackShuffleActions.cs
+++ b/src/Core/Banshee.ThickClient/Banshee.Gui/PlaybackShuffleActions.cs
@@ -102,8 +102,6 @@ namespace Banshee.Gui
             this["ShuffleSongAction"].IconName = "media-playlist-shuffle";
             this["ShuffleArtistAction"].IconName = "media-playlist-shuffle";
             this["ShuffleAlbumAction"].IconName = "media-playlist-shuffle";
-            this["ShuffleArtistAction"].Sensitive = false;
-            this["ShuffleAlbumAction"].Sensitive = false;
 
             ServiceManager.PlaybackController.ShuffleModeChanged += OnShuffleModeChanged;
             ServiceManager.PlaybackController.SourceChanged += OnPlaybackSourceChanged;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]