Skip to content

Instantly share code, notes, and snippets.

@crummy
Created October 17, 2014 22:00
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save crummy/6e3973695d7b8adb672f to your computer and use it in GitHub Desktop.
Save crummy/6e3973695d7b8adb672f to your computer and use it in GitHub Desktop.
Sonos Now Playing

Description

A Dashing widget that searches for a Sonos device that is currently playing music, and displays Now Playing information and album artwork.

Utilises soffe's Sonos controller.

Dependencies

Please add the following lines to your gemfile:

require 'rubygems'
require 'sonos'

Installation

Place sonos.rb in /jobs.

Edit your dashboard and add these widgets:

<li data-row="1" data-col="1" data-sizex="1" data-sizey="1">
  <div data-id="nowplaying" data-view="Text" data-title="NOW PLAYING" data-text="Artist - Track"></div>
</li>

<li data-row="1" data-col="1" data-sizex="1" data-sizey="1">
  <div data-id="albumart" data-view="Image" data-title="Album Name"></div>
</li>

Screenshot

screenshot

require 'rubygems'
require 'sonos'
def send_transport_message(name, player, part = '<Speed>1</Speed>')
@transport_client ||= Savon.client endpoint: "http://#{player.ip}:#{Sonos::PORT}#{TRANSPORT_ENDPOINT}", namespace: Sonos::NAMESPACE, log: Sonos.logging_enabled
action = "#{TRANSPORT_XMLNS}##{name}"
message = %Q{<u:#{name} xmlns:u="#{TRANSPORT_XMLNS}"><InstanceID>0</InstanceID>#{part}</u:#{name}>}
@transport_client.call(name, soap_action: action, message: message)
end
# Get information about the currently playing track.
# @return [Hash] information about the current track.
def get_now_playing(player)
return nil if player == nil
response = send_transport_message('GetPositionInfo', player)
body = response.body[:get_position_info_response]
doc = Nokogiri::XML(body[:track_meta_data])
# No music
return nil if doc.children.length == 0
art_path = doc.xpath('//upnp:albumArtURI').inner_text
# TODO: No idea why this is necessary. Maybe its a Nokogiri thing
art_path.sub!('/getaa?s=1=x-sonos-http', '/getaa?s=1&u=x-sonos-http')
{
title: doc.xpath('//dc:title').inner_text,
artist: doc.xpath('//dc:creator').inner_text,
album: doc.xpath('//upnp:album').inner_text,
info: doc.xpath('//r:streamContent').inner_text,
queue_position: body[:track],
track_duration: body[:track_duration],
current_position: body[:rel_time],
uri: body[:track_uri],
album_art: "http://#{player.ip}:#{Sonos::PORT}#{art_path}"
}
end
TRANSPORT_ENDPOINT = '/MediaRenderer/AVTransport/Control'
TRANSPORT_XMLNS = 'urn:schemas-upnp-org:service:AVTransport:1'
system = Sonos::System.new
player = nil
system.speakers.each do |speaker|
if speaker.is_playing?
player = speaker
break
end
end
SCHEDULER.every '10s' do
metadata = get_now_playing(player)
if metadata and player
send_event("albumart", { image: metadata[:album_art] })
send_event("nowplaying", { text: metadata[:artist] + ' - ' + metadata[:title], moreinfo: player.name })
elsif player
send_event("albumart", { image: 'assets/sonoslogo.png' })
send_event("nowplaying", { text: "Nothing playing in " + player.name })
else
send_event("albumart", { image: 'assets/sonoslogo.png' })
send_event("nowplaying", { text: "Unable to connect to any player" })
end
end
@fliptrocity
Copy link

Any insight on how I can get this to point to a specific bridge rather than it picking a random one on the network?

@stigert
Copy link

stigert commented Mar 7, 2019

This isn't working for me. The dashboard won't load at all after installing this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment