Class: MusicBox::Player
- Inherits:
-
Object
- Object
- MusicBox::Player
- Defined in:
- lib/musicbox/player.rb
Constant Summary collapse
- Keymap =
{ 'a' => :play_random_album, 't' => :play_random_tracks, 'r' => :play_album_for_current_track, 'n' => :play_next_track, 'p' => :play_previous_track, ' ' => :toggle_pause, '<' => :skip_backward, '>' => :skip_forward, '^' => :skip_to_beginning, 'e' => :toggle_equalizer, 'E' => :next_equalizer, 'q' => :quit, '.' => :show_playlist, '?' => :show_keymap, }
- ObservedProperties =
{ 'playlist' => :playlist, 'playlist-pos' => :playlist_position, 'pause' => :pause_state, 'time-pos' => :time_position, }
- SeekSeconds =
30
Instance Attribute Summary collapse
-
#albums ⇒ Object
Returns the value of attribute albums.
-
#audio_device ⇒ Object
Returns the value of attribute audio_device.
-
#equalizers ⇒ Object
Returns the value of attribute equalizers.
-
#mpv_log_level ⇒ Object
Returns the value of attribute mpv_log_level.
Instance Method Summary collapse
-
#initialize(**params) ⇒ Player
constructor
A new instance of Player.
- #next_equalizer ⇒ Object
- #play ⇒ Object
- #play_album_for_current_track ⇒ Object
- #play_next_track ⇒ Object
- #play_previous_track ⇒ Object
- #play_random_album ⇒ Object
- #play_random_tracks ⇒ Object
- #play_tracks(tracks) ⇒ Object
- #playlist_changed(value) ⇒ Object
-
#property_changed(name, value) ⇒ Object
callbacks from MPV.
-
#quit ⇒ Object
commands called by interface.
- #random_album ⇒ Object
- #random_tracks(length:) ⇒ Object
- #read_albums ⇒ Object
- #set_current_equalizer ⇒ Object
- #setup_interface ⇒ Object
- #setup_mpv ⇒ Object
- #show_keymap ⇒ Object
- #show_playlist ⇒ Object
- #shutdown_mpv ⇒ Object
- #skip_backward ⇒ Object
- #skip_forward ⇒ Object
- #skip_to_beginning ⇒ Object
- #toggle_equalizer ⇒ Object
- #toggle_pause ⇒ Object
Constructor Details
#initialize(**params) ⇒ Player
Returns a new instance of Player.
34 35 36 37 38 39 |
# File 'lib/musicbox/player.rb', line 34 def initialize(**params) { mpv_log_level: 'error', }.merge(params).each { |k, v| send("#{k}=", v) } @playlist_file = Path.new('/tmp/mpv_playlist') end |
Instance Attribute Details
#albums ⇒ Object
Returns the value of attribute albums.
29 30 31 |
# File 'lib/musicbox/player.rb', line 29 def albums @albums end |
#audio_device ⇒ Object
Returns the value of attribute audio_device.
30 31 32 |
# File 'lib/musicbox/player.rb', line 30 def audio_device @audio_device end |
#equalizers ⇒ Object
Returns the value of attribute equalizers.
32 33 34 |
# File 'lib/musicbox/player.rb', line 32 def equalizers @equalizers end |
#mpv_log_level ⇒ Object
Returns the value of attribute mpv_log_level.
31 32 33 |
# File 'lib/musicbox/player.rb', line 31 def mpv_log_level @mpv_log_level end |
Instance Method Details
#next_equalizer ⇒ Object
243 244 245 246 247 248 249 |
# File 'lib/musicbox/player.rb', line 243 def next_equalizer if @equalizers @current_equalizer &&= @equalizers[@equalizers.index(@current_equalizer) + 1] @current_equalizer ||= @equalizers.first set_current_equalizer end end |
#play ⇒ Object
41 42 43 44 45 46 47 48 49 50 |
# File 'lib/musicbox/player.rb', line 41 def play raise Error, "No albums to play" if @albums.nil? || @albums.empty? read_albums @dispatcher = IO::Dispatcher.new setup_interface setup_mpv puts "[ready]" play_random_album @dispatcher.run end |
#play_album_for_current_track ⇒ Object
173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/musicbox/player.rb', line 173 def play_album_for_current_track if @properties.playlist_position entry = @properties.playlist[@properties.playlist_position] track_path = Path.new(entry.filename) album = @album_for_track_path[track_path] \ or raise Error, "Can't determine album for track file: #{track_path}" play_tracks(album.tracks) else puts "no current track" end end |
#play_next_track ⇒ Object
149 150 151 152 153 154 155 |
# File 'lib/musicbox/player.rb', line 149 def play_next_track if @properties.playlist_position && @properties.playlist_position < @properties.playlist.count - 1 @mpv.command('playlist-next') else puts 'no next track' end end |
#play_previous_track ⇒ Object
157 158 159 160 161 162 163 |
# File 'lib/musicbox/player.rb', line 157 def play_previous_track if @properties.playlist_position && @properties.playlist_position > 0 @mpv.command('playlist-prev') else puts 'no previous track' end end |
#play_random_album ⇒ Object
165 166 167 |
# File 'lib/musicbox/player.rb', line 165 def play_random_album play_tracks(random_album.tracks) end |
#play_random_tracks ⇒ Object
169 170 171 |
# File 'lib/musicbox/player.rb', line 169 def play_random_tracks play_tracks(random_tracks(length: 10)) end |
#play_tracks(tracks) ⇒ Object
232 233 234 235 236 |
# File 'lib/musicbox/player.rb', line 232 def play_tracks(tracks) @playlist_file.dirname.mkpath @playlist_file.write(tracks.map(&:path).join("\n")) @mpv.command('loadlist', @playlist_file.to_s) end |
#playlist_changed(value) ⇒ Object
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/musicbox/player.rb', line 125 def playlist_changed(value) @current_track = @playlist = nil if @properties.playlist @playlist = @properties.playlist.map do |entry| track_path = Path.new(entry.filename) album = @album_for_track_path[track_path] \ or raise Error, "Can't determine album for track file: #{track_path}" track = album.tracks.find { |t| t.path == track_path } \ or raise Error, "Can't determine track for track file: #{track_path}" @current_track = track if entry.current track end end show_playlist end |
#property_changed(name, value) ⇒ Object
callbacks from MPV
265 266 267 268 269 270 |
# File 'lib/musicbox/player.rb', line 265 def property_changed(name, value) # ;;pp(name => value) unless name == 'time-pos' key = ObservedProperties[name] or raise @properties[key] = value send("#{key}_changed", value) rescue NoMethodError end |
#quit ⇒ Object
commands called by interface
145 146 147 |
# File 'lib/musicbox/player.rb', line 145 def quit Kernel.exit(0) end |
#random_album ⇒ Object
113 114 115 |
# File 'lib/musicbox/player.rb', line 113 def random_album @albums.shuffle.first end |
#random_tracks(length:) ⇒ Object
117 118 119 120 121 122 123 |
# File 'lib/musicbox/player.rb', line 117 def random_tracks(length:) tracks = Set.new while tracks.length < length tracks << random_album.tracks.shuffle.first end tracks.to_a end |
#read_albums ⇒ Object
104 105 106 107 108 109 110 111 |
# File 'lib/musicbox/player.rb', line 104 def read_albums @album_for_track_path = {} @albums.each do |album| album.tracks.each do |track| @album_for_track_path[track.path] = album end end end |
#set_current_equalizer ⇒ Object
251 252 253 254 255 256 257 258 259 |
# File 'lib/musicbox/player.rb', line 251 def set_current_equalizer if @current_equalizer puts "[equalizer: %s <%s>]" % [ @current_equalizer.name, @equalizer_enabled ? 'enabled' : 'disabled', ] @mpv.command('af', 'set', @current_equalizer.to_s(enabled: @equalizer_enabled)) end end |
#setup_interface ⇒ Object
89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/musicbox/player.rb', line 89 def setup_interface @stty_old_params = `stty -g`.chomp at_exit { system('stty', @stty_old_params) } system('stty', 'cbreak', '-echo') @dispatcher.add_io_handler(input: STDIN) do |io| key = io.sysread(1) if (command = Keymap[key]) puts "[#{command_description(command)}]" send(command) else puts "unknown key: %p" % key end end end |
#setup_mpv ⇒ Object
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 |
# File 'lib/musicbox/player.rb', line 52 def setup_mpv @mpv = MPVClient.new( 'mpv-log-level' => @mpv_log_level, 'audio-device' => @audio_device, 'audio-display' => 'no', 'vo' => 'null', 'volume' => 100) @mpv.register_event('log-message') do |event| ;;pp(log: event) end @mpv.command('request_log_messages', @mpv_log_level) if @mpv_log_level @properties = HashStruct.new ObservedProperties.each do |name, key| @mpv.observe_property(name) { |n, v| property_changed(n, v) } end if @equalizers @equalizer_enabled = true next_equalizer end @dispatcher.add_io_handler(input: @mpv.socket) do |io| @mpv.process_response end @dispatcher.add_io_handler(exception: @mpv.socket) do |io| shutdown_mpv end at_exit { shutdown_mpv } end |
#show_keymap ⇒ Object
226 227 228 229 230 |
# File 'lib/musicbox/player.rb', line 226 def show_keymap Keymap.each do |key, command| puts "%-8s %s" % [key_description(key), command_description(command)] end end |
#show_playlist ⇒ Object
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/musicbox/player.rb', line 207 def show_playlist if @playlist system('clear') if @current_track @current_track.album.show_cover(width: 'auto', height: 20, preserve_aspect_ratio: false) puts end @playlist.each_with_index do |track, i| puts '%1s %2d. %-40.40s | %-40.40s | %-40.40s' % [ track == @current_track ? '>' : '', i + 1, track.title, track.album.title, track.album.artist, ] end end end |
#shutdown_mpv ⇒ Object
80 81 82 83 84 85 86 87 |
# File 'lib/musicbox/player.rb', line 80 def shutdown_mpv if @mpv @mpv.command('quit') @dispatcher.remove_io_handler(input: @mpv.socket, exception: @mpv.socket) @mpv.stop @mpv = nil end end |
#skip_backward ⇒ Object
189 190 191 192 193 |
# File 'lib/musicbox/player.rb', line 189 def skip_backward if @properties.time_position && @properties.time_position > 0 @mpv.command('seek', -SeekSeconds) end end |
#skip_forward ⇒ Object
195 196 197 198 199 |
# File 'lib/musicbox/player.rb', line 195 def skip_forward if @properties.time_position @mpv.command('seek', SeekSeconds) end end |
#skip_to_beginning ⇒ Object
201 202 203 204 205 |
# File 'lib/musicbox/player.rb', line 201 def skip_to_beginning if @properties.time_position && @properties.time_position > 0 @mpv.command('seek', 0, 'absolute-percent') end end |
#toggle_equalizer ⇒ Object
238 239 240 241 |
# File 'lib/musicbox/player.rb', line 238 def toggle_equalizer @equalizer_enabled = !@equalizer_enabled set_current_equalizer end |
#toggle_pause ⇒ Object
185 186 187 |
# File 'lib/musicbox/player.rb', line 185 def toggle_pause @mpv.set_property('pause', !@properties.pause_state) end |