dtas.git  about / heads / tags
duct tape audio suite for *nix
blob 6856648168308bf048e15c5cd824ad247fd0b00a 3164 bytes (raw)
$ git show v0.5.0:lib/dtas/tracklist.rb	# shows this blob on the CLI

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
 
# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
require_relative '../dtas'
require_relative 'serialize'

# this is inspired by the MPRIS 2.0 TrackList spec
class DTAS::Tracklist # :nodoc:
  include DTAS::Serialize
  attr_accessor :repeat # true, false, 1

  SIVS = %w(list pos repeat)
  TL_DEFAULTS = {
    "list" => [],
    "pos" => -1,
    "repeat" => false,
  }

  def self.load(hash)
    obj = new
    obj.instance_eval do
      list = hash["list"] and @list.replace(list)
      @pos = hash["pos"] || -1
      @repeat = hash["repeat"] || false
    end
    obj
  end

  def to_hsh
    ivars_to_hash(SIVS).delete_if { |k,v| TL_DEFAULTS[k] == v }
  end

  def initialize
    TL_DEFAULTS.each { |k,v| instance_variable_set("@#{k}", v) }
    @list = []
    @goto_off = @goto_pos = nil
  end

  def reset
    @goto_off = @goto_pos = nil
    @pos = TL_DEFAULTS["pos"]
  end

  def size
    @list.size
  end

  # caching this probably isn't worth it.  a tracklist is usually
  # a few tens of tracks, maybe a hundred at most.
  def _track_id_map
    by_track_id = {}
    @list.each_with_index { |t,i| by_track_id[t.object_id] = i }
    by_track_id
  end

  def get_tracks(track_ids)
    by_track_id = _track_id_map
    track_ids.map do |track_id|
      idx = by_track_id[track_id]
      # dtas-mpris fills in the metadata, we just return a path
      [ track_id, idx ? @list[idx] : nil ]
    end
  end

  def tracks
    @list.map { |t| t.object_id }
  end

  def advance_track(repeat_ok = true)
    return if @list.empty?
    # @repeat == 1 for single track repeat
    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]
      @pos = next_pos
    elsif @repeat && repeat_ok
      next_pos = @pos = 0
    else
      return
    end
    [ @list[next_pos], next_off ]
  end

  def cur_track
    @pos >= 0 ? @list[@pos] : nil
  end

  def add_track(track, after_track_id = nil, set_as_current = false)
    if after_track_id
      by_track_id = _track_id_map
      idx = by_track_id[after_track_id] or
        raise ArgumentError, "after_track_id invalid"
      @list[idx, 1] = [ @list[idx], track ]
      @pos = idx + 1 if set_as_current
    else # nil = first_track
      @list.unshift(track)
      @pos = 0 if set_as_current
    end
    track.object_id
  end

  def remove_track(track_id)
    by_track_id = _track_id_map
    if idx = by_track_id.delete(track_id)
      @list[idx] = nil
      @list.compact!
      # TODO: what do we do with @pos (and the currently-playing track)
    end
  end

  def go_to(track_id, offset_hhmmss = nil)
    by_track_id = _track_id_map
    if idx = by_track_id[track_id]
      @goto_off = offset_hhmmss
      return @list[@goto_pos = idx]
    end
    @goto_pos = nil
    # noop if track_id is invalid
  end

  def previous!
    return if @list.empty?
    prev_idx = @pos - 1
    if prev_idx < 0
      # stop playback if nothing to go back to.
      prev_idx = @repeat ? @list.size - 1 : @list.size
    end
    @goto_pos = prev_idx
  end
end

git clone git://80x24.org/dtas.git
git clone https://80x24.org/dtas.git