banshee r3749 - in trunk/banshee: . src/Core/Banshee.Services/Banshee.Collection src/Core/Banshee.Services/Banshee.Collection.Database src/Core/Banshee.Services/Banshee.MediaEngine src/Core/Banshee.Services/Banshee.PlaybackController src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue src/Libraries/Hyena/Hyena.Data.Sqlite



Author: gburt
Date: Thu Apr 10 09:50:53 2008
New Revision: 3749
URL: http://svn.gnome.org/viewvc/banshee?rev=3749&view=rev

Log:
2008-04-10  Gabriel Burt  <gabriel burt gmail com>

	* src/Core/Banshee.Services/Banshee.Collection/TrackListModel.cs:
	* src/Core/Banshee.Services/Banshee.Collection/MemoryTrackListModel.cs:
	* src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs:
	Implement GetRandom method, using SQL for DatabaseTrackListModel.

	* src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs:
	Move IncrementPlay/SkipCount logic into public IncrementLastPlayed method.

	* src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs:
	Cann IncrementLastPlayed before getting the next song since that affects
	the random query method.  Fix repeat/restart in linear query.  Change
	QueryTrackRandom to call GetRandom on TrackModel.

	* src/Core/Banshee.Services/Banshee.PlaybackController/IBasicPlaybackController.cs:
	* src/Core/Banshee.Services/Banshee.PlaybackController/ICanonicalPlaybackController.cs:
	* src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs:
	Add restart arg to Previous.

	* src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelCache.cs: Add GetSingle
	method that can be passed a condition/order by fragment and returns one
	item.


Modified:
   trunk/banshee/ChangeLog
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/MemoryTrackListModel.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/TrackListModel.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.PlaybackController/IBasicPlaybackController.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.PlaybackController/ICanonicalPlaybackController.cs
   trunk/banshee/src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs
   trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs
   trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelCache.cs

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs	Thu Apr 10 09:50:53 2008
@@ -310,6 +310,28 @@
             return (int) (db_track == null ? -1 : cache.IndexOf ((int)db_track.TrackId));
         }
 
+        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)
+        {
+            if (Count == 0)
+                return null;
+
+            if (random_began_at < notPlayedSince)
+                random_began_at = last_random = notPlayedSince;
+
+            TrackInfo track = cache.GetSingle (random_fragment, random_began_at, random_began_at);
+
+            if (track == null && repeat) {
+                random_began_at = last_random;
+                track = cache.GetSingle (random_fragment, random_began_at, random_began_at);
+            }
+
+            last_random = DateTime.Now;
+            return track;
+        }
+
         public override TrackInfo this[int index] {
             get { return cache.GetValue (index); }
         }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/MemoryTrackListModel.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/MemoryTrackListModel.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/MemoryTrackListModel.cs	Thu Apr 10 09:50:53 2008
@@ -35,6 +35,7 @@
 {
     public class MemoryTrackListModel : TrackListModel, IEnumerable<TrackInfo>
     {
+        private static Random random = new Random ();
         private List<TrackInfo> tracks = new List<TrackInfo> ();
 
         public MemoryTrackListModel () : base ()
@@ -80,6 +81,14 @@
             get { lock (this) { return (index >= 0 && index < tracks.Count) ? tracks[index] : null; } }
         }
 
+        public override TrackInfo GetRandom (DateTime since, bool repeat)
+        {
+            if (Count == 0)
+                return null;
+
+            return this [random.Next (0, Count - 1)];
+        }
+
         public override int Count { 
             get { lock (this) { return tracks.Count; } }
         }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/TrackListModel.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/TrackListModel.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection/TrackListModel.cs	Thu Apr 10 09:50:53 2008
@@ -53,6 +53,8 @@
         {
             throw new NotImplementedException();
         }
+
+        public abstract TrackInfo GetRandom (DateTime notPlayedSince, bool repeat);
         
         public virtual IEnumerable<ArtistInfo> ArtistInfoFilter {
             set { throw new NotImplementedException(); }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.MediaEngine/PlayerEngineService.cs	Thu Apr 10 09:50:53 2008
@@ -314,23 +314,32 @@
             } else {
                 return;
             }
+
+            IncrementLastPlayed ();
             
             FindSupportingEngine (uri);
             CheckPending ();
             
-            if (active_engine.CurrentTrack != null) {
+            if (track != null) {
+                active_engine.Open (track);
+                incremented_last_played = false;
+            } else if (uri != null) {
+                active_engine.Open (uri);
+                incremented_last_played = false;
+            }
+        }
+
+        private bool incremented_last_played = true;
+        public void IncrementLastPlayed ()
+        {
+            if (!incremented_last_played && active_engine.CurrentTrack != null) {
                 // If we're at least 50% done playing a song, mark it as played, otherwise as skipped
                 if (active_engine.Length > 0 && active_engine.Position >= active_engine.Length / 2) {
                     active_engine.CurrentTrack.IncrementPlayCount ();
                 } else {
                     active_engine.CurrentTrack.IncrementSkipCount ();
                 }
-            }
-            
-            if (track != null) {
-                active_engine.Open (track);
-            } else if (uri != null) {
-                active_engine.Open (uri);
+                incremented_last_played = true;
             }
         }
         
@@ -371,6 +380,7 @@
         
         public void Close (bool fullShutdown)
         {
+            IncrementLastPlayed ();
             active_engine.Reset ();
             active_engine.Close (fullShutdown);
         }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.PlaybackController/IBasicPlaybackController.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.PlaybackController/IBasicPlaybackController.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.PlaybackController/IBasicPlaybackController.cs	Thu Apr 10 09:50:53 2008
@@ -32,6 +32,6 @@
     {
         void First ();
         void Next (bool restart);
-        void Previous ();
+        void Previous (bool restart);
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.PlaybackController/ICanonicalPlaybackController.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.PlaybackController/ICanonicalPlaybackController.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.PlaybackController/ICanonicalPlaybackController.cs	Thu Apr 10 09:50:53 2008
@@ -32,6 +32,6 @@
     {
         new void First ();
         new void Next (bool restart);
-        new void Previous ();
+        new void Previous (bool restart);
     }
 }

Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs	(original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs	Thu Apr 10 09:50:53 2008
@@ -55,7 +55,7 @@
         private bool raise_started_after_transition = false;
         private bool transition_track_started = false;
         
-        private Random random = new Random ();
+        //private Random random = new Random ();
     
         private PlaybackShuffleMode shuffle_mode;
         private PlaybackRepeatMode repeat_mode;
@@ -151,6 +151,8 @@
         public void Next (bool restart)
         {
             raise_started_after_transition = true;
+
+            player_engine.IncrementLastPlayed ();
             
             if (Source is IBasicPlaybackController) {
                 ((IBasicPlaybackController)Source).Next (restart);
@@ -160,15 +162,22 @@
             
             OnTransition ();
         }
-        
+
         public void Previous ()
         {
+            Previous (RepeatMode == PlaybackRepeatMode.RepeatAll);
+        }
+        
+        public void Previous (bool restart)
+        {
             raise_started_after_transition = true;
+
+            player_engine.IncrementLastPlayed ();
             
             if (Source is IBasicPlaybackController) {
-                ((IBasicPlaybackController)Source).Previous ();
+                ((IBasicPlaybackController)Source).Previous (restart);
             } else {
-                ((ICanonicalPlaybackController)this).Previous ();
+                ((ICanonicalPlaybackController)this).Previous (restart);
             }
             
             OnTransition ();
@@ -191,19 +200,11 @@
                     previous_stack.Push (tmp_track);
                 }
             } else {
-                TrackInfo next_track = QueryTrack (Direction.Next);
+                TrackInfo next_track = QueryTrack (Direction.Next, restart);
                 if (next_track != null) {
                     if (tmp_track != null) {
                         previous_stack.Push (tmp_track);
                     }
-                } else if (restart && Source.Count > 0) {
-                    if (tmp_track != null) {
-                        previous_stack.Push (tmp_track);
-                    }
-                    
-                    CurrentTrack = Source.TrackModel[0];
-                    QueuePlayTrack ();
-                    return;
                 } else {
                     return;
                 }
@@ -214,7 +215,7 @@
             QueuePlayTrack ();
         }
         
-        void ICanonicalPlaybackController.Previous ()
+        void ICanonicalPlaybackController.Previous (bool restart)
         {
             if (CurrentTrack != null && previous_stack.Count > 0) {
                 next_stack.Push (current_track);
@@ -223,30 +224,51 @@
             if (previous_stack.Count > 0) {
                 CurrentTrack = previous_stack.Pop ();
             } else {
-                CurrentTrack = QueryTrack (Direction.Previous);
+                TrackInfo track = CurrentTrack = QueryTrack (Direction.Previous, restart);
+                if (track != null) {
+                    CurrentTrack = track;
+                } else {
+                    return;
+                }
             }
             
             QueuePlayTrack ();
         }
         
-        private TrackInfo QueryTrack (Direction direction)
+        private TrackInfo QueryTrack (Direction direction, bool restart)
         {
             Log.DebugFormat ("Querying model for track to play in {0}:{1} mode", ShuffleMode, direction);
             return ShuffleMode == PlaybackShuffleMode.Linear
-                ? QueryTrackLinear (direction)
-                : QueryTrackRandom ();
+                ? QueryTrackLinear (direction, restart)
+                : QueryTrackRandom (restart);
         }
         
-        private TrackInfo QueryTrackLinear (Direction direction)
+        private TrackInfo QueryTrackLinear (Direction direction, bool restart)
         {
+            if (Source.TrackModel.Count == 0)
+                return null;
+
             int index = Source.TrackModel.IndexOf (CurrentTrack);
-            return Source.TrackModel[index < 0 ? 0 : index + (direction == Direction.Next ? 1 : -1)];
+            if (index == -1) {
+                return Source.TrackModel[0];
+            } else {
+                index += (direction == Direction.Next ? 1 : -1);
+                if (index >= 0 && index < Source.TrackModel.Count) {
+                    return Source.TrackModel[index];
+                } else if (!restart) {
+                    return null;
+                } else if (index < 0) {
+                    return Source.TrackModel[Source.TrackModel.Count - 1];
+                } else {
+                    return Source.TrackModel[0];
+                }
+            }
         }
         
-        private TrackInfo QueryTrackRandom ()
+        private TrackInfo QueryTrackRandom (bool restart)
         {
-            // TODO let the TrackModel give us a random track
-            return Source.TrackModel[random.Next (0, Source.TrackModel.Count - 1)];
+            return Source.TrackModel.GetRandom (source_set_at, restart);
+            //return Source.TrackModel[random.Next (0, Source.TrackModel.Count - 1)];
         }
         
         private void QueuePlayTrack ()
@@ -304,6 +326,7 @@
             protected set { current_track = value; }
         }
         
+        protected DateTime source_set_at;
         public ITrackModelSource Source {
             get { 
                 if (source == null && ServiceManager.SourceManager.DefaultSource is ITrackModelSource) {
@@ -315,6 +338,7 @@
             set {
                 if (source != value) {
                     source = value;
+                    source_set_at = DateTime.Now;
                     OnSourceChanged ();
                 }
             }

Modified: trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs
==============================================================================
--- trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs	(original)
+++ trunk/banshee/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs	Thu Apr 10 09:50:53 2008
@@ -226,7 +226,7 @@
             ServiceManager.PlayerEngine.OpenPlay ((DatabaseTrackInfo)TrackModel[0]);
         }
         
-        void IBasicPlaybackController.Previous ()
+        void IBasicPlaybackController.Previous (bool restart)
         {
         }
         

Modified: trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelCache.cs
==============================================================================
--- trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelCache.cs	(original)
+++ trunk/banshee/src/Libraries/Hyena/Hyena.Data.Sqlite/SqliteModelCache.cs	Thu Apr 10 09:50:53 2008
@@ -45,6 +45,7 @@
         private HyenaSqliteCommand save_selection_command;
         private HyenaSqliteCommand get_selection_command;
 
+        private string select_str;
         private string reload_sql;
         private long uid;
         private long selection_uid;
@@ -100,23 +101,19 @@
             }
 
             if (model.CachesJoinTableEntries) {
-                select_range_command = new HyenaSqliteCommand (
-                    String.Format (@"
-                        SELECT {0}, {5}.ItemID  FROM {1}
-                            INNER JOIN {2}
-                                ON {3} = {2}.{4}
-                            INNER JOIN {5}
-                                ON {2}.{6} = {5}.ItemID
-                            WHERE
-                                {5}.ModelID = {7} {8}
-                                {9}
-                            LIMIT ?, ?",
-                        provider.Select, provider.From,
-                        model.JoinTable, provider.PrimaryKey, model.JoinColumn,
-                        CacheTableName, model.JoinPrimaryKey, uid,
-                        String.IsNullOrEmpty (provider.Where) ? null : "AND",
-                        provider.Where
-                    )
+                select_str = String.Format (
+                    @"SELECT {0}, {5}.ItemID  FROM {1}
+                        INNER JOIN {2}
+                            ON {3} = {2}.{4}
+                        INNER JOIN {5}
+                            ON {2}.{6} = {5}.ItemID
+                        WHERE
+                            {5}.ModelID = {7} {8} {9}",
+                    provider.Select, provider.From,
+                    model.JoinTable, provider.PrimaryKey, model.JoinColumn,
+                    CacheTableName, model.JoinPrimaryKey, uid,
+                    String.IsNullOrEmpty (provider.Where) ? null : "AND",
+                    provider.Where
                 );
 
                 select_single_command = new HyenaSqliteCommand (
@@ -135,22 +132,18 @@
                     CacheTableName, uid, model.JoinPrimaryKey
                 );
             } else {
-                select_range_command = new HyenaSqliteCommand (
-                    String.Format (@"
-                        SELECT {0}, {2}.ItemID FROM {1}
-                            INNER JOIN {2} 
-                                ON {3} = {2}.ItemID
-                            WHERE
-                                {2}.ModelID = {4} {5}
-                                {6}
-                            LIMIT ?, ?",
-                        provider.Select, provider.From, CacheTableName,
-                        provider.PrimaryKey, uid,
-                        String.IsNullOrEmpty (provider.Where) ? String.Empty : "AND",
-                        provider.Where
-                    )
+                select_str = String.Format (
+                    @"SELECT {0}, {2}.ItemID FROM {1}
+                        INNER JOIN {2} 
+                            ON {3} = {2}.ItemID
+                        WHERE
+                            {2}.ModelID = {4} {5} {6}",
+                    provider.Select, provider.From, CacheTableName,
+                    provider.PrimaryKey, uid,
+                    String.IsNullOrEmpty (provider.Where) ? String.Empty : "AND",
+                    provider.Where
                 );
-            
+
                 select_single_command = new HyenaSqliteCommand (
                     String.Format (@"
                         SELECT OrderID FROM {0}
@@ -167,7 +160,11 @@
                     CacheTableName, uid, provider.PrimaryKey
                 );
             }
-            
+
+            select_range_command = new HyenaSqliteCommand (
+                String.Format ("{0} {1}", select_str, "LIMIT ?, ?")
+            );
+
             select_first_command = new HyenaSqliteCommand (
                 String.Format (
                     "SELECT OrderID FROM {0} WHERE ModelID = {1} LIMIT 1",
@@ -244,6 +241,29 @@
             }
         }
 
+        private HyenaSqliteCommand get_single_command;
+        private string last_get_single_fragment;
+        public T GetSingle (string fragment, params object [] args)
+        {
+            if (fragment != last_get_single_fragment || get_single_command == null) {
+                last_get_single_fragment = fragment;
+                get_single_command = new HyenaSqliteCommand (
+                    String.Format ("{0} {1} {2}", select_str, fragment, "LIMIT 1")
+                );
+            }
+
+            using (IDataReader reader = connection.Query (get_single_command, args)) {
+                if (reader.Read ()) {
+                    T item = provider.Load (reader, 0);
+                    item.CacheEntryId = Convert.ToInt64 (reader[reader.FieldCount - 1]);
+                    item.CacheModelId = uid;
+                    return item;
+                }
+            }
+            return default(T);
+        }
+
+
         private HyenaSqliteCommand last_reload_command;
         private string last_reload_fragment;
 



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