[gnome-music/mcatanzaro/random-shuffle] Make random shuffle actually random




commit 4d847bffe3a904e3dc24bc73be92debe829eddfc
Author: Michael Catanzaro <mcatanzaro redhat com>
Date:   Thu Aug 19 12:12:07 2021 -0500

    Make random shuffle actually random
    
    Currently the randomness in the random shuffle is implemented by
    returning a random result in a sort function, which is not very random
    at all. In practice, it results in songs close to the start of the list
    being sorted first.
    
    To fix this, we can simply assign a random integer to each song and
    compare them in the sorting function, to make the results consistent.
    
    Yes, I know this probably isn't a great way to implement a random
    shuffle in a music player app. We would probably want to write our own
    list model to handle smarts like "don't sort two songs from the same
    artist next to each other." But that requires effort, whereas what I've
    done here is simple and works.
    
    Fixes #369

 gnomemusic/coresong.py | 6 ++++++
 gnomemusic/player.py   | 7 ++++---
 2 files changed, 10 insertions(+), 3 deletions(-)
---
diff --git a/gnomemusic/coresong.py b/gnomemusic/coresong.py
index 064a6f8d7..94d548aa0 100644
--- a/gnomemusic/coresong.py
+++ b/gnomemusic/coresong.py
@@ -24,6 +24,7 @@
 
 from __future__ import annotations
 from enum import IntEnum
+from random import randint
 from typing import Optional
 import typing
 
@@ -50,6 +51,7 @@ class CoreSong(GObject.GObject):
     media = GObject.Property(type=Grl.Media)
     grlid = GObject.Property(type=str, default=None)
     play_count = GObject.Property(type=int)
+    shuffle_pos = GObject.Property(type=int)
     state = GObject.Property()  # FIXME: How to set an IntEnum type?
     title = GObject.Property(type=str)
     track_number = GObject.Property(type=int)
@@ -82,6 +84,7 @@ class CoreSong(GObject.GObject):
         self._is_tracker: bool = media.get_source() == "grl-tracker3-source"
         self.props.validation = CoreSong.Validation.PENDING
         self.update(media)
+        self.update_shuffle_pos()
 
     def __eq__(self, other: object) -> bool:
         return (isinstance(other, CoreSong)
@@ -175,3 +178,6 @@ class CoreSong(GObject.GObject):
         self.props.media.set_last_played(GLib.DateTime.new_now_utc())
         self._coregrilo.writeback_tracker(
             self.props.media, "last-played")
+
+    def update_shuffle_pos(self) -> None:
+        self.props.shuffle_pos = randint(1, 1_000_000)
diff --git a/gnomemusic/player.py b/gnomemusic/player.py
index 7e6ddf289..372d30103 100644
--- a/gnomemusic/player.py
+++ b/gnomemusic/player.py
@@ -24,7 +24,7 @@
 
 from enum import Enum, IntEnum
 from gettext import gettext as _
-from random import randint, randrange
+from random import randrange
 import time
 import typing
 
@@ -277,11 +277,12 @@ class PlayerPlaylist(GObject.GObject):
         self._model_recent.set_offset(offset)
 
     def _on_repeat_mode_changed(self, klass, param):
-        # FIXME: This shuffle is too simple.
         def _shuffle_sort(song_a, song_b):
-            return randint(-1, 1)
+            return song_a.shuffle_pos < song_b.shuffle_pos
 
         if self.props.repeat_mode == RepeatMode.SHUFFLE:
+            for idx, coresong in enumerate(self._model):
+                coresong.update_shuffle_pos()
             self._model.set_sort_func(
                 utils.wrap_list_store_sort_func(_shuffle_sort))
         elif self.props.repeat_mode in [RepeatMode.NONE, RepeatMode.ALL]:


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