Class: Plllayer
- Inherits:
-
Object
- Object
- Plllayer
- Extended by:
- TimeHelpers
- Defined in:
- lib/plllayer.rb,
lib/plllayer/time_helpers.rb,
lib/plllayer/single_player.rb,
lib/plllayer/single_players/nop.rb,
lib/plllayer/single_players/mplayer.rb
Overview
Plllayer provides an interface to an external media player, such as mplayer. It contains a playlist of tracks, which may be as simple as an Array of paths to some audio files. You can then control the playback of this playlist by calling various command-like methods, like play, pause, seek, skip, shuffle, and so on.
Defined Under Namespace
Modules: SinglePlayers, TimeHelpers Classes: SinglePlayer
Constant Summary collapse
- SINGLE_PLAYERS =
{ mplayer: Plllayer::SinglePlayers::MPlayer, nop: Plllayer::SinglePlayers::Nop }
- FileNotFoundError =
Raise this exception when the file at the given track path doesn’t exist.
Class.new(ArgumentError)
- InvalidAudioFileError =
Raise this one when the file can’t be played for whatever reason
Class.new(ArgumentError)
Instance Attribute Summary collapse
-
#repeat_mode ⇒ Object
readonly
Returns the value of attribute repeat_mode.
Instance Method Summary collapse
-
#append(*tracks) ⇒ Object
(also: #<<)
Append tracks to the playlist.
-
#back(n = 1) ⇒ Object
Play the previous track.
-
#clear ⇒ Object
Stop playback and empty the playlist.
-
#formatted_position(options = {}) ⇒ Object
Returns the current position of the currently-playing track, as a String like “1:23”.
-
#formatted_track_length(options = {}) ⇒ Object
Returns the length of the currently-playing track, as a String like “1:23”.
-
#initialize(*args) ⇒ Plllayer
constructor
Create a new Plllayer.
-
#insert(*tracks) ⇒ Object
Insert one or more tracks in the playlist, right after the currently-playing track.
-
#insert_at(index, *tracks) ⇒ Object
Insert one or more tracks anywhere in the playlist.
-
#mute ⇒ Object
Mute the volume.
-
#muted? ⇒ Boolean
Check if volume is muted.
-
#pause ⇒ Object
Pause playback.
-
#paused? ⇒ Boolean
Check if playback is paused.
-
#play ⇒ Object
Start playing the playlist from beginning to end.
-
#playing? ⇒ Boolean
Check if the playlist is being played.
-
#playlist ⇒ Object
Returns a copy of the playlist.
-
#position ⇒ Object
Returns the current position of the currently-playing track, in milliseconds.
-
#remove(*tracks) ⇒ Object
Remove one or more tracks from the playlist by value.
-
#remove_at(index, n = 1) ⇒ Object
Remove one or more tracks from the playlist at a particular index.
-
#repeat(one_or_all_or_off) ⇒ Object
Set the repeat behaviour of the playlist.
-
#restart ⇒ Object
Play the currently-playing track from the beginning.
-
#resume ⇒ Object
Resume playback.
-
#seek(where) ⇒ Object
Seek to a particular position within the currently-playing track.
-
#shuffle ⇒ Object
Shuffle the playlist.
-
#skip(n = 1) ⇒ Object
Play the next track.
-
#sort(&by) ⇒ Object
Sorts the playlist.
-
#speed ⇒ Object
Get the playback speed as a Float.
-
#speed=(new_speed) ⇒ Object
Set the playback speed as a Float.
-
#stop ⇒ Object
Stop playback.
-
#track ⇒ Object
Get the currently-playing track, or the track that’s about to play if you’re paused between tracks.
-
#track_index ⇒ Object
Get the index of the currently-playing track, or of the track that’s about to play if you’re paused between tracks.
-
#track_length ⇒ Object
Returns the length of the currently-playing track, in milliseconds.
-
#track_path ⇒ Object
Get the path to the audio file of the currently-playing track.
-
#unmute ⇒ Object
Unmute the volume.
-
#volume ⇒ Object
Get the volume, as a percentage.
-
#volume=(new_volume) ⇒ Object
Set the volume, as a percentage.
Methods included from TimeHelpers
Constructor Details
#initialize(*args) ⇒ Plllayer
Create a new Plllayer. Optionally, you can pass in an initial playlist to be loaded (won’t start playing until you call #play). You can also pass the :external_player option to specify the preferred external player to use. Otherwise, it will try to figure out what external players are available, and attempt to use the best one available.
However, only mplayer is supported at the moment, so this option isn’t useful right now.
TODO: check if external player is available before trying to use it.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/plllayer.rb', line 36 def initialize(*args) = {} = args.pop if args.last.is_a? Hash [:external_player] ||= :mplayer # Look up the single player class, raise error if it doesn't exist. single_player_class = SINGLE_PLAYERS[[:external_player].to_sym] if single_player_class.nil? raise NotImplementedError, "external player #{[:external_player]} not supported" end @single_player = single_player_class.new @playlist = [] append(args.first) unless args.empty? @index = nil @paused = false @playing = false @repeat_mode = nil @index_mutex = Mutex.new end |
Instance Attribute Details
#repeat_mode ⇒ Object (readonly)
Returns the value of attribute repeat_mode.
24 25 26 |
# File 'lib/plllayer.rb', line 24 def repeat_mode @repeat_mode end |
Instance Method Details
#append(*tracks) ⇒ Object Also known as: <<
Append tracks to the playlist. Can be done while the playlist is playing. A track is either a String containing the path to the audio file, or an object with a #location method that returns the path to the audio file. An ArgumentError is raised when you try to pass a non-track.
This method is aliased as the << operator.
64 65 66 67 68 69 70 71 72 73 |
# File 'lib/plllayer.rb', line 64 def append(*tracks) tracks = tracks.flatten tracks.each do |track| if !track.is_a?(String) && !track.respond_to?(:location) raise ArgumentError, "a #{track.class} is not a track (try adding a #location method)" end end @playlist += tracks @playlist.dup end |
#back(n = 1) ⇒ Object
Play the previous track. Pass a number to go back that many tracks. Treats the playlist like a circular array if the repeat mode is :all.
270 271 272 |
# File 'lib/plllayer.rb', line 270 def back(n = 1) change_track(-n) end |
#clear ⇒ Object
Stop playback and empty the playlist.
170 171 172 173 174 |
# File 'lib/plllayer.rb', line 170 def clear stop @playlist.clear true end |
#formatted_position(options = {}) ⇒ Object
Returns the current position of the currently-playing track, as a String like “1:23”.
392 393 394 |
# File 'lib/plllayer.rb', line 392 def formatted_position( = {}) Plllayer.format_time(position, ) end |
#formatted_track_length(options = {}) ⇒ Object
Returns the length of the currently-playing track, as a String like “1:23”.
406 407 408 409 410 |
# File 'lib/plllayer.rb', line 406 def formatted_track_length( = {}) if length = track_length Plllayer.format_time(length, ) end end |
#insert(*tracks) ⇒ Object
Insert one or more tracks in the playlist, right after the currently-playing track. If no track is playing, insert to the head of the playlist.
79 80 81 82 83 |
# File 'lib/plllayer.rb', line 79 def insert(*tracks) after = @index || -1 _unsynchronized_insert_at(after + 1, *tracks) @playlist.dup end |
#insert_at(index, *tracks) ⇒ Object
Insert one or more tracks anywhere in the playlist. A negative index may be given to refer to the end of the playlist.
88 89 90 91 92 93 94 95 96 |
# File 'lib/plllayer.rb', line 88 def insert_at(index, *tracks) index = @playlist.length + index + 1 if index < 0 unless (0..@playlist.length).include? index raise IndexError, "index is out of range" end @playlist.insert(index, *tracks) @index += tracks.length if @index && index < @index @playlist.dup end |
#mute ⇒ Object
Mute the volume.
334 335 336 |
# File 'lib/plllayer.rb', line 334 def mute @single_player.mute end |
#muted? ⇒ Boolean
Check if volume is muted.
344 345 346 |
# File 'lib/plllayer.rb', line 344 def muted? @single_player.muted? end |
#pause ⇒ Object
Pause playback.
218 219 220 221 222 223 224 225 |
# File 'lib/plllayer.rb', line 218 def pause if && !paused? @paused = true @single_player.pause else false end end |
#paused? ⇒ Boolean
Check if playback is paused.
177 178 179 |
# File 'lib/plllayer.rb', line 177 def paused? @paused end |
#play ⇒ Object
Start playing the playlist from beginning to end.
190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/plllayer.rb', line 190 def play if !@playlist.empty? && ! @playing = true @paused = false @index = 0 play_track true else false end end |
#playing? ⇒ Boolean
Check if the playlist is being played. Whether playback is paused doesn’t affect this. False is only returned if either (1) #play was never called, (2) #stop has been called, or (3) playback stopped after finishing playing all the songs.
185 186 187 |
# File 'lib/plllayer.rb', line 185 def @playing end |
#playlist ⇒ Object
Returns a copy of the playlist.
143 144 145 |
# File 'lib/plllayer.rb', line 143 def playlist @playlist.dup end |
#position ⇒ Object
Returns the current position of the currently-playing track, in milliseconds.
386 387 388 |
# File 'lib/plllayer.rb', line 386 def position @single_player.position || 0 end |
#remove(*tracks) ⇒ Object
Remove one or more tracks from the playlist by value. If the currently-playing track is removed, it will start playing the next track in the playlist.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/plllayer.rb', line 101 def remove(*tracks) n = nil n = tracks.pop if tracks.last.is_a?(Fixnum) index = 0 current_track_removed = false @playlist = @playlist.inject([]) do |playlist, track| if tracks.include?(track) && (n.nil? || n > 0) n &&= n - 1 @index -= 1 if @index && index < @index current_track_removed = true if index == @index else playlist << track end index += 1 playlist end _unsynchronized_change_track(0) if current_track_removed @playlist.dup end |
#remove_at(index, n = 1) ⇒ Object
Remove one or more tracks from the playlist at a particular index. A negative index may be given to refer to the end of the playlist. If the currently-playing track is removed, it will start playing the next track in the playlist.
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/plllayer.rb', line 125 def remove_at(index, n = 1) index = @playlist.length + index if index < 0 if @playlist.empty? || index < 0 || index + n > @playlist.length raise IndexError, "index is out of range" end @playlist.slice!(index, n) if @index && @index > index if @index < index + n _unsynchronized_change_track(index - @index) else @index -= n end end @playlist.dup end |
#repeat(one_or_all_or_off) ⇒ Object
Set the repeat behaviour of the playlist. There are three possible values:
:one repeat a single track over and over
:all repeat the whole playlist, treating it like a circular array
:off play songs consecutively, stop playback when done
The default, of course, is :off.
249 250 251 252 253 254 255 256 257 258 259 260 261 |
# File 'lib/plllayer.rb', line 249 def repeat(one_or_all_or_off) case one_or_all_or_off when :one @repeat_mode = :one when :all @repeat_mode = :all when :off @repeat_mode = nil else raise ArgumentError end true end |
#restart ⇒ Object
Play the currently-playing track from the beginning.
264 265 266 |
# File 'lib/plllayer.rb', line 264 def restart change_track(0) end |
#resume ⇒ Object
Resume playback.
228 229 230 231 232 233 234 235 236 237 238 239 240 |
# File 'lib/plllayer.rb', line 228 def resume if && paused? @paused = false if @single_player. @single_player.resume else play_track @track true end else false end end |
#seek(where) ⇒ Object
Seek to a particular position within the currently-playing track. There are multiple ways to specify where to seek to:
seek 10000 # seek 10000 milliseconds forward, relative to the current position
seek -5000 # seek 5000 milliseconds backward
seek "3:45" # seek to the absolute position 3 minutes and 45 seconds
seek "1:03:45.123" # seek to 1 hour, 3 minutes, 45 seconds, 123 milliseconds
seek 3..45 # syntax sugar for seeking to "3:45"
seek 3..45.123 # syntax sugar for seeking to "3:45.123"
seek abs: 150000 # seek to the absolute position 150000 milliseconds
seek percent: 80 # seek to 80% of the way through the track
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 |
# File 'lib/plllayer.rb', line 292 def seek(where) if paused? && !@single_player. resume pause end case where when Integer @single_player.seek(where, :relative) when Range seconds = where.begin * 60 + where.end @single_player.seek(seconds * 1000, :absolute) when String @single_player.seek(Plllayer.parse_time(where), :absolute) when Hash if where[:abs] if where[:abs].is_a? Integer @single_player.seek(where[:abs], :absolute) else seek(where[:abs]) end elsif where[:percent] @single_player.seek(where[:percent], :percent) end else raise ArgumentError, "seek doesn't take a #{where.class}" end end |
#shuffle ⇒ Object
Shuffle the playlist. If this is done while the playlist is playing, the current song will go to the top of the playlist and the rest of the songs will be shuffled.
361 362 363 364 365 366 367 368 369 370 |
# File 'lib/plllayer.rb', line 361 def shuffle current_track = track @playlist.shuffle! if index = @playlist.index(current_track) @playlist[0], @playlist[index] = @playlist[index], @playlist[0] @index = 0 end true end |
#skip(n = 1) ⇒ Object
Play the next track. Pass a number to go forward that many tracks. Treats the playlist like a circular array if the repeat mode is :all.
276 277 278 |
# File 'lib/plllayer.rb', line 276 def skip(n = 1) change_track(n) end |
#sort(&by) ⇒ Object
Sorts the playlist. Delegates to Array#sort, so a block may be passed to specify what the tracks should be sorted by.
This method is safe to call while the playlist is playing.
376 377 378 379 380 381 382 383 |
# File 'lib/plllayer.rb', line 376 def sort(&by) current_track = track @playlist.sort! &by if @index = @playlist.index(current_track) end true end |
#speed ⇒ Object
Get the playback speed as a Float. 1.0 is normal speed, 2.0 is double speed, 0.5 is half-speed, and so on.
323 324 325 |
# File 'lib/plllayer.rb', line 323 def speed @single_player.speed || 1.0 end |
#speed=(new_speed) ⇒ Object
Set the playback speed as a Float. 1.0 is normal speed, 2.0 is double speed, 0.5 is half-speed, and so on.
329 330 331 |
# File 'lib/plllayer.rb', line 329 def speed=(new_speed) @single_player.speed = new_speed end |
#stop ⇒ Object
Stop playback.
203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/plllayer.rb', line 203 def stop if @single_player.stop @track = nil @index = nil @paused = false @playing = false true else false end end |
#track ⇒ Object
Get the currently-playing track, or the track that’s about to play if you’re paused between tracks. Returns nil if playback is stopped.
149 150 151 |
# File 'lib/plllayer.rb', line 149 def track @index ? @playlist[@index] : nil end |
#track_index ⇒ Object
Get the index of the currently-playing track, or of the track that’s about to play if you’re paused between tracks. Returns nil if playback is stopped.
156 157 158 |
# File 'lib/plllayer.rb', line 156 def track_index @index end |
#track_length ⇒ Object
Returns the length of the currently-playing track, in milliseconds.
397 398 399 400 401 402 403 |
# File 'lib/plllayer.rb', line 397 def track_length if paused? && !@single_player. resume pause end @single_player.track_length end |
#track_path ⇒ Object
Get the path to the audio file of the currently-playing track.
161 162 163 164 165 166 167 |
# File 'lib/plllayer.rb', line 161 def track_path if track.respond_to? :location track.location else track end end |
#unmute ⇒ Object
Unmute the volume.
339 340 341 |
# File 'lib/plllayer.rb', line 339 def unmute @single_player.unmute end |
#volume ⇒ Object
Get the volume, as a percentage.
349 350 351 |
# File 'lib/plllayer.rb', line 349 def volume @single_player.volume end |
#volume=(new_volume) ⇒ Object
Set the volume, as a percentage.
354 355 356 |
# File 'lib/plllayer.rb', line 354 def volume=(new_volume) @single_player.volume = new_volume end |