class SpotiphyPlayer
Public Class Methods
new(options)
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 7 def initialize(options) @options = options @plaything = Plaything.new setup_session_callbacks # HACK not sure this is copacetic path = File.expand_path File.dirname(__FILE__) path = "#{path}/../../../" appkey = IO.read("#{path}spotify_appkey.key", encoding: "BINARY") config = Spotify::SessionConfig.new({ api_version: Spotify::API_VERSION.to_i, application_key: appkey, cache_location: "#{path}.spotify/", settings_location: "#{path}.spotify/", tracefile: "#{path}spotify_tracefile.txt", user_agent: "terminal_player gem", callbacks: Spotify::SessionCallbacks.new($session_callbacks), }) @session = create_session(config) login(get_env("SPOTIFY_USERNAME"), get_env("SPOTIFY_PASSWORD")) end
Public Instance Methods
get_track(uri)
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 48 def get_track(uri) link = Spotify.link_create_from_string(uri) track = Spotify.link_as_track(link) track end
next()
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 44 def next $end_of_track = true end
play()
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 31 def play u = @options[:url] if u[':track:'] play_track_from_uri u elsif u[':playlist:'] play_playlist u elsif u[':album:'] play_album u else puts "unsupported URI #{u}" end end
play_album(uri)
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 85 def play_album(uri) link = Spotify.link_create_from_string(uri) browser = Spotify.albumbrowse_create(@session, Spotify.link_as_album(link), proc { }, nil) poll(@session) { Spotify.albumbrowse_is_loaded(browser) } # album = Spotify.albumbrowse_album(browser) num_tracks = Spotify.albumbrowse_num_tracks(browser) # TODO this should reset channel # puts "\nPlaying #{Spotify.album_name(album)} (#{Spotify.album_year(album)}), #{num_tracks} tracks" 0.upto(num_tracks - 1) do |i| track = Spotify.albumbrowse_track(browser, i) play_track track end end
play_playlist(uri)
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 71 def play_playlist(uri) link = Spotify.link_create_from_string(uri) plist = Spotify.playlist_create(@session, link) poll(@session) { Spotify.playlist_is_loaded(plist) } num_tracks = Spotify.playlist_num_tracks(plist) # TODO this should reset channel # puts "\nPlaying #{Spotify.playlist_name(plist)}, #{num_tracks} tracks, " + # "#{Spotify.playlist_num_subscribers(plist)} subscribers" 0.upto(num_tracks - 1) do |i| track = Spotify.playlist_track(plist, i) play_track track end end
play_track(track)
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 59 def play_track(track) wait_for_track_to_load track artist = Spotify.track_artist(track, 0) notify "SPOTTY #{Spotify.track_name(track)} - #{Spotify.artist_name(artist)}" begin play_track_raw track wait_for_track_to_end rescue => e puts "play_track: error playing track: #{e}" end end
play_track_from_uri(uri)
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 54 def play_track_from_uri(uri) track = get_track(uri) play_track track end
play_track_raw(track)
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 99 def play_track_raw(track) Spotify.try(:session_player_play, @session, false) Spotify.try(:session_player_load, @session, track) Spotify.try(:session_player_play, @session, true) end
wait_for_track_to_end()
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 105 def wait_for_track_to_end poll(@session) { $end_of_track } $end_of_track = false end
wait_for_track_to_load(track)
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 110 def wait_for_track_to_load(track) poll(@session) { Spotify.track_is_loaded(track) } end
Private Instance Methods
create_session(config)
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 135 def create_session(config) FFI::MemoryPointer.new(Spotify::Session) do |ptr| Spotify.try(:session_create, config, ptr) return Spotify::Session.new(ptr.read_pointer) end end
get_env(name)
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 198 def get_env(name) ENV.fetch(name) do raise "set the #{name} environment variable" end end
login(u, p)
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 121 def login(u, p) Spotify.session_login(@session, u, p, false, nil) poll(@session) { Spotify.session_connectionstate(@session) == :logged_in } end
notify(message)
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 116 def notify(message) changed notify_observers(Time.now, message) end
poll(session)
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 126 def poll(session) until yield FFI::MemoryPointer.new(:int) do |ptr| Spotify.session_process_events(session, ptr) end sleep(0.1) end end
setup_session_callbacks()
click to toggle source
# File lib/terminal_player/spotiphy/spotiphy_player.rb, line 142 def setup_session_callbacks # these must remain global. i think. $session_callbacks = { log_message: proc do |session, message| #$logger.info("session (log message)") { message } end, logged_in: proc do |session, error| #$logger.debug("session (logged in)") { Spotify::Error.explain(error) } end, logged_out: proc do |session| #$logger.debug("session (logged out)") { "logged out!" } end, streaming_error: proc do |session, error| #$logger.error("session (player)") { "streaming error %s" % Spotify::Error.explain(error) } end, start_playback: proc do |session| #$logger.debug("session (player)") { "start playback" } @plaything.play end, stop_playback: proc do |session| #$logger.debug("session (player)") { "stop playback" } @plaything.stop end, get_audio_buffer_stats: proc do |session, stats| stats[:samples] = @plaything.queue_size stats[:stutter] = @plaything.drops #$logger.debug("session (player)") { "queue size [#{stats[:samples]}, #{stats[:stutter]}]" } end, music_delivery: proc do |session, format, frames, num_frames| if num_frames == 0 #$logger.debug("session (player)") { "music delivery audio discontuity" } @plaything.stop 0 else frames = FrameReader.new(format[:channels], format[:sample_type], num_frames, frames) consumed_frames = @plaything.stream(frames, format.to_h) #$logger.debug("session (player)") { "music delivery #{consumed_frames} of #{num_frames}" } consumed_frames end end, end_of_track: proc do |session| $end_of_track = true #$logger.debug("session (player)") { "end of track" } @plaything.stop end, } end