[banshee/1.5.1-fixes: 16/56] Fix bug with AutoDJ updating LastPlayed erroneously
- From: Gabriel Burt <gburt src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [banshee/1.5.1-fixes: 16/56] Fix bug with AutoDJ updating LastPlayed erroneously
- Date: Mon, 22 Mar 2010 18:05:25 +0000 (UTC)
commit 8b2d3b8198cbb0be0c4768cdc7da82da22950a30
Author: Gabriel Burt <gabriel burt gmail com>
Date: Wed Oct 14 20:08:07 2009 -0700
Fix bug with AutoDJ updating LastPlayed erroneously
The old random-bys used the LastPlayed/LastSkipped values in CoreTracks
to not repeat a track that had already been shuffled. This works well
for playback shuffling, but the AutoDJ was using it for its
fill-shuffling as well. Fix that by adding a CoreShuffles table that
the PlayQueue and others can use to get a random track from a source,
without repeats, and without messing with the LastPlayedStamp. This
fixes BGO #594701
.../DatabaseTrackListModel.cs | 58 +-------
.../Banshee.Collection.Database/RandomBy.cs | 67 +++++++++-
.../Banshee.Collection.Database/RandomByAlbum.cs | 19 ++-
.../Banshee.Collection.Database/RandomByArtist.cs | 14 ++-
.../Banshee.Collection.Database/RandomByRating.cs | 35 +++++-
.../Banshee.Collection.Database/RandomByScore.cs | 39 +++++-
.../Banshee.Collection.Database/RandomBySlot.cs | 22 +++-
.../Banshee.Collection.Database/RandomByTrack.cs | 11 ++-
.../Banshee.Collection.Database/Shuffler.cs | 140 ++++++++++++++++++++
.../Banshee.Collection/MemoryTrackListModel.cs | 2 +-
.../Banshee.Collection/TrackListModel.cs | 2 +-
.../Banshee.Database/BansheeDbFormatMigrator.cs | 46 +++++++-
.../PlaybackControllerService.cs | 5 +-
src/Core/Banshee.Services/Makefile.am | 1 +
.../Banshee.PlayQueue/HeaderWidget.cs | 6 +-
.../Banshee.PlayQueue/PlayQueueSource.cs | 13 ++-
.../Banshee.PlayQueue/QueueableSourceComboBox.cs | 4 +-
17 files changed, 398 insertions(+), 86 deletions(-)
---
diff --git a/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs b/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs
index 384edaf..afcf511 100644
--- a/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs
+++ b/src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs
@@ -338,65 +338,19 @@ namespace Banshee.Collection.Database
}
}
-#region Get random methods
-
- private static RandomBy [] randoms = new RandomBy [] {
- new RandomByTrack (), new RandomByArtist (), new RandomByAlbum (), new RandomByRating (), new RandomByScore()
- };
-
- private DateTime random_began_at = DateTime.MinValue;
- private DateTime last_random = DateTime.MinValue;
-
- public override TrackInfo GetRandom (DateTime notPlayedSince, PlaybackShuffleMode mode, bool repeat, bool lastWasSkipped)
+ public override TrackInfo GetRandom (DateTime notPlayedSince)
{
- lock (this) {
- if (Count == 0) {
- return null;
- }
-
- if (random_began_at < notPlayedSince) {
- random_began_at = last_random = notPlayedSince;
- }
-
- TrackInfo track = GetRandomTrack (mode, repeat, lastWasSkipped);
- if (track == null && (repeat || mode != PlaybackShuffleMode.Linear)) {
- random_began_at = (random_began_at == last_random) ? DateTime.Now : last_random;
- track = GetRandomTrack (mode, repeat, true);
- }
-
- last_random = DateTime.Now;
- return track;
- }
+ return GetRandom (notPlayedSince, PlaybackShuffleMode.Song, true, false, Shuffler.Playback);
}
- private TrackInfo GetRandomTrack (PlaybackShuffleMode mode, bool repeat, bool lastWasSkipped)
+ public TrackInfo GetRandom (DateTime notPlayedSince, PlaybackShuffleMode mode, bool repeat, bool resetSinceTime, Shuffler shuffler)
{
- foreach (var r in randoms) {
- r.SetModelAndCache (this, cache);
- if (lastWasSkipped || r.Mode != mode) {
- r.Reset ();
- }
- }
-
- var random = randoms.First (r => r.Mode == mode);
- if (random != null) {
- if (!random.IsReady) {
- if (!random.Next (random_began_at) && repeat) {
- random_began_at = last_random;
- random.Next (random_began_at);
- }
- }
-
- if (random.IsReady) {
- return random.GetTrack (random_began_at);
- }
+ lock (this) {
+ shuffler.SetModelAndCache (this, cache);
+ return shuffler.GetRandom (notPlayedSince, mode, repeat, resetSinceTime);
}
-
- return null;
}
-#endregion
-
public override TrackInfo this[int index] {
get {
lock (this) {
diff --git a/src/Core/Banshee.Services/Banshee.Collection.Database/RandomBy.cs b/src/Core/Banshee.Services/Banshee.Collection.Database/RandomBy.cs
index 6add717..ae01174 100644
--- a/src/Core/Banshee.Services/Banshee.Collection.Database/RandomBy.cs
+++ b/src/Core/Banshee.Services/Banshee.Collection.Database/RandomBy.cs
@@ -44,12 +44,43 @@ namespace Banshee.Collection.Database
protected DatabaseTrackListModel Model { get; private set; }
protected IDatabaseTrackModelCache Cache { get; private set; }
+ private HyenaSqliteCommand insert_shuffle;
+
+ protected Shuffler Shuffler { get; private set; }
+
public virtual bool IsReady { get { return true; } }
public PlaybackShuffleMode Mode { get; private set; }
- public RandomBy (PlaybackShuffleMode mode)
+ protected string Condition { get; set; }
+ protected string OrderBy { get; set; }
+
+ public RandomBy (PlaybackShuffleMode mode, Shuffler shuffler)
{
+ Shuffler = shuffler;
Mode = mode;
+ insert_shuffle = new HyenaSqliteCommand ("INSERT OR REPLACE INTO CoreShuffles (ShufflerID, TrackID, LastShuffledAt) VALUES (?, ?, ?)");
+ }
+
+ private HyenaSqliteCommand shuffler_query;
+ protected HyenaSqliteCommand ShufflerQuery {
+ get {
+ if (shuffler_query == null) {
+ var provider = DatabaseTrackInfo.Provider;
+ shuffler_query = new HyenaSqliteCommand (String.Format (@"
+ SELECT {0}
+ FROM {1} LEFT OUTER JOIN CoreShuffles ON (CoreShuffles.ShufflerId = {2} AND CoreShuffles.TrackID = CoreTracks.TrackID)
+ WHERE {3} {4} AND {5} AND
+ LastStreamError = 0 AND (CoreShuffles.LastShuffledAt < ? OR CoreShuffles.LastShuffledAt IS NULL)
+ ORDER BY {6}",
+ provider.Select,
+ Model.FromFragment, Shuffler.DbId,
+ String.IsNullOrEmpty (provider.Where) ? "1=1" : provider.Where, Model.ConditionFragment ?? "1=1", Condition,
+ OrderBy
+ ));
+ }
+
+ return shuffler_query;
+ }
}
public void SetModelAndCache (DatabaseTrackListModel model, IDatabaseTrackModelCache cache)
@@ -61,6 +92,8 @@ namespace Banshee.Collection.Database
OnModelAndCacheUpdated ();
}
+
+ shuffler_query = null;
}
protected virtual void OnModelAndCacheUpdated ()
@@ -68,7 +101,37 @@ namespace Banshee.Collection.Database
}
public virtual void Reset () {}
+
public abstract bool Next (DateTime after);
- public abstract TrackInfo GetTrack (DateTime after);
+
+ public TrackInfo GetTrack (DateTime after)
+ {
+ if (Shuffler == Shuffler.Playback) {
+ return GetPlaybackTrack (after);
+ } else {
+ var track = GetShufflerTrack (after);
+
+ // Record this shuffle
+ if (track != null) {
+ ServiceManager.DbConnection.Execute (insert_shuffle, Shuffler.DbId, track.TrackId, DateTime.Now);
+ }
+
+ return track;
+ }
+ }
+
+ public abstract TrackInfo GetPlaybackTrack (DateTime after);
+ public abstract DatabaseTrackInfo GetShufflerTrack (DateTime after);
+
+ protected DatabaseTrackInfo GetTrack (HyenaSqliteCommand cmd, params object [] args)
+ {
+ using (var reader = ServiceManager.DbConnection.Query (cmd, args)) {
+ if (reader.Read ()) {
+ return DatabaseTrackInfo.Provider.Load (reader);
+ }
+ }
+
+ return null;
+ }
}
}
diff --git a/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByAlbum.cs b/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByAlbum.cs
index 1b3cd60..185fde8 100644
--- a/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByAlbum.cs
+++ b/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByAlbum.cs
@@ -39,12 +39,15 @@ namespace Banshee.Collection.Database
{
public class RandomByAlbum : RandomBy
{
- private static string track_condition = String.Format ("AND CoreTracks.AlbumID = ? {0} ORDER BY Disc ASC, TrackNumber ASC", RANDOM_CONDITION);
+ private static string last_played_condition = String.Format ("AND CoreTracks.AlbumID = ? {0} ORDER BY Disc ASC, TrackNumber ASC", RANDOM_CONDITION);
+
private HyenaSqliteCommand album_query;
private int? album_id;
- public RandomByAlbum () : base (PlaybackShuffleMode.Album)
+ public RandomByAlbum (Shuffler shuffler) : base (PlaybackShuffleMode.Album, shuffler)
{
+ Condition = "CoreTracks.AlbumID = ?";
+ OrderBy = "Disc ASC, TrackNumber ASC";
}
protected override void OnModelAndCacheUpdated ()
@@ -72,9 +75,17 @@ namespace Banshee.Collection.Database
return IsReady;
}
- public override TrackInfo GetTrack (DateTime after)
+ public override TrackInfo GetPlaybackTrack (DateTime after)
{
- return album_id == null ? null : Cache.GetSingle (track_condition, (int)album_id, after, after);
+ return album_id == null ? null : Cache.GetSingle (last_played_condition, (int)album_id, after, after);
+ }
+
+ public override DatabaseTrackInfo GetShufflerTrack (DateTime after)
+ {
+ if (album_id == null)
+ return null;
+
+ return GetTrack (ShufflerQuery, (int)album_id, after);
}
private HyenaSqliteCommand AlbumQuery {
diff --git a/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByArtist.cs b/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByArtist.cs
index 3fcb11e..ed20f36 100644
--- a/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByArtist.cs
+++ b/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByArtist.cs
@@ -43,8 +43,10 @@ namespace Banshee.Collection.Database
private HyenaSqliteCommand query;
private int? id;
- public RandomByArtist () : base (PlaybackShuffleMode.Artist)
+ public RandomByArtist (Shuffler shuffler) : base (PlaybackShuffleMode.Artist, shuffler)
{
+ Condition = "CoreAlbums.ArtistID = ?";
+ OrderBy = "CoreTracks.Year, CoreTracks.AlbumID ASC, Disc ASC, TrackNumber ASC";
}
protected override void OnModelAndCacheUpdated ()
@@ -72,11 +74,19 @@ namespace Banshee.Collection.Database
return IsReady;
}
- public override TrackInfo GetTrack (DateTime after)
+ public override TrackInfo GetPlaybackTrack (DateTime after)
{
return id == null ? null : Cache.GetSingle (track_condition, (int)id, after, after);
}
+ public override DatabaseTrackInfo GetShufflerTrack (DateTime after)
+ {
+ if (id == null)
+ return null;
+
+ return GetTrack (ShufflerQuery, (int)id, after);
+ }
+
private HyenaSqliteCommand Query {
get {
if (query == null) {
diff --git a/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByRating.cs b/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByRating.cs
index 35180c2..2f71260 100644
--- a/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByRating.cs
+++ b/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByRating.cs
@@ -40,22 +40,34 @@ namespace Banshee.Collection.Database
{
private static string track_condition = String.Format ("AND (CoreTracks.Rating = ? OR (? = 3 AND CoreTracks.Rating = 0)) {0} ORDER BY RANDOM()", RANDOM_CONDITION);
- public RandomByRating () : base (PlaybackShuffleMode.Rating)
+ public RandomByRating (Shuffler shuffler) : base (PlaybackShuffleMode.Rating, shuffler)
{
+ Condition = "(CoreTracks.Rating = ? OR (? = 3 AND CoreTracks.Rating = 0))";
+ OrderBy = "RANDOM()";
}
- public override TrackInfo GetTrack (DateTime after)
+ public override TrackInfo GetPlaybackTrack (DateTime after)
{
var track = !IsReady ? null : Cache.GetSingle (track_condition, slot + 1, slot + 1, after, after);
Reset ();
return track;
}
+ public override DatabaseTrackInfo GetShufflerTrack (DateTime after)
+ {
+ if (!IsReady)
+ return null;
+
+ var track = GetTrack (ShufflerQuery, slot + 1, slot + 1, after);
+ Reset ();
+ return track;
+ }
+
protected override int Slots {
get { return 5; }
}
- protected override string QuerySql {
+ protected override string PlaybackSlotQuerySql {
get {
return @"
SELECT
@@ -72,5 +84,22 @@ namespace Banshee.Collection.Database
GROUP BY Slot";
}
}
+
+ protected override string ShufflerSlotQuerySql {
+ get {
+ return @"
+ SELECT
+ (CoreTracks.Rating - 1) AS Slot, COUNT(*)
+ FROM
+ CoreTracks LEFT OUTER JOIN CoreShuffles ON (CoreShuffles.ShufflerId = " + Shuffler.DbId.ToString () +
+ @" AND CoreShuffles.TrackID = CoreTracks.TrackID)
+ {0}
+ WHERE
+ CoreTracks.LastStreamError = 0 AND
+ (CoreShuffles.LastShuffledAt < ? OR CoreShuffles.LastShuffledAt IS NULL)
+ {3}
+ GROUP BY Slot";
+ }
+ }
}
}
diff --git a/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByScore.cs b/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByScore.cs
index 81f34de..c997773 100644
--- a/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByScore.cs
+++ b/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByScore.cs
@@ -36,11 +36,13 @@ namespace Banshee.Collection.Database
{
private static string track_condition = String.Format ("AND (CoreTracks.Score BETWEEN ? AND ? OR (? = 50 AND CoreTracks.Score = 0)) {0} ORDER BY RANDOM()", RANDOM_CONDITION);
- public RandomByScore () : base (PlaybackShuffleMode.Score)
+ public RandomByScore (Shuffler shuffler) : base (PlaybackShuffleMode.Score, shuffler)
{
+ Condition = "(CoreTracks.Score BETWEEN ? AND ? OR (? = 50 AND CoreTracks.Score = 0))";
+ OrderBy = "RANDOM()";
}
- public override TrackInfo GetTrack (DateTime after)
+ public override TrackInfo GetPlaybackTrack (DateTime after)
{
int min = slot * 100 / Slots + 1;
int max = (slot + 1) * 100 / Slots;
@@ -50,11 +52,24 @@ namespace Banshee.Collection.Database
return track;
}
+ public override DatabaseTrackInfo GetShufflerTrack (DateTime after)
+ {
+ if (!IsReady)
+ return null;
+
+ int min = slot * 100 / Slots + 1;
+ int max = (slot + 1) * 100 / Slots;
+
+ var track = GetTrack (ShufflerQuery, min, max, max, after);
+ Reset ();
+ return track;
+ }
+
protected override int Slots {
get { return 20; }
}
- protected override string QuerySql {
+ protected override string PlaybackSlotQuerySql {
get {
// NOTE: SQLite wrongly assumes that (-1)/5 == 0, the CASE WHEN works around this.
return @"
@@ -72,5 +87,23 @@ namespace Banshee.Collection.Database
GROUP BY Slot";
}
}
+
+ protected override string ShufflerSlotQuerySql {
+ get {
+ // NOTE: SQLite wrongly assumes that (-1)/5 == 0, the CASE WHEN works around this.
+ return @"
+ SELECT
+ CASE WHEN IFNULL(CoreTracks.Score, 0) = 0 THEN -1 ELSE (CoreTracks.Score - 1) * 20 / 100 END AS Slot, COUNT(*)
+ FROM
+ CoreTracks LEFT OUTER JOIN CoreShuffles ON (CoreShuffles.ShufflerId = " + Shuffler.DbId.ToString () +
+ @" AND CoreShuffles.TrackID = CoreTracks.TrackID)
+ {0}
+ WHERE
+ CoreTracks.LastStreamError = 0 AND
+ (CoreShuffles.LastShuffledAt < ? OR CoreShuffles.LastShuffledAt IS NULL)
+ {3}
+ GROUP BY Slot";
+ }
+ }
}
}
diff --git a/src/Core/Banshee.Services/Banshee.Collection.Database/RandomBySlot.cs b/src/Core/Banshee.Services/Banshee.Collection.Database/RandomBySlot.cs
index 348a726..2a988de 100644
--- a/src/Core/Banshee.Services/Banshee.Collection.Database/RandomBySlot.cs
+++ b/src/Core/Banshee.Services/Banshee.Collection.Database/RandomBySlot.cs
@@ -49,7 +49,7 @@ namespace Banshee.Collection.Database
private HyenaSqliteCommand query;
protected int slot;
- public RandomBySlot (PlaybackShuffleMode mode) : base (mode)
+ public RandomBySlot (PlaybackShuffleMode mode, Shuffler shuffler) : base (mode, shuffler)
{
}
@@ -74,7 +74,11 @@ namespace Banshee.Collection.Database
int default_slot = (Slots - 1) / 2;
// Get the distribution for tracks that haven't been played since stamp.
- using (var reader = ServiceManager.DbConnection.Query (Query, after, after)) {
+ var reader = Shuffler == Shuffler.Playback
+ ? ServiceManager.DbConnection.Query (SlotQuery, after, after)
+ : ServiceManager.DbConnection.Query (SlotQuery, after);
+
+ using (reader) {
while (reader.Read ()) {
int s = Convert.ToInt32 (reader[0]);
int count = Convert.ToInt32 (reader[1]);
@@ -121,10 +125,10 @@ namespace Banshee.Collection.Database
return IsReady;
}
- private HyenaSqliteCommand Query {
+ private HyenaSqliteCommand SlotQuery {
get {
if (query == null) {
- query = new HyenaSqliteCommand (String.Format (QuerySql,
+ query = new HyenaSqliteCommand (String.Format (SlotQuerySql,
Model.JoinFragment,
Model.CachesJoinTableEntries
? String.Format ("CoreCache.ItemID = {0}.{1} AND", Model.JoinTable, Model.JoinPrimaryKey)
@@ -137,7 +141,15 @@ namespace Banshee.Collection.Database
}
}
+ private string SlotQuerySql {
+ get {
+ return Shuffler == Shuffler.Playback ? PlaybackSlotQuerySql : ShufflerSlotQuerySql;
+ }
+ }
+
protected abstract int Slots { get; }
- protected abstract string QuerySql { get; }
+
+ protected abstract string PlaybackSlotQuerySql { get; }
+ protected abstract string ShufflerSlotQuerySql { get; }
}
}
diff --git a/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByTrack.cs b/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByTrack.cs
index 1b91bf5..18c57dc 100644
--- a/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByTrack.cs
+++ b/src/Core/Banshee.Services/Banshee.Collection.Database/RandomByTrack.cs
@@ -41,8 +41,10 @@ namespace Banshee.Collection.Database
{
private static string track_condition = String.Format ("{0} ORDER BY RANDOM()", RANDOM_CONDITION);
- public RandomByTrack () : base (PlaybackShuffleMode.Song)
+ public RandomByTrack (Shuffler shuffler) : base (PlaybackShuffleMode.Song, shuffler)
{
+ Condition = "1=1";
+ OrderBy = "RANDOM()";
}
public override bool Next (DateTime after)
@@ -50,9 +52,14 @@ namespace Banshee.Collection.Database
return true;
}
- public override TrackInfo GetTrack (DateTime after)
+ public override TrackInfo GetPlaybackTrack (DateTime after)
{
return Cache.GetSingle (track_condition, after, after);
}
+
+ public override DatabaseTrackInfo GetShufflerTrack (DateTime after)
+ {
+ return GetTrack (ShufflerQuery, after);
+ }
}
}
diff --git a/src/Core/Banshee.Services/Banshee.Collection.Database/Shuffler.cs b/src/Core/Banshee.Services/Banshee.Collection.Database/Shuffler.cs
new file mode 100644
index 0000000..6636462
--- /dev/null
+++ b/src/Core/Banshee.Services/Banshee.Collection.Database/Shuffler.cs
@@ -0,0 +1,140 @@
+//
+// Shuffler.cs
+//
+// Author:
+// Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2009 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Linq;
+
+using Hyena;
+using Hyena.Data;
+using Hyena.Data.Sqlite;
+
+using Banshee.ServiceStack;
+using Banshee.PlaybackController;
+
+namespace Banshee.Collection.Database
+{
+ public class Shuffler
+ {
+ public static readonly Shuffler Playback = new Shuffler () { Id = "playback", DbId = 0 };
+
+ private DateTime random_began_at = DateTime.MinValue;
+ private DateTime last_random = DateTime.MinValue;
+ private RandomBy [] randoms;
+ private DatabaseTrackListModel model;
+
+ public string Id { get; private set; }
+ public int DbId { get; private set; }
+
+ private Shuffler ()
+ {
+ randoms = new RandomBy [] {
+ new RandomByTrack (this), new RandomByArtist (this), new RandomByAlbum (this), new RandomByRating (this), new RandomByScore (this)
+ };
+ }
+
+ public Shuffler (string id) : this ()
+ {
+ Id = id;
+ LoadOrCreate ();
+ }
+
+ public void SetModelAndCache (DatabaseTrackListModel model, IDatabaseTrackModelCache cache)
+ {
+ this.model = model;
+
+ foreach (var random in randoms) {
+ random.SetModelAndCache (model, cache);
+ }
+ }
+
+ public TrackInfo GetRandom (DateTime notPlayedSince, PlaybackShuffleMode mode, bool repeat, bool resetSinceTime)
+ {
+ lock (this) {
+ if (this == Playback) {
+ if (model.Count == 0) {
+ return null;
+ }
+ } else {
+ if (model.UnfilteredCount == 0) {
+ return null;
+ }
+ }
+
+ if (random_began_at < notPlayedSince) {
+ random_began_at = last_random = notPlayedSince;
+ }
+
+ TrackInfo track = GetRandomTrack (mode, repeat, resetSinceTime);
+ if (track == null && (repeat || mode != PlaybackShuffleMode.Linear)) {
+ random_began_at = (random_began_at == last_random) ? DateTime.Now : last_random;
+ track = GetRandomTrack (mode, repeat, true);
+ }
+
+ last_random = DateTime.Now;
+ return track;
+ }
+ }
+
+ private TrackInfo GetRandomTrack (PlaybackShuffleMode mode, bool repeat, bool resetSinceTime)
+ {
+ foreach (var r in randoms) {
+ if (resetSinceTime || r.Mode != mode) {
+ r.Reset ();
+ }
+ }
+
+ var random = randoms.First (r => r.Mode == mode);
+ if (random != null) {
+ if (!random.IsReady) {
+ if (!random.Next (random_began_at) && repeat) {
+ random_began_at = last_random;
+ random.Next (random_began_at);
+ }
+ }
+
+ if (random.IsReady) {
+ return random.GetTrack (random_began_at);
+ }
+ }
+
+ return null;
+ }
+
+ private void LoadOrCreate ()
+ {
+ var db = ServiceManager.DbConnection;
+
+ int res = db.Query<int> ("SELECT ShufflerID FROM CoreShufflers WHERE ID = ?", Id);
+ if (res > 0) {
+ DbId = res;
+ } else {
+ DbId = db.Execute ("INSERT INTO CoreShufflers (ID) VALUES (?)", Id);
+ }
+ }
+ }
+}
diff --git a/src/Core/Banshee.Services/Banshee.Collection/MemoryTrackListModel.cs b/src/Core/Banshee.Services/Banshee.Collection/MemoryTrackListModel.cs
index dbe12c6..b39a777 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, Banshee.PlaybackController.PlaybackShuffleMode mode, bool repeat, bool lastWasSkipped)
+ public override TrackInfo GetRandom (DateTime since)
{
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 e3c6f02..043ae3d 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, Banshee.PlaybackController.PlaybackShuffleMode mode, bool repeat, bool lastWasSkipped);
+ public abstract TrackInfo GetRandom (DateTime since);
}
}
diff --git a/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs b/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
index 36dd90e..04e4c01 100644
--- a/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
+++ b/src/Core/Banshee.Services/Banshee.Database/BansheeDbFormatMigrator.cs
@@ -56,7 +56,7 @@ namespace Banshee.Database
// NOTE: Whenever there is a change in ANY of the database schema,
// this version MUST be incremented and a migration method
// MUST be supplied to match the new version number
- protected const int CURRENT_VERSION = 35;
+ protected const int CURRENT_VERSION = 36;
protected const int CURRENT_METADATA_VERSION = 6;
#region Migration Driver
@@ -802,6 +802,33 @@ namespace Banshee.Database
#endregion
+#region Version 36
+
+ [DatabaseVersion (36)]
+ private bool Migrate_36 ()
+ {
+ Execute(@"
+ CREATE TABLE CoreShuffles (
+ ShufflerId INTEGER,
+ TrackID INTEGER,
+ LastShuffledAt INTEGER,
+ CONSTRAINT one_entry_per_track UNIQUE (ShufflerID, TrackID)
+ )
+ ");
+ Execute("CREATE INDEX CoreShufflesIndex ON CoreShuffles (ShufflerId, TrackID, LastShuffledAt)");
+
+ Execute(@"
+ CREATE TABLE CoreShufflers (
+ ShufflerId INTEGER PRIMARY KEY,
+ Id TEXT UNIQUE
+ )
+ ");
+
+ return true;
+ }
+
+#endregion
+
#pragma warning restore 0169
#region Fresh database setup
@@ -1010,6 +1037,23 @@ namespace Banshee.Database
// This index slows down queries were we shove data into the CoreCache.
// Since we do that frequently, not using it.
//Execute("CREATE INDEX CoreCacheModelId ON CoreCache(ModelID)");
+
+ Execute(@"
+ CREATE TABLE CoreShuffles (
+ ShufflerId INTEGER,
+ TrackID INTEGER,
+ LastShuffledAt INTEGER,
+ CONSTRAINT one_entry_per_track UNIQUE (ShufflerID, TrackID)
+ )
+ ");
+ Execute("CREATE INDEX CoreShufflesIndex ON CoreShuffles (ShufflerId, TrackID, LastShuffledAt)");
+
+ Execute(@"
+ CREATE TABLE CoreShufflers (
+ ShufflerId INTEGER PRIMARY KEY,
+ Id TEXT UNIQUE
+ )
+ ");
}
#endregion
diff --git a/src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs b/src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs
index 8b58e70..c7c5959 100644
--- a/src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs
+++ b/src/Core/Banshee.Services/Banshee.PlaybackController/PlaybackControllerService.cs
@@ -344,7 +344,10 @@ namespace Banshee.PlaybackController
private TrackInfo QueryTrackRandom (PlaybackShuffleMode mode, bool restart)
{
- var track = Source.TrackModel.GetRandom (source_set_at, mode, restart, last_was_skipped);
+ var track_shuffler = Source.TrackModel as Banshee.Collection.Database.DatabaseTrackListModel;
+ TrackInfo track = track_shuffler == null
+ ? Source.TrackModel.GetRandom (source_set_at)
+ : track_shuffler.GetRandom (source_set_at, mode, restart, last_was_skipped, Banshee.Collection.Database.Shuffler.Playback);
// Reset to default of true, only ever set to false by EosTransition
last_was_skipped = true;
return track;
diff --git a/src/Core/Banshee.Services/Makefile.am b/src/Core/Banshee.Services/Makefile.am
index c36d426..c48cdcf 100644
--- a/src/Core/Banshee.Services/Makefile.am
+++ b/src/Core/Banshee.Services/Makefile.am
@@ -29,6 +29,7 @@ SOURCES = \
Banshee.Collection.Database/RandomByScore.cs \
Banshee.Collection.Database/RandomBySlot.cs \
Banshee.Collection.Database/RandomByTrack.cs \
+ Banshee.Collection.Database/Shuffler.cs \
Banshee.Collection.Database/Tests/DatabaseAlbumInfoTests.cs \
Banshee.Collection.Database/Tests/DatabaseArtistInfoTests.cs \
Banshee.Collection.Database/Tests/DatabaseTrackInfoTests.cs \
diff --git a/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/HeaderWidget.cs b/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/HeaderWidget.cs
index 96e6e63..1f0982c 100644
--- a/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/HeaderWidget.cs
+++ b/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/HeaderWidget.cs
@@ -114,14 +114,14 @@ namespace Banshee.PlayQueue
public sealed class SourceChangedEventArgs : EventArgs
{
- private ITrackModelSource value;
+ private DatabaseSource value;
- public SourceChangedEventArgs (ITrackModelSource value)
+ public SourceChangedEventArgs (DatabaseSource value)
{
this.value = value;
}
- public ITrackModelSource Value {
+ public DatabaseSource Value {
get { return this.value; }
}
}
diff --git a/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs b/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs
index aa48a36..3ef237b 100644
--- a/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs
+++ b/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/PlayQueueSource.cs
@@ -58,6 +58,7 @@ namespace Banshee.PlayQueue
private ITrackModelSource prior_playback_source;
private DatabaseTrackInfo current_track;
+ private Shuffler shuffler;
private long offset;
private TrackInfo prior_playback_track;
private PlayQueueActions actions;
@@ -70,7 +71,7 @@ namespace Banshee.PlayQueue
private PlaybackShuffleMode populate_mode = (PlaybackShuffleMode) PopulateModeSchema.Get ();
private string populate_from_name = PopulateFromSchema.Get ();
- private ITrackModelSource populate_from = null;
+ private DatabaseSource populate_from = null;
private int played_songs_number = PlayedSongsNumberSchema.Get ();
private int upcoming_songs_number = UpcomingSongsNumberSchema.Get ();
@@ -107,7 +108,7 @@ namespace Banshee.PlayQueue
ServiceManager.SourceManager.VideoLibrary.TracksDeleted += HandleTracksDeleted;
populate_from = ServiceManager.SourceManager.Sources.FirstOrDefault (
- source => source.Name == populate_from_name) as ITrackModelSource;
+ source => source.Name == populate_from_name) as DatabaseSource;
if (populate_from != null) {
populate_from.Reload ();
}
@@ -125,6 +126,8 @@ namespace Banshee.PlayQueue
header_widget = CreateHeaderWidget ();
header_widget.ShowAll ();
+ shuffler = new Shuffler (UniqueId);
+
Properties.Set<Gtk.Widget> ("Nereid.SourceContents.HeaderWidget", header_widget);
}
@@ -568,8 +571,10 @@ namespace Banshee.PlayQueue
// Add songs from the selected source, skip if all tracks need to be populated.
bool skip = tracks_to_add == upcoming_songs_number;
for (int i = 0; i < tracks_to_add; i++) {
- var track = populate_from.TrackModel.GetRandom (
- source_set_at, populate_mode, false, skip && i == 0) as DatabaseTrackInfo;
+
+ var track = populate_from.DatabaseTrackModel.GetRandom (
+ source_set_at, populate_mode, false, skip && i == 0, shuffler) as DatabaseTrackInfo;
+
if (track != null) {
track.LastPlayed = DateTime.Now;
// track.Save() is quite slow, update LastPlayedStamp directly in the database.
diff --git a/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/QueueableSourceComboBox.cs b/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/QueueableSourceComboBox.cs
index 1ae0725..db7f6bc 100644
--- a/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/QueueableSourceComboBox.cs
+++ b/src/Extensions/Banshee.PlayQueue/Banshee.PlayQueue/QueueableSourceComboBox.cs
@@ -103,11 +103,11 @@ namespace Banshee.PlayQueue
return TreeIter.Zero;
}
- public ITrackModelSource Source {
+ public DatabaseSource Source {
get {
TreeIter iter;
if (GetActiveIter (out iter)) {
- return filter.GetValue(iter, 0) as ITrackModelSource;
+ return filter.GetValue(iter, 0) as DatabaseSource;
}
return null;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]