Index: src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs
===================================================================
--- src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs	(revision 4247)
+++ src/Core/Banshee.Services/Banshee.Collection.Database/DatabaseTrackListModel.cs	(working copy)
@@ -307,7 +307,8 @@
 
         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()";
+        private static string random_fragment = "AND (LastPlayedStamp < ? OR LastPlayedStamp IS NULL) AND (LastSkippedStamp < ? OR LastSkippedStamp IS NULL) AND (CoreTracks.Rating == ?) ORDER BY RANDOM()"; 
+        private ShuffleStars w_random = new ShuffleStars(6, connection); //BAD LITERAL XXX FIXME 
         public override TrackInfo GetRandom (DateTime notPlayedSince, bool repeat)
         {
             lock (this) {
@@ -317,18 +318,94 @@
                 if (random_began_at < notPlayedSince)
                     random_began_at = last_random = notPlayedSince;
 
-                TrackInfo track = cache.GetSingle (random_fragment, random_began_at, random_began_at);
-
+                int next_star = w_random.NextStar;
+                TrackInfo track = cache.GetSingle (random_fragment, random_began_at, random_began_at, next_star);
+                    
                 if (track == null && repeat) {
                     random_began_at = last_random;
-                    track = cache.GetSingle (random_fragment, random_began_at, random_began_at);
+                    track = cache.GetSingle (random_fragment, random_began_at, random_began_at, next_star);
                 }
-
+                           
                 last_random = DateTime.Now;
                 return track;
             }
         }
-
+        
+        internal class ShuffleStars
+        {
+            //private static bool loaded = false;    
+            private int classes;
+            private double[] weights;
+            private int[] stars;
+            private Random random;
+            private const int NO_RATING_VALUE = 3; //unrated songs (with rating == 0) are considered like 3 stars songs
+            private readonly BansheeDbConnection connection;
+
+            public ShuffleStars(int classes, BansheeDbConnection connection)
+            {
+                //if (!loaded) {
+                    this.classes = classes;
+                    this.random = new Random();
+                    this.connection = connection;
+
+                    weights = new double[classes];
+                    stars =  new int[classes];
+                    for (int i = 0; i < classes; i++) {
+                       stars[i]= i;
+                    }
+              
+                    FillWeights();
+                //}
+                //loaded = true;
+            }
+        
+            private void FillWeights()
+            {
+                long[] library_banshee = new long[classes];
+                long with_stars = 0;
+                for (int i = 0; i < classes; i++) {
+                    library_banshee[i] = connection.Query<long> ("SELECT COUNT(*) FROM CoreTracks WHERE Rating == ?", i);
+                    with_stars += library_banshee[i];
+                    Log.DebugFormat("{0} songs with {1} stars", library_banshee[i], i);
+                }
+                // libraryBanshee[i] now contains the number of songs with i stars
+
+                double tot = 0;
+                for (int i = 0; i < classes; i++) {
+                    weights[i] = library_banshee[i] * ((i == 0) ? NO_RATING_VALUE : stars[i]);
+                    tot += weights[i];
+                }
+                for (int i = 0; i < classes; i++) { 
+                    weights[i] /= tot;
+                    Log.DebugFormat("Songs with {0} stars have a weight of {1}", i, weights[i]);
+                }
+
+                Array.Sort(weights, stars);
+            }
+
+            private int NextRandom()
+            {
+                double rand = random.NextDouble();
+                for (int i = 0; i < classes; i++) {
+                    rand -= weights[i];
+                    if (rand < 0) {
+                        Log.DebugFormat("Selected rating {0}", stars[i]);
+                        return i;
+                    }
+                }
+                // If for some rounding error rand is still >= 0 we simply return
+                // the highest class.
+                Log.DebugFormat("After...Selected rating {0}", stars[classes-1]);
+                return classes-1;
+            }
+        
+            public int NextStar {
+                get {
+                   return stars[NextRandom()];
+                }
+            }
+        }
+        
         public override TrackInfo this[int index] {
             get {
                 lock (this) {
