about summary refs log tree commit homepage
path: root/lib/dtas/tracklist.rb
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2015-12-07 03:51:33 +0000
committerEric Wong <e@80x24.org>2015-12-07 05:22:20 +0000
commit3e013d3f24f0f935dce985d4c6bd155889e05dbb (patch)
tree7c9dfae4dc7939265ff4abe2b906ef91a884cb19 /lib/dtas/tracklist.rb
parente5668a47f20a6593ab47847083bc704e1abeb1e6 (diff)
downloaddtas-3e013d3f24f0f935dce985d4c6bd155889e05dbb.tar.gz
This is in the MPRIS 2.0 TrackList spec and also in mpd (as "repeat"
mode), so we can probably support it directly in player to ease
implementations of future wrappers.
Diffstat (limited to 'lib/dtas/tracklist.rb')
-rw-r--r--lib/dtas/tracklist.rb87
1 files changed, 72 insertions, 15 deletions
diff --git a/lib/dtas/tracklist.rb b/lib/dtas/tracklist.rb
index 1ae2719..f3dca31 100644
--- a/lib/dtas/tracklist.rb
+++ b/lib/dtas/tracklist.rb
@@ -9,6 +9,7 @@ require_relative 'track'
 class DTAS::Tracklist # :nodoc:
   include DTAS::Serialize
   attr_accessor :repeat # true, false, 1
+  attr_reader :shuffle  # false or shuffled @list
 
   SIVS = %w(list pos repeat)
   TL_DEFAULTS = {
@@ -20,9 +21,13 @@ class DTAS::Tracklist # :nodoc:
   def self.load(hash)
     obj = new
     obj.instance_eval do
-      list = hash["list"] and @list.replace(list.map! { |s| new_track(s) })
+      list = hash["list"] and @list.replace(list.map { |s| new_track(s) })
       @pos = hash["pos"] || -1
       @repeat = hash["repeat"] || false
+      if hash['shuffle']
+        @shuffle = @list.shuffle
+        @pos = _idx_of(@shuffle, @list[@pos].track_id) if @pos >= 0
+      end
     end
     obj
   end
@@ -31,6 +36,10 @@ class DTAS::Tracklist # :nodoc:
     h = ivars_to_hash(SIVS)
     h.delete_if { |k,v| TL_DEFAULTS[k] == v }
     list = h['list'] and h['list'] = list.map(&:to_path)
+    if @shuffle
+      h['shuffle'] = true
+      h['pos'] = _idx_of(@list, @shuffle[@pos].track_id) if @pos >= 0
+    end
     h
   end
 
@@ -39,6 +48,7 @@ class DTAS::Tracklist # :nodoc:
     @list = []
     @goto_off = @goto_pos = nil
     @track_nr = 0
+    @shuffle = false
   end
 
   def new_track(path)
@@ -54,6 +64,7 @@ class DTAS::Tracklist # :nodoc:
   def reset
     @goto_off = @goto_pos = nil
     @pos = TL_DEFAULTS["pos"]
+    @shuffle.shuffle! if @shuffle
   end
 
   def get_tracks(track_ids)
@@ -66,37 +77,66 @@ class DTAS::Tracklist # :nodoc:
     rv
   end
 
+  def _update_pos(pos, prev, list)
+    old = prev[pos]
+    _idx_of(list, old.track_id)
+  end
+
+  def shuffle=(bool)
+    prev = @shuffle
+    if bool
+      list = @shuffle = (prev ||= @list).shuffle
+    else
+      list = @list
+      @shuffle = false
+    end
+    @pos = _update_pos(@pos, prev, list) if @pos >= 0
+    @goto_pos = _update_pos(@goto_pos, prev, list) if @goto_pos
+  end
+
   def tracks
     @list.map(&:track_id)
   end
 
   def advance_track(repeat_ok = true)
-    return if @list.empty?
+    cur = @shuffle || @list
+    return if cur.empty?
     # @repeat == 1 for single track repeat
     repeat = repeat_ok ? @repeat : false
     next_pos = @goto_pos || @pos + (repeat == 1 ? 0 : 1)
     next_off = @goto_off # nil by default
     @goto_pos = @goto_off = nil
-    if @list[next_pos]
+    if cur[next_pos]
       @pos = next_pos
     elsif repeat
       next_pos = @pos = 0
     else
       return
     end
-    [ @list[next_pos].to_path, next_off ]
+    [ cur[next_pos].to_path, next_off ]
   end
 
   def cur_track
-    @pos >= 0 ? @list[@pos] : nil
+    @pos >= 0 ? (@shuffle || @list)[@pos] : nil
   end
 
   def add_track(track, after_track_id = nil, set_as_current = false)
     track = new_track(track)
     if after_track_id
-      idx = _idx_of(after_track_id) or
-        raise ArgumentError, "after_track_id invalid"
+      idx = _idx_of(@list, after_track_id) or
+                                  raise ArgumentError, 'after_track_id invalid'
+      if @shuffle
+        _idx_of(@shuffle, after_track_id) or
+                                  raise ArgumentError, 'after_track_id invalid'
+      end
       @list[idx, 1] = [ @list[idx], track ]
+
+      # add into random position if shuffling
+      if @shuffle
+        idx = rand(@shuffle.size)
+        @shuffle[idx, 1] = [ @shuffle[idx], track ]
+      end
+
       if set_as_current
         @pos = idx + 1
       else
@@ -104,21 +144,37 @@ class DTAS::Tracklist # :nodoc:
       end
     else # nil = first_track
       @list.unshift(track)
-      if set_as_current
-        @pos = 0
+
+      if @shuffle
+        if @shuffle.empty?
+          @shuffle << track
+          @pos = 0 if set_as_current
+        else
+          idx = rand(@shuffle.size)
+          @shuffle[idx, 1] = [ @shuffle[idx], track ]
+          @pos = idx + 1 if set_as_current
+        end
       else
-        @pos += 1 if @pos >= 0
+        if set_as_current
+          @pos = 0
+        else
+          @pos += 1 if @pos >= 0
+        end
       end
     end
     track.track_id
   end
 
-  def _idx_of(track_id)
-    @list.index { |t| t.track_id == track_id }
+  def _idx_of(list, track_id)
+    list.index { |t| t.track_id == track_id }
   end
 
   def remove_track(track_id)
-    idx = _idx_of(track_id) or return false
+    idx = _idx_of(@list, track_id) or return false
+    if @shuffle
+      si = _idx_of(@shuffle, track_id) or return false
+      @shuffle.delete_at(si)
+    end
     track = @list.delete_at(idx)
     len = @list.size
     if @pos >= len
@@ -129,9 +185,10 @@ class DTAS::Tracklist # :nodoc:
   end
 
   def go_to(track_id, offset_hhmmss = nil)
-    if idx = _idx_of(track_id)
+    list = @shuffle || @list
+    if idx = _idx_of(list, track_id)
       @goto_off = offset_hhmmss
-      return @list[@goto_pos = idx].to_path
+      return list[@goto_pos = idx].to_path
     end
     @goto_pos = nil
     # noop if track_id is invalid