The branch, frodo has been updated
via 18ea10ddd44b06902d28333518d6ef353dfbc41d (commit)
from 174c6718d269fa07d5f2cc219831b01d4c514e01 (commit)
- Log -----------------------------------------------------------------
http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/scripts;a=commit;h=18ea10ddd44b06902d28333518d6ef353dfbc41d
commit 18ea10ddd44b06902d28333518d6ef353dfbc41d
Author: Martijn Kaijser <[email protected]>
Date: Sat Feb 1 14:16:20 2014 +0100
[script.sonos] 1.0.2
diff --git a/script.sonos/addon.xml b/script.sonos/addon.xml
index 97a97e8..64bb099 100644
--- a/script.sonos/addon.xml
+++ b/script.sonos/addon.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<addon id="script.sonos" name="Sonos" version="1.0.0"
provider-name="robwebset">
+<addon id="script.sonos" name="Sonos" version="1.0.2"
provider-name="robwebset">
<requires>
<import addon="xbmc.python" version="2.1.0"/>
<import addon="script.module.requests" version="1.1.0"/>
diff --git a/script.sonos/changelog.txt b/script.sonos/changelog.txt
index 624356f..a9b44bf 100644
--- a/script.sonos/changelog.txt
+++ b/script.sonos/changelog.txt
@@ -1,2 +1,9 @@
+v1.0.2
+- Mini Sonos controller added with album art
+
+v1.0.1
+- Don't display notification on startup if Sonos is not playing
+- Initial version of controller
+
v1.0.0:
- Initial release
diff --git a/script.sonos/default.py b/script.sonos/default.py
index 62cf4d3..8c242af 100644
--- a/script.sonos/default.py
+++ b/script.sonos/default.py
@@ -22,6 +22,9 @@ from soco import SoCo
from soco import SonosDiscovery
from soco import SoCoException
+# Import the Mock Sonos class for testing where there is no live Sonos system
+from mocksonos import TestMockSonos
+
def log(txt):
if __addon__.getSetting( "logEnabled" ) == "true":
@@ -42,30 +45,358 @@ class Settings():
return __addon__.getSetting("ipAddress")
@staticmethod
- def getNotificationDisplayDuration():
+ def getRefreshInterval():
# Convert to milliseconds before returning
- return int(float(__addon__.getSetting("notifDisplayDuration"))) * 1000
+ return int(float(__addon__.getSetting("refreshInterval")) * 1000)
@staticmethod
- def getNotificationCheckFrequency():
- # Convert to milliseconds before returning
- return int(float(__addon__.getSetting("notifCheckFrequency"))) * 1000
+ def useTestData():
+ return __addon__.getSetting("useTestData") == 'true'
+
+#####################################################
+# Main window for the Sonos controller
+#####################################################
+class SonosControllerWindow(xbmcgui.WindowXMLDialog):
+ ALBUM_ART = 801
+ ARTIST_LABEL = 802
+ TITLE_LABEL = 803
+ ALBUM_LABEL = 804
+ NEXT_LABEL = 805
+
+ TRACK_POSITION_LABEL = 810
+ DURATION_LABEL = 812
+ SLIDER_SEEK = 811
+
+ # Button IDs
+ BUTTON_PREVIOUS = 600
+ BUTTON_PLAY = 601
+ BUTTON_PAUSE = 602
+ BUTTON_STOP = 603
+ BUTTON_NEXT = 604
+
+ BUTTON_NOT_MUTED = 620
+ BUTTON_MUTED = 621
+ SLIDER_VOLUME = 622
+
+
+ def __init__( self, *args, **kwargs ):
+ self.closeRequested = False
+ # Copy off the key-word arguments
+ # The non keyword arguments will be the ones passed to the main
WindowXML
+ self.sonosDevice = kwargs.pop('sonosDevice')
+ self.currentTrack = None
+
+ self.delayedRefresh = 0
+
+ # Static method to create the Window Dialog class
@staticmethod
- def useXbmcNotifDialog():
- return __addon__.getSetting("xbmcNotifDialog") == 'true'
+ def createSonosControllerWindow(sonosDevice):
+ return SonosControllerWindow("script-sonos-controller.xml", __cwd__,
sonosDevice=sonosDevice)
+
+ def isClose(self):
+ return self.closeRequested
+
+ # Handle the close action
+ def onAction(self, action):
+ # ACTION_PREVIOUS_MENU 10
+ # ACTION_NAV_BACK 92
+ if (action == 10) or (action == 92):
+ log("SonosControllerWindow: Close Action received: %s" %
str(action))
+ self.close()
+
+ # Handle the close event - make sure we set the flag so we know it's been
closed
+ def close(self):
+ self.closeRequested = True
+ xbmcgui.WindowXMLDialog.close(self)
+
+ def updateDisplay(self):
+ # Get the current track information
+ track = sonosDevice.get_current_track_info()
+
+ # Only update if the track has changed
+ if (track != None) and ((self.currentTrack == None) or (track['uri']
!= self.currentTrack['uri'])):
+ # Get the album art if it is set (Default to the Sonos icon)
+ albumArtImage = __icon__
+ if track['album_art'] != "":
+ albumArtImage = track['album_art']
+
+ # Need to populate the popup with the artist details
+ albumArt = self.getControl(SonosControllerWindow.ALBUM_ART)
+ albumArt.setImage(albumArtImage)
+
+ artistLabel = self.getControl(SonosControllerWindow.ARTIST_LABEL)
+ artistLabel.reset()
+ artistLabel.addLabel(track['artist'])
+
+ titleLabel = self.getControl(SonosControllerWindow.TITLE_LABEL)
+ titleLabel.reset()
+ titleLabel.addLabel(track['title'])
+
+ albumLabel = self.getControl(SonosControllerWindow.ALBUM_LABEL)
+ albumLabel.reset()
+ albumLabel.addLabel(track['album'])
+
+ nextTrackLabel = self.getControl(SonosControllerWindow.NEXT_LABEL)
+ # Clear the current text
+ nextTrackLabel.reset()
+
+ # Display the track duration
+ durationLabel =
self.getControl(SonosControllerWindow.DURATION_LABEL)
+ durationLabel.setLabel(self._stripHoursFromTime(track['duration']))
+ # If the duration is 00:00:00 then this normally means that
something like radio
+ # is steaming so we shouldn't show any timing details
+ if track['duration'] == '0:00:00':
+ durationLabel.setVisible(False)
+ else:
+ durationLabel.setVisible(True)
+ #################################################################
+ # Note: the code below gives the next track in the playlist
+ # not the next track to be played (which is the case if random)
+ # No way to do that at the moment
+ #################################################################
+ # Check if there is a next track
+# if track['playlist_position'] != "" and
int(track['playlist_position']) > -1:
+# # Also get the "Next Track" Information
+# # 0 would be the current track
+# nextTrackList =
sonosDevice.get_queue(int(track['playlist_position']), 1)
+#
+# if (nextTrackList != None) and (len(nextTrackList) > 0):
+# nextTrackItem = nextTrackList[0]
+# nextTrackText = "[COLOR=FF0084ff]%s:[/COLOR] %s - %s" %
("Next", nextTrackItem['title'], nextTrackItem['artist'])
+# nextTrackLabel.addLabel(nextTrackText)
-###########################################################################
-# NOTE
-# ====
-# This section is all temporary - it is just to show what future versions
-# will be able to do
-###########################################################################
+ self.currentTrack = track
-if __name__ == '__main__':
+ # Display the track position
+ trackPositionLabel =
self.getControl(SonosControllerWindow.TRACK_POSITION_LABEL)
+
trackPositionLabel.setLabel(self._stripHoursFromTime(track['position']))
+
+ # Get the initial state of the device
+ playStatus = sonosDevice.get_current_transport_info()
+
+ # Set the play/pause button to the correct value
+ playButton = self.getControl(SonosControllerWindow.BUTTON_PLAY)
+ if (playStatus != None) and (playStatus['current_transport_state'] ==
'PLAYING'):
+ playButton.setVisible(False)
+ else:
+ playButton.setVisible(True)
+
+ # Check to see what the current state of the mute button is
+ muteButton = self.getControl(SonosControllerWindow.BUTTON_NOT_MUTED)
+ if sonosDevice.mute() == 0:
+ muteButton.setVisible(True)
+ else:
+ muteButton.setVisible(False)
+
+ # The following controls need a delayed refresh, this is because they
+ # are controls like sliders, so we do not want to update them until
+ # the slider operation is complete
+ if self.delayedRefresh < 1:
+
+ # Get the current volume and set the slider
+ # Will return a value between 0 and 100
+ currentVolume = sonosDevice.volume()
+ # Get the slider control
+ volumeSlider = self.getControl(SonosControllerWindow.SLIDER_VOLUME)
+ # Don't move slider is already in correct position
+ currentSliderPosition = int(volumeSlider.getPercent())
+ if currentSliderPosition != currentVolume:
+ volumeSlider.setPercent(currentVolume)
+
+ # Set the seek slider
+ self._setSeekSlider(track['position'],track['duration'])
+
+ else:
+ self.delayedRefresh = self.delayedRefresh - 1
+
+
+ # Do the initial setup of the dialog
+ def onInit(self):
+ self.updateDisplay()
+
+ # Handle the operations where the user clicks on a button
+ def onClick(self, controlID):
+
+ # Play button has been clicked
+ if controlID == SonosControllerWindow.BUTTON_PLAY:
+ log("SonosControllerWindow: Play Requested")
+
+ # Send the play message to Sonos
+ sonosDevice.play()
+ self.setFocusId(SonosControllerWindow.BUTTON_PAUSE)
+
+ elif controlID == SonosControllerWindow.BUTTON_PAUSE:
+ log("SonosControllerWindow: Pause Requested")
+
+ # Send the pause message to Sonos
+ sonosDevice.pause()
+ self.setFocusId(SonosControllerWindow.BUTTON_PLAY)
+
+ elif controlID == SonosControllerWindow.BUTTON_NEXT:
+ log("SonosControllerWindow: Next Track Requested")
+ sonosDevice.next()
+
+ elif controlID == SonosControllerWindow.BUTTON_PREVIOUS:
+ log("SonosControllerWindow: Previous Track Requested")
+ sonosDevice.previous()
+
+ elif controlID == SonosControllerWindow.BUTTON_STOP:
+ log("SonosControllerWindow: Stop Requested")
+ sonosDevice.stop()
+
+ elif controlID == SonosControllerWindow.BUTTON_NOT_MUTED:
+ log("SonosControllerWindow: Mute Requested")
+ sonosDevice.mute(True)
+ self.setFocusId(SonosControllerWindow.BUTTON_MUTED)
+
+ elif controlID == SonosControllerWindow.BUTTON_MUTED:
+ log("SonosControllerWindow: Mute Requested")
+ sonosDevice.mute(False)
+ self.setFocusId(SonosControllerWindow.BUTTON_NOT_MUTED)
+
+ elif controlID == SonosControllerWindow.SLIDER_VOLUME:
+ # Get the position of the slider
+ volumeSlider = self.getControl(SonosControllerWindow.SLIDER_VOLUME)
+ currentSliderPosition = int(volumeSlider.getPercent())
+
+ log("SonosControllerWindow: Volume Request to value: %d" %
currentSliderPosition)
+
+ # Before we send the volume change request we want to delay any
refresh
+ # on the gui so we have time to perform the slide operation without
+ # the slider being reset
+ self._setDelayedRefresh()
+
+ # Now set the volume
+ sonosDevice.volume(currentSliderPosition)
+
+ elif controlID == SonosControllerWindow.SLIDER_SEEK:
+ # Get the position of the slider
+ seekSlider = self.getControl(SonosControllerWindow.SLIDER_SEEK)
+ currentSliderPosition = int(seekSlider.getPercent())
+
+ log("SonosControllerWindow: Seek Request to value: %d" %
currentSliderPosition)
+
+ # Before we send the seek change request we want to delay any
refresh
+ # on the gui so we have time to perform the slide operation without
+ # the slider being reset
+ self._setDelayedRefresh()
+
+ # Now set the seek location
+ self._setSeekPosition(currentSliderPosition)
+
+# else:
+# xbmcgui.Dialog().ok(__addon__.getLocalizedString(32001), "Control
clicked is " + str(controlID))
+
+ # Refresh the screen to show the current state
+ self.updateDisplay()
+
+ # Set a delay time so that the screen does not automatically update
+ # and leaves time for a given operation
+ def _setDelayedRefresh(self):
+ # Convert the refresh interval into seconds
+ refreshInterval = Settings.getRefreshInterval() / 1000
+ if refreshInterval == 0:
+ # Make sure we do not divide by zero
+ refreshInterval = 1
+ self.delayedRefresh = int( 4 / float(refreshInterval) )
+ if self.delayedRefresh == 0:
+ self.delayedRefresh = 1
+
+ # Takes a time string (00:00:00) and removes the hour section if it is 0
+ def _stripHoursFromTime(self, fullTimeString):
+ if (fullTimeString == None) or (fullTimeString == ""):
+ return "00:00"
+ if fullTimeString.count(':') == 2:
+ # Check if the hours section should be stripped
+ hours = 0
+ try:
+ hours = int(fullTimeString.split(':',1)[0])
+ except:
+ # Hours section is not numbers
+ log("SonosControllerWindow: Exception Details: %s" %
traceback.format_exc())
+ hours = 0
+
+ # Only strip the hours if there are no hours
+ if hours < 1:
+ return fullTimeString.split(':',1)[-1]
+ return fullTimeString
+
+ # Set the seek slider to the current position of the track
+ def _setSeekSlider(self, currentPosition, trackDuration):
+ currentPositionSeconds = self._getSecondsInTimeString(currentPosition)
+ trackDurationSeconds = self._getSecondsInTimeString(trackDuration)
+
+ # work out the percentage we are through the track
+ currentPercentage = 0
+ if trackDurationSeconds > 0:
+ currentPercentage = int((float(currentPositionSeconds) /
float(trackDurationSeconds)) * 100)
+
+ log("SonosControllerWindow: Setting seek slider to %d" %
currentPercentage)
+
+ # Get the slider control
+ seekSlider = self.getControl(SonosControllerWindow.SLIDER_SEEK)
+ seekSlider.setPercent(currentPercentage)
+
+ # Converts a time string 0:00:00 to the total number of seconds
+ def _getSecondsInTimeString(self, fullTimeString):
+ # Start by splitting the time into sections
+ hours = 0
+ minutes = 0
+ seconds = 0
+
+ try:
+ hours = int(fullTimeString.split(':',1)[0])
+ minutes = int(fullTimeString.split(':')[1])
+ seconds = int(fullTimeString.split(':')[2])
+ except:
+ # time sections are not numbers
+ log("SonosControllerWindow: Exception Details: %s" %
traceback.format_exc())
+ hours = 0
+ minutes = 0
+ seconds = 0
+
+ totalInSeconds = (((hours * 60) + minutes) * 60) + seconds
+ log("SonosControllerWindow: Time %s, splits into hours=%d, minutes=%d,
seconds=%d, total=%d" % (fullTimeString, hours, minutes, seconds,
totalInSeconds))
+
+ # Return the total time in seconds
+ return totalInSeconds
+
+ # Sets the current seek time, sending it to the sonos speaker
+ def _setSeekPosition(self, percentage):
+ trackDurationSeconds =
self._getSecondsInTimeString(self.currentTrack['duration'])
+
+ if trackDurationSeconds > 0:
+ # Get the current number of seconds into the track
+ newPositionSeconds = int((float(percentage) *
float(trackDurationSeconds))/100)
+
+ # Convert the seconds into a timestamp
+ newPosition = "0:00:00"
+
+ # Convert the duration into a viewable format
+ if newPositionSeconds > 0:
+ seconds = newPositionSeconds % 60
+ minutes = 0
+ hours = 0
+
+ if newPositionSeconds > 60:
+ minutes = ((newPositionSeconds - seconds) % 3600)/60
+
+ if newPositionSeconds > 3600:
+ hours = (newPositionSeconds - (minutes*60) - seconds)/3600
+
+ # Build the string up
+ newPosition = "%d:%02d:%02d" % (hours, minutes, seconds)
+
+ # Now send the seek message to the sonos speaker
+ sonosDevice.seek(newPosition)
+
+
+
+if __name__ == '__main__':
ipAddress = Settings.getIPAddress()
@@ -75,52 +406,31 @@ if __name__ == '__main__':
if ipAddress != "0.0.0.0":
sonosDevice = SoCo(ipAddress)
- # Display a simple selection dialog for now
- menuItems = ['Play', 'Pause', 'Stop', 'Next Track', 'Previous', 'LED
On', 'LED Off', 'Exit']
+ if Settings.useTestData():
+ sonosDevice = TestMockSonos()
- select = xbmcgui.Dialog().select(__addon__.getLocalizedString(32001),
menuItems)
- try:
- # Play was requested
- if select == 0:
- log("Sonos: Play Requested")
- sonosDevice.play()
-
- # Pause was requested
- elif select == 1:
- log("Sonos: Pause Requested")
- sonosDevice.pause()
-
- # Stop was requested
- elif select == 2:
- log("Sonos: Stop Requested")
- sonosDevice.stop()
-
- # Next was requested
- elif select == 3:
- log("Sonos: Next Track Requested")
- sonosDevice.next()
-
- # Previous was requested
- elif select == 4:
- log("Sonos: Previous Track Requested")
- sonosDevice.previous()
-
- # Turn Status Light On
- elif select == 5:
- log("Sonos: LED On Requested")
- sonosDevice.status_light(True)
-
- # Turn Status Light Off
- elif select == 6:
- log("Sonos: LED Off Requested")
- sonosDevice.status_light(False)
+ sonosCtrl =
SonosControllerWindow.createSonosControllerWindow(sonosDevice)
+ sonosCtrl.show()
+
+ # Record the fact that the Sonos controller window is displayed
+ xbmcgui.Window(10000).setProperty( "SonosControllerShowing", "true" )
+ try:
+ while (not sonosCtrl.isClose()) and (not xbmc.abortRequested):
+ sonosCtrl.updateDisplay()
+ # Wait a second or so before updating
+ xbmc.sleep(Settings.getRefreshInterval())
except:
# Failed to connect to the Sonos Speaker
xbmcgui.Dialog().ok(__addon__.getLocalizedString(32001), ("Error
from speaker %s" % ipAddress))
log("Sonos: Exception Details: %s" % traceback.format_exc())
+ sonosCtrl.close()
+ # Record the fact that the Sonos controller is no longer displayed
+ xbmcgui.Window(10000).clearProperty("SonosControllerShowing")
+ del sonosCtrl
+
else:
xbmcgui.Dialog().ok(__addon__.getLocalizedString(32001), "IP Address
Not Set")
diff --git a/script.sonos/resources/language/English/strings.po
b/script.sonos/resources/language/English/strings.po
index 0d90dec..f07d771 100644
--- a/script.sonos/resources/language/English/strings.po
+++ b/script.sonos/resources/language/English/strings.po
@@ -79,3 +79,16 @@ msgstr ""
msgctxt "#32014"
msgid "No speakers found, please enter your IP address manually"
msgstr ""
+
+msgctxt "#32015"
+msgid "Controller"
+msgstr ""
+
+msgctxt "#32016"
+msgid "Refresh Interval (Seconds)"
+msgstr ""
+
+msgctxt "#32017"
+msgid "Use Test Data"
+msgstr ""
+
diff --git a/script.sonos/resources/settings.xml
b/script.sonos/resources/settings.xml
index c24f68e..7b471fa 100644
--- a/script.sonos/resources/settings.xml
+++ b/script.sonos/resources/settings.xml
@@ -3,6 +3,9 @@
<setting label="32013" type="action"
action="RunScript($CWD/discovery.py)"/>
<setting id="ipAddress" type="ipaddress" label="32002"
default="0.0.0.0"/>
</category>
+ <category label="32015">
+ <setting id="refreshInterval" label="32016" type="slider"
default="2" range="0.5,0.5,5" option="float"/>
+ </category>
<category label="32011">
<setting id="notifEnabled" type="bool" label="32003"
default="true"/>
<setting id="notifDisplayDuration" enable="eq(-1,true)"
label="32004" type="slider" default="3" range="0,1,60" option="int"/>
@@ -12,5 +15,6 @@
</category>
<category label="32012">
<setting id="logEnabled" type="bool" label="32009"
default="false"/>
+ <setting id="useTestData" type="bool" label="32017"
default="false"/>
</category>
</settings>
diff --git
a/script.sonos/resources/skins/Default/720p/script-sonos-notif-popup.xml
b/script.sonos/resources/skins/Default/720p/script-sonos-notif-popup.xml
index ea7e382..2d68569 100644
--- a/script.sonos/resources/skins/Default/720p/script-sonos-notif-popup.xml
+++ b/script.sonos/resources/skins/Default/720p/script-sonos-notif-popup.xml
@@ -14,8 +14,15 @@
<posy>0</posy>
<width>420</width>
<height>90</height>
- <colordiffuse>EEFFFFFF</colordiffuse>
- <texture
border="12">OverlayDialogBackground.png</texture>
+ <colordiffuse>CCFFFFFF</colordiffuse>
+ <texture
border="12">[email protected]</texture>
+ </control>
+ <control type="image">
+ <posx>5</posx>
+ <posy>5</posy>
+ <width>410</width>
+ <height>80</height>
+ <texture
border="20">msNowPlayingBg_ipad.png</texture>
</control>
<control type="image" id="400">
<description>avatar</description>
diff --git a/script.sonos/service.py b/script.sonos/service.py
index bb615f7..3c91ae5 100644
--- a/script.sonos/service.py
+++ b/script.sonos/service.py
@@ -21,6 +21,8 @@ from soco import SoCo
from soco import SonosDiscovery
from soco import SoCoException
+# Import the Mock Sonos class for testing where there is no live Sonos system
+from mocksonos import TestMockSonos
def log(txt):
if __addon__.getSetting( "logEnabled" ) == "true":
@@ -60,6 +62,10 @@ class Settings():
def useXbmcNotifDialog():
return __addon__.getSetting("xbmcNotifDialog") == 'true'
+ @staticmethod
+ def useTestData():
+ return __addon__.getSetting("useTestData") == 'true'
+
##########################################################
# Class to display a popup of what is currently playing
@@ -113,6 +119,7 @@ class SonosPlayingPopup(xbmcgui.WindowXMLDialog):
self.close()
+
################################
# Main of the Sonos Service
################################
@@ -128,11 +135,20 @@ if __name__ == '__main__':
lastDisplayedTrack = None
+ # Need to only display the popup when the service starts if there is
+ # currently something playing
+ justStartedService = True
+
# Loop until XBMC exits
while (not xbmc.abortRequested):
if timeUntilNextCheck < 1:
if Settings.stopNotifIfVideoPlaying() and
xbmc.Player().isPlayingVideo():
log("SonosService: Video Playing, Skipping Notification
Display")
+ elif
xbmcgui.Window(10000).getProperty("SonosControllerShowing") == 'true':
+ log("SonosService: Sonos Controller Showing, Skipping
Notification Display")
+ # Reset the "just started" flag to ensure that when we
exit it does not
+ # show the notification immediately
+ justStartedService = True
else:
log("SonosService: Notification wait time expired")
ipAddress = Settings.getIPAddress()
@@ -142,6 +158,9 @@ if __name__ == '__main__':
# Make sure the IP Address has been set
if ipAddress != "0.0.0.0":
sonosDevice = SoCo(ipAddress)
+
+ if Settings.useTestData():
+ sonosDevice = TestMockSonos()
# Should now have a single speaker set to "device"
if sonosDevice != None:
@@ -149,34 +168,47 @@ if __name__ == '__main__':
# Get the current track that is being played
at the moment
track = sonosDevice.get_current_track_info()
+ # Record if the sonos is currently playing
+ isActive = True
+
# Check to see if a new track is playing
before displaying the popup
- if (track['uri'] == '') and (track['title'] ==
''):
+ if (track['uri'] == '') or (track['title'] ==
''):
track = None
# Also make the last track value None as
we don't want
# this seen as a change
lastDisplayedTrack = None
+ elif justStartedService == True:
+ # Check if the sonos is currently playing
+ playStatus =
sonosDevice.get_current_transport_info()
+ if (playStatus == None) or
(playStatus['current_transport_state'] != 'PLAYING'):
+ isActive = False
# Check to see if the playing track has changed
if (track != None) and ((lastDisplayedTrack ==
None) or (track['uri'] != lastDisplayedTrack['uri'])):
# Update the last displayed track to the
current one
lastDisplayedTrack = track
- if Settings.useXbmcNotifDialog():
- log("SonosService: Currently playing
artist = %s, album = %s, track = %s" % (track['artist'], track['album'],
track['title']))
-
- # Get the album art if it is set
(Default to the Sonos icon)
- albumArt = __icon__
- if track['album_art'] != "":
- albumArt = track['album_art']
-
- xbmc.executebuiltin('Notification(%s,
%s, %d, %s)' % (track['artist'], track['title'],
Settings.getNotificationDisplayDuration(), albumArt))
- else:
- sonosPopup =
SonosPlayingPopup.createSonosPlayingPopup(track)
- sonosPopup.showPopup()
- del sonosPopup
+ # Only display the dialog if it is playing
+ if isActive:
+ if Settings.useXbmcNotifDialog():
+ log("SonosService: Currently
playing artist = %s, album = %s, track = %s" % (track['artist'],
track['album'], track['title']))
+
+ # Get the album art if it is set
(Default to the Sonos icon)
+ albumArt = __icon__
+ if track['album_art'] != "":
+ albumArt = track['album_art']
+
+
xbmc.executebuiltin('Notification(%s, %s, %d, %s)' % (track['artist'],
track['title'], Settings.getNotificationDisplayDuration(), albumArt))
+ else:
+ sonosPopup =
SonosPlayingPopup.createSonosPlayingPopup(track)
+ sonosPopup.showPopup()
+ del sonosPopup
except:
# Connection failure - may just be a network
glitch - so don't exit
log("SonosService: Error from speaker %s" %
ipAddress)
log("SonosService: %s" %
traceback.format_exc())
+
+ # No longer the first start
+ justStartedService = False
# Reset the timer for the next check
timeUntilNextCheck = Settings.getNotificationCheckFrequency()
@@ -186,11 +218,3 @@ if __name__ == '__main__':
timeUntilNextCheck = timeUntilNextCheck - 1
log("Sonos: Stopping service")
-
- # Test code to test the dialog without a Sonos Speaker connected
-# track = {'title': 'Title value', 'artist': 'Artist Value', 'album':
'AlbumValue', 'album_art': '',
-# 'position': ''}
-#
-# sonosPopup = SonosPlayingPopup.createSonosPlayingPopup(track)
-# sonosPopup.showPopup()
-# del sonosPopup
-----------------------------------------------------------------------
Summary of changes:
script.sonos/addon.xml | 2 +-
script.sonos/changelog.txt | 7 +
script.sonos/default.py | 414 +++++++++++++++++---
script.sonos/resources/language/English/strings.po | 13 +
script.sonos/resources/lib/mocksonos.py | 95 +++++
script.sonos/resources/settings.xml | 4 +
.../skins/Default/720p/script-sonos-controller.xml | 297 ++++++++++++++
.../Default/720p/script-sonos-notif-popup.xml | 11 +-
.../Default/media/DialogCloseButton-focus.png | Bin 5216 -> 5216 bytes
.../skins/Default/media/DialogCloseButton.png | Bin 4522 -> 4522 bytes
.../Default/media/control_buttons/snAutoBtn.png | Bin 0 -> 630 bytes
.../skins/Default/media/control_buttons/tbMute.png | Bin 0 -> 1751 bytes
.../Default/media/control_buttons/tbMute_on.png | Bin 0 -> 1812 bytes
.../Default/media/control_buttons/tbMute_sel.png | Bin 0 -> 3904 bytes
.../Default/media/control_buttons/tbPause.png | Bin 0 -> 1881 bytes
.../Default/media/control_buttons/tbPause_sel.png | Bin 0 -> 4518 bytes
.../skins/Default/media/control_buttons/tbPlay.png | Bin 0 -> 2042 bytes
.../Default/media/control_buttons/tbPlay_sel.png | Bin 0 -> 4651 bytes
.../skins/Default/media/control_buttons/tbStop.png | Bin 0 -> 1848 bytes
.../Default/media/control_buttons/tbStop_sel.png | Bin 0 -> 4465 bytes
.../media/control_buttons/tbTransportBack.png | Bin 0 -> 1597 bytes
.../media/control_buttons/tbTransportBack_sel.png | Bin 0 -> 3711 bytes
.../media/control_buttons/tbTransportForward.png | Bin 0 -> 1598 bytes
.../control_buttons/tbTransportForward_sel.png | Bin 0 -> 3709 bytes
.../Default/media/control_buttons/tbUnMute_sel.png | Bin 0 -> 3866 bytes
.../media/control_buttons/tbVolumeScrubber.png | Bin 0 -> 1807 bytes
.../media/control_buttons/tbVolumeScrubber_dis.png | Bin 0 -> 1368 bytes
.../skins/Default/media/[email protected] | Bin 0 -> 997 bytes
.../skins/Default/media/msNowPlayingBg_ipad.png | Bin 0 -> 19126 bytes
.../skins/Default/media/[email protected] | Bin 0 -> 1974 bytes
.../skins/Default/media/pmProgressTrackBar.png | Bin 0 -> 310 bytes
.../media/pmProgressTrackBarFillStretch.png | Bin 0 -> 168 bytes
script.sonos/service.py | 68 +++-
33 files changed, 834 insertions(+), 77 deletions(-)
create mode 100644 script.sonos/resources/lib/mocksonos.py
create mode 100644
script.sonos/resources/skins/Default/720p/script-sonos-controller.xml
copy {script.linphone =>
script.sonos}/resources/skins/Default/media/DialogCloseButton-focus.png (100%)
copy {script.linphone =>
script.sonos}/resources/skins/Default/media/DialogCloseButton.png (100%)
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/snAutoBtn.png
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/tbMute.png
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/tbMute_on.png
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/tbMute_sel.png
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/tbPause.png
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/tbPause_sel.png
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/tbPlay.png
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/tbPlay_sel.png
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/tbStop.png
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/tbStop_sel.png
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/tbTransportBack.png
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/tbTransportBack_sel.png
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/tbTransportForward.png
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/tbTransportForward_sel.png
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/tbUnMute_sel.png
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/tbVolumeScrubber.png
create mode 100644
script.sonos/resources/skins/Default/media/control_buttons/tbVolumeScrubber_dis.png
create mode 100644
script.sonos/resources/skins/Default/media/[email protected]
create mode 100644
script.sonos/resources/skins/Default/media/msNowPlayingBg_ipad.png
create mode 100644
script.sonos/resources/skins/Default/media/[email protected]
create mode 100644
script.sonos/resources/skins/Default/media/pmProgressTrackBar.png
create mode 100644
script.sonos/resources/skins/Default/media/pmProgressTrackBarFillStretch.png
hooks/post-receive
--
Scripts
------------------------------------------------------------------------------
WatchGuard Dimension instantly turns raw network data into actionable
security intelligence. It gives you real-time visual feedback on key
security issues and trends. Skip the complicated setup - simply import
a virtual appliance and go from zero to informed in seconds.
http://pubads.g.doubleclick.net/gampad/clk?id=123612991&iu=/4140/ostg.clktrk
_______________________________________________
Xbmc-addons mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/xbmc-addons