The branch, frodo has been updated
via e8b1d9c754b631506698542cb432810622dafcd5 (commit)
from 836c5ed61e003ce4dc786015f7d1d6a0d21617d8 (commit)
- Log -----------------------------------------------------------------
http://xbmc.git.sourceforge.net/git/gitweb.cgi?p=xbmc/scripts;a=commit;h=e8b1d9c754b631506698542cb432810622dafcd5
commit e8b1d9c754b631506698542cb432810622dafcd5
Author: Martijn Kaijser <[email protected]>
Date: Thu Sep 18 19:49:24 2014 +0200
[script.sonos] 1.2.0
diff --git a/script.sonos/addon.xml b/script.sonos/addon.xml
index f62e072..e351236 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.1.1"
provider-name="robwebset">
+<addon id="script.sonos" name="Sonos" version="1.2.0"
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 0340b13..901ef7e 100644
--- a/script.sonos/changelog.txt
+++ b/script.sonos/changelog.txt
@@ -1,3 +1,6 @@
+v1.2.0
+- Initial version of speech support
+
v1.1.1
- Give the search for Sonos systems more time to run
- Set default for Artist Slideshow selection
diff --git a/script.sonos/plugin.py b/script.sonos/plugin.py
index 225986b..da89c85 100644
--- a/script.sonos/plugin.py
+++ b/script.sonos/plugin.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import sys
import os
+import cgi
import traceback
import urllib
import urlparse
@@ -25,6 +26,7 @@ from settings import Settings
from settings import log
import soco
+from speech import Speech
###################################################################
@@ -65,6 +67,11 @@ class MenuNavigator():
ROOT_MENU_RADIO_SHOWS = 'Radio-Shows'
ROOT_MENU_RADIO_SHOWS = 'Radio-Shows'
ROOT_MENU_SONOS_PLAYLISTS = 'Sonos-Playlists'
+ ROOT_MENU_SPEECH = 'Speech'
+
+ COMMAND_CONTROLLER = 'launchController'
+ COMMAND_SPEECH_INPUT = 'SpeechInput'
+ COMMAND_SPEECH_SAVE = 'SpeechSave'
def __init__(self, base_url, addon_handle):
self.base_url = base_url
@@ -77,7 +84,7 @@ class MenuNavigator():
# Display the default list of items in the root menu
def setRootMenu(self):
# Sonos Controller Link
- url = self._build_url({'mode': 'launchController'})
+ url = self._build_url({'mode': MenuNavigator.COMMAND_CONTROLLER})
li = xbmcgui.ListItem(__addon__.getLocalizedString(32103),
iconImage=__icon__)
li.addContextMenuItems([], replaceItems=True) # Clear the Context Menu
self._addPlayerToContextMenu(li) # Add the Sonos player to the menu
@@ -122,6 +129,13 @@ class MenuNavigator():
self._addPlayerToContextMenu(li) # Add the Sonos player to the menu
xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url,
listitem=li, isFolder=True)
+ # Custom Speech Options
+ url = self._build_url({'mode': 'folder', 'foldername':
MenuNavigator.ROOT_MENU_SPEECH})
+ li = xbmcgui.ListItem(__addon__.getLocalizedString(32105),
iconImage=__icon__)
+ li.addContextMenuItems([], replaceItems=True) # Clear the Context Menu
+ self._addPlayerToContextMenu(li) # Add the Sonos player to the menu
+ xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url,
listitem=li, isFolder=True)
+
xbmcplugin.endOfDirectory(self.addon_handle)
# Populate the Music menu
@@ -179,7 +193,7 @@ class MenuNavigator():
# Get the items from the sonos system
list = None
try:
- list = sonosDevice.get_queue(start=totalCollected,
max_items=Settings.getBatchSize())
+ list = sonosDevice.get_queue(totalCollected,
Settings.getBatchSize(), True)
except:
log("SonosPlugin: %s" % traceback.format_exc())
xbmcgui.Dialog().ok("Error", "Failed to perform queue
lookup")
@@ -242,7 +256,13 @@ class MenuNavigator():
# Get the items from the sonos system
list = None
try:
- list =
sonosDevice.get_music_library_information(search_type=folderName,
start=totalCollected, max_items=Settings.getBatchSize(),
sub_category=subCategory)
+ if (subCategory is None) or (subCategory == ''):
+ list =
sonosDevice.get_music_library_information(folderName, totalCollected,
Settings.getBatchSize(), True)
+ else:
+ # Make sure the sub category is valid for the message,
escape invalid characters
+ subCategory = cgi.escape(subCategory)
+ # Call the browse version
+ list = sonosDevice.browse_by_idstring(folderName,
subCategory, totalCollected, Settings.getBatchSize(), True)
except:
log("SonosPlugin: %s" % traceback.format_exc())
xbmcgui.Dialog().ok("Error", "Failed to perform lookup %s
(%s)" % (folderName, subCategory))
@@ -387,6 +407,42 @@ class MenuNavigator():
xbmcplugin.endOfDirectory(self.addon_handle)
+ # Populate the Music menu
+ def populateSpeech(self):
+ url = self._build_url({'mode': MenuNavigator.COMMAND_SPEECH_INPUT})
+ li = xbmcgui.ListItem(__addon__.getLocalizedString(32200),
iconImage=__icon__)
+ li.addContextMenuItems([], replaceItems=True) # Clear the Context Menu
+ self._addPlayerToContextMenu(li) # Add the Sonos player to the menu
+ xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url,
listitem=li, isFolder=False)
+
+ url = self._build_url({'mode': MenuNavigator.COMMAND_SPEECH_SAVE})
+ li = xbmcgui.ListItem(__addon__.getLocalizedString(32203),
iconImage=__icon__)
+ li.addContextMenuItems([], replaceItems=True) # Clear the Context Menu
+ self._addPlayerToContextMenu(li) # Add the Sonos player to the menu
+ xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url,
listitem=li, isFolder=False)
+
+ # Add a blank line before the filters
+ li = xbmcgui.ListItem("", iconImage=__icon__)
+ li.addContextMenuItems([], replaceItems=True)
+ xbmcplugin.addDirectoryItem(handle=self.addon_handle, url="",
listitem=li, isFolder=False)
+
+ # Create the speech class (Not going to call the Sonos System do no
need for the device)
+ speech = Speech()
+ phrases = speech.loadSavedPhrases()
+
+ # Loop through all the phrases and add them to the screen
+ for phrase in phrases:
+ url = self._build_url({'mode': 'action', 'action':
ActionManager.ACTION_SPEECH_SAY_PHRASE, 'itemId': phrase})
+ li = xbmcgui.ListItem(phrase, iconImage=__icon__)
+ # Add the remove button to the context menu
+ cmd = self._build_url({'mode': 'action', 'action':
ActionManager.ACTION_SPEECH_REMOVE_PHRASE, 'itemId': phrase})
+ ctxtMenu = []
+ ctxtMenu.append((__addon__.getLocalizedString(32204),
'XBMC.RunPlugin(%s)' % cmd))
+ li.addContextMenuItems(ctxtMenu, replaceItems=True) # Clear the
Context Menu
+ xbmcplugin.addDirectoryItem(handle=self.addon_handle, url=url,
listitem=li, isFolder=False)
+
+ xbmcplugin.endOfDirectory(self.addon_handle)
+
# Checks if the limit for the size of the list has been reached
def _listLimitReached(self, currentEntries):
queueLimit = Settings.getMaxListEntries()
@@ -557,6 +613,9 @@ class ActionManager():
ACTION_RADIO_PLAY = 'playRadio'
+ ACTION_SPEECH_SAY_PHRASE = 'speechSayPhrase'
+ ACTION_SPEECH_REMOVE_PHRASE = 'speechRemovePhrase'
+
def __init__(self):
self.sonosDevice = Settings.getSonosDevice()
@@ -578,8 +637,13 @@ class ActionManager():
# Radio Operations
elif actionType == ActionManager.ACTION_RADIO_PLAY:
self.performPlayURI(itemId, title)
+ # Speech Operations
+ elif actionType == ActionManager.ACTION_SPEECH_SAY_PHRASE:
+ self.sayPhrase(itemId)
+ elif actionType == ActionManager.ACTION_SPEECH_REMOVE_PHRASE:
+ self.removePhrase(itemId)
else:
- # Temp error message - should never be shown - will remove
when all features complete
+ # This should never be shown, so no need to translate, enabled
for debug
xbmcgui.Dialog().ok("Error", "Operation %s not currently
supported" % actionType)
except:
log("SonosPlugin: %s" % traceback.format_exc())
@@ -598,7 +662,7 @@ class ActionManager():
def performPlayURI(self, itemId, title):
# Make sure a Sonos speaker was found
if self.sonosDevice is not None:
- self.sonosDevice.play_uri(itemId, title)
+ self.sonosDevice.play_uri(cgi.escape(itemId),
title=cgi.escape(title))
def performAddToQueue(self, itemId):
positionInQueue = None
@@ -634,6 +698,20 @@ class ActionManager():
# Refresh the screen now that we have removed all the items
xbmc.executebuiltin('Container.Refresh')
+ # SPEECH OPERATIONS
+ def sayPhrase(self, phrase):
+ # Make sure a Sonos speaker was found
+ if self.sonosDevice is not None:
+ # Create the speech class and play the message
+ speech = Speech(self.sonosDevice)
+ # Now get the Sonos Sytem to say the message
+ speech.say(phrase)
+
+ def removePhrase(self, phrase):
+ speech = Speech(self.sonosDevice)
+ speech.removePhrase(phrase)
+ # Refresh the screen now that an item has been removed
+ xbmc.executebuiltin('Container.Refresh')
################################
# Main of the Sonos Plugin
@@ -678,6 +756,9 @@ if __name__ == '__main__':
elif foldername[0] == MenuNavigator.ROOT_MENU_RADIO_SHOWS:
menuNav = MenuNavigator(base_url, addon_handle)
menuNav.populateRadioShows()
+ elif foldername[0] == MenuNavigator.ROOT_MENU_SPEECH:
+ menuNav = MenuNavigator(base_url, addon_handle)
+ menuNav.populateSpeech()
else:
subCategory = args.get('subCategory', '')
if subCategory != '':
@@ -705,7 +786,28 @@ if __name__ == '__main__':
actionMgr = ActionManager()
actionMgr.performAction(actionType[0], itemId[0], title)
- elif mode[0] == 'launchController':
+ elif mode[0] == MenuNavigator.COMMAND_CONTROLLER:
log("SonosPlugin: Mode is launchController")
xbmc.executebuiltin("xbmc.ActivateWindow(home)", True)
xbmc.executebuiltin('XBMC.RunScript(script.sonos)')
+
+ elif mode[0] == MenuNavigator.COMMAND_SPEECH_INPUT:
+ log("SonosPlugin: Mode is Speech Input")
+ sonosDevice = Settings.getSonosDevice()
+ # Make sure a Sonos speaker was found
+ if sonosDevice is not None:
+ # Create the speech class and prompt the user for the message
+ speech = Speech(sonosDevice)
+ msg = speech.promptForInput()
+ if msg is not None:
+ # Now get the Sonos Sytem to say the message
+ speech.say(msg)
+
+ elif mode[0] == MenuNavigator.COMMAND_SPEECH_SAVE:
+ log("SonosPlugin: Mode is Speech Save")
+ # Create the speech class and prompt the user for the message
+ # (No need for a device to save a message)
+ speech = Speech()
+ speech.addPhrase()
+ # Refresh the screen now that an item has been removed
+ xbmc.executebuiltin('Container.Refresh')
diff --git a/script.sonos/resources/language/Belarusian/strings.po
b/script.sonos/resources/language/Belarusian/strings.po
index cf76c90..aa8ca8f 100644
--- a/script.sonos/resources/language/Belarusian/strings.po
+++ b/script.sonos/resources/language/Belarusian/strings.po
@@ -36,6 +36,10 @@ msgctxt "#32015"
msgid "Controller"
msgstr "Controller"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Layout"
+
msgctxt "#32062"
msgid "Next"
msgstr "Next"
diff --git a/script.sonos/resources/language/Burmese/strings.po
b/script.sonos/resources/language/Burmese/strings.po
index f960172..3f58d79 100644
--- a/script.sonos/resources/language/Burmese/strings.po
+++ b/script.sonos/resources/language/Burmese/strings.po
@@ -16,6 +16,14 @@ msgstr ""
"Language: my\n"
"Plural-Forms: nplurals=1; plural=0;\n"
+msgctxt "#32110"
+msgid "Artists"
+msgstr "á¡ááá¯áá±á¬áºáá»á¬á¸"
+
msgctxt "#32111"
msgid "Albums"
msgstr "á¡ááºááẠáá»á¬á¸"
+
+msgctxt "#32114"
+msgid "Tracks"
+msgstr "á¡áá¯ááºáá»á¬á¸"
diff --git a/script.sonos/resources/language/Catalan/strings.po
b/script.sonos/resources/language/Catalan/strings.po
index 2f85468..92f8ea3 100644
--- a/script.sonos/resources/language/Catalan/strings.po
+++ b/script.sonos/resources/language/Catalan/strings.po
@@ -40,6 +40,10 @@ msgctxt "#32015"
msgid "Controller"
msgstr "Controlador"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Disseny"
+
msgctxt "#32062"
msgid "Next"
msgstr "Següent"
diff --git a/script.sonos/resources/language/Chinese (Simple)/strings.po
b/script.sonos/resources/language/Chinese (Simple)/strings.po
index 122ac41..1b64dfe 100644
--- a/script.sonos/resources/language/Chinese (Simple)/strings.po
+++ b/script.sonos/resources/language/Chinese (Simple)/strings.po
@@ -44,6 +44,10 @@ msgctxt "#32015"
msgid "Controller"
msgstr "æ§å¶å¨"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "å¸å±"
+
msgctxt "#32062"
msgid "Next"
msgstr "ä¸ä¸é¡¹"
diff --git a/script.sonos/resources/language/Chinese (Traditional)/strings.po
b/script.sonos/resources/language/Chinese (Traditional)/strings.po
index 15444eb..026beab 100644
--- a/script.sonos/resources/language/Chinese (Traditional)/strings.po
+++ b/script.sonos/resources/language/Chinese (Traditional)/strings.po
@@ -32,6 +32,10 @@ msgctxt "#32012"
msgid "Debugging"
msgstr "é¤é¯"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "çé¢"
+
msgctxt "#32062"
msgid "Next"
msgstr "åå¾"
diff --git a/script.sonos/resources/language/Czech/strings.po
b/script.sonos/resources/language/Czech/strings.po
index 3bda91f..37e8e3b 100644
--- a/script.sonos/resources/language/Czech/strings.po
+++ b/script.sonos/resources/language/Czech/strings.po
@@ -36,6 +36,10 @@ msgctxt "#32012"
msgid "Debugging"
msgstr "LadÄnÃ"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "RozvrženÃ"
+
msgctxt "#32062"
msgid "Next"
msgstr "DalÅ¡Ã"
diff --git a/script.sonos/resources/language/Danish/strings.po
b/script.sonos/resources/language/Danish/strings.po
index df574c4..c8ba811 100644
--- a/script.sonos/resources/language/Danish/strings.po
+++ b/script.sonos/resources/language/Danish/strings.po
@@ -36,6 +36,10 @@ msgctxt "#32012"
msgid "Debugging"
msgstr "Foretag fejlretning"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Layout"
+
msgctxt "#32062"
msgid "Next"
msgstr "Næste"
diff --git a/script.sonos/resources/language/Dutch/strings.po
b/script.sonos/resources/language/Dutch/strings.po
index 6282e77..4bbaf3f 100644
--- a/script.sonos/resources/language/Dutch/strings.po
+++ b/script.sonos/resources/language/Dutch/strings.po
@@ -136,6 +136,50 @@ msgctxt "#32029"
msgid "Automatically Update IP Address On Startup"
msgstr "Automatisch IP-adres updaten bij opstarten"
+msgctxt "#32030"
+msgid "Switch Sonos To Line-In On Media Start"
+msgstr "Verwissel Sonos naar Line-In bij starten media"
+
+msgctxt "#32031"
+msgid "Coordinator"
+msgstr "Coördinator"
+
+msgctxt "#32032"
+msgid "is not the group coordinator for zone"
+msgstr "Is niet de groepscoördinator voor deze zone"
+
+msgctxt "#32033"
+msgid "Some functions may not work correctly if the speaker is not a
coordinator"
+msgstr "Sommige functies kunnen mogelijk niet juist werken als de speaker geen
coördinator is"
+
+msgctxt "#32034"
+msgid "Automation"
+msgstr "Automatiseren"
+
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Lay-out"
+
+msgctxt "#32036"
+msgid "Controller,Slideshow,Bio,Albums"
+msgstr "Controler,Diavoorstelling,Biografie,Albums"
+
+msgctxt "#32037"
+msgid "Controller,Slideshow"
+msgstr "Beheerder,Diavoorstelling"
+
+msgctxt "#32038"
+msgid "Use Skin Icons Instead Of Sonos Icons"
+msgstr "Gebruik skin iconen in plaats van Sonos iconen"
+
+msgctxt "#32039"
+msgid "Slideshow Only"
+msgstr "Alleen diavoorstelling"
+
+msgctxt "#32040"
+msgid "Do Not Display Notification If Controller Is Showing"
+msgstr "Toon geen notificatie als de beheerder speelt"
+
msgctxt "#32060"
msgid "The following setting in ArtistSlideshow must be enabled"
msgstr "De volgende instelling in Artiestendiashow moet zijn geactiveerd"
@@ -164,6 +208,10 @@ msgctxt "#32103"
msgid "Launch Sonos Controller"
msgstr "Start Sonos Controller"
+msgctxt "#32104"
+msgid "Sonos Playlists"
+msgstr "Sonos afspeellijsten"
+
msgctxt "#32110"
msgid "Artists"
msgstr "Artiesten"
diff --git a/script.sonos/resources/language/English (Australia)/strings.po
b/script.sonos/resources/language/English (Australia)/strings.po
index 17da86b..279ae5b 100644
--- a/script.sonos/resources/language/English (Australia)/strings.po
+++ b/script.sonos/resources/language/English (Australia)/strings.po
@@ -20,6 +20,10 @@ msgctxt "#32002"
msgid "IP Address"
msgstr "IP Address"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Layout"
+
msgctxt "#32062"
msgid "Next"
msgstr "Next"
diff --git a/script.sonos/resources/language/English (New Zealand)/strings.po
b/script.sonos/resources/language/English (New Zealand)/strings.po
index 058cb16..0957908 100644
--- a/script.sonos/resources/language/English (New Zealand)/strings.po
+++ b/script.sonos/resources/language/English (New Zealand)/strings.po
@@ -92,6 +92,10 @@ msgctxt "#32019"
msgid "Batch Size"
msgstr "Batch Size"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Layout"
+
msgctxt "#32062"
msgid "Next"
msgstr "Next"
diff --git a/script.sonos/resources/language/English (US)/strings.po
b/script.sonos/resources/language/English (US)/strings.po
index 23466eb..c45a2dd 100644
--- a/script.sonos/resources/language/English (US)/strings.po
+++ b/script.sonos/resources/language/English (US)/strings.po
@@ -136,6 +136,50 @@ msgctxt "#32029"
msgid "Automatically Update IP Address On Startup"
msgstr "Automatically Update IP Address On Startup"
+msgctxt "#32030"
+msgid "Switch Sonos To Line-In On Media Start"
+msgstr "Switch Sonos To Line-In On Media Start"
+
+msgctxt "#32031"
+msgid "Coordinator"
+msgstr "Coordinator"
+
+msgctxt "#32032"
+msgid "is not the group coordinator for zone"
+msgstr "is not the group coordinator for zone"
+
+msgctxt "#32033"
+msgid "Some functions may not work correctly if the speaker is not a
coordinator"
+msgstr "Some functions may not work correctly if the speaker is not a
coordinator"
+
+msgctxt "#32034"
+msgid "Automation"
+msgstr "Automation"
+
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Layout"
+
+msgctxt "#32036"
+msgid "Controller,Slideshow,Bio,Albums"
+msgstr "Controller,Slideshow,Bio,Albums"
+
+msgctxt "#32037"
+msgid "Controller,Slideshow"
+msgstr "Controller,Slideshow"
+
+msgctxt "#32038"
+msgid "Use Skin Icons Instead Of Sonos Icons"
+msgstr "Use Skin Icons Instead Of Sonos Icons"
+
+msgctxt "#32039"
+msgid "Slideshow Only"
+msgstr "Slideshow Only"
+
+msgctxt "#32040"
+msgid "Do Not Display Notification If Controller Is Showing"
+msgstr "Do Not Display Notification If Controller Is Showing"
+
msgctxt "#32060"
msgid "The following setting in ArtistSlideshow must be enabled"
msgstr "The following setting in ArtistSlideshow must be enabled"
@@ -164,6 +208,10 @@ msgctxt "#32103"
msgid "Launch Sonos Controller"
msgstr "Launch Sonos Controller"
+msgctxt "#32104"
+msgid "Sonos Playlists"
+msgstr "Sonos Playlists"
+
msgctxt "#32110"
msgid "Artists"
msgstr "Artists"
diff --git a/script.sonos/resources/language/English/strings.po
b/script.sonos/resources/language/English/strings.po
index 19aea08..49c4f67 100644
--- a/script.sonos/resources/language/English/strings.po
+++ b/script.sonos/resources/language/English/strings.po
@@ -220,7 +220,11 @@ msgctxt "#32104"
msgid "Sonos Playlists"
msgstr ""
-#empty strings from id 32105 to 32109
+msgctxt "#32105"
+msgid "Speech"
+msgstr ""
+
+#empty strings from id 32106 to 32109
msgctxt "#32110"
msgid "Artists"
@@ -271,3 +275,56 @@ msgstr ""
msgctxt "#32156"
msgid "Replace Queue"
msgstr ""
+
+#empty strings from id 32157 to 32199
+
+msgctxt "#32200"
+msgid "Enter Speech Text To Play ..."
+msgstr ""
+
+msgctxt "#32201"
+msgid "Speech messages are limited to 100 characters"
+msgstr ""
+
+msgctxt "#32202"
+msgid "No message specified"
+msgstr ""
+
+msgctxt "#32203"
+msgid "Enter Speech Text To Save ..."
+msgstr ""
+
+msgctxt "#32204"
+msgid "Remove Saved Text"
+msgstr ""
+
+#empty strings from id 32204 to 32219
+
+msgctxt "#32220"
+msgid "The time is %time"
+msgstr ""
+
+msgctxt "#32221"
+msgid "Today is %day"
+msgstr ""
+
+msgctxt "#32222"
+msgid "Todays date is %date"
+msgstr ""
+
+msgctxt "#32223"
+msgid "Good Morning"
+msgstr ""
+
+msgctxt "#32224"
+msgid "Good Afternon"
+msgstr ""
+
+msgctxt "#32225"
+msgid "Good Evening"
+msgstr ""
+
+msgctxt "#32226"
+msgid "The time is %time"
+msgstr ""
+
diff --git a/script.sonos/resources/language/Estonian/strings.po
b/script.sonos/resources/language/Estonian/strings.po
index 2380b19..d539999 100644
--- a/script.sonos/resources/language/Estonian/strings.po
+++ b/script.sonos/resources/language/Estonian/strings.po
@@ -36,6 +36,10 @@ msgctxt "#32012"
msgid "Debugging"
msgstr "Silumine"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Paigutus"
+
msgctxt "#32062"
msgid "Next"
msgstr "Järgmine"
diff --git a/script.sonos/resources/language/Finnish/strings.po
b/script.sonos/resources/language/Finnish/strings.po
index 93fd54b..750d69f 100644
--- a/script.sonos/resources/language/Finnish/strings.po
+++ b/script.sonos/resources/language/Finnish/strings.po
@@ -36,6 +36,10 @@ msgctxt "#32012"
msgid "Debugging"
msgstr "Debugging"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Ulkoasu"
+
msgctxt "#32062"
msgid "Next"
msgstr "Seuraava"
diff --git a/script.sonos/resources/language/French (Canada)/strings.po
b/script.sonos/resources/language/French (Canada)/strings.po
index aca731c..4c397ca 100644
--- a/script.sonos/resources/language/French (Canada)/strings.po
+++ b/script.sonos/resources/language/French (Canada)/strings.po
@@ -136,6 +136,50 @@ msgctxt "#32029"
msgid "Automatically Update IP Address On Startup"
msgstr "Mettre à jour l'adresse IP automatiquement lors du démarrage"
+msgctxt "#32030"
+msgid "Switch Sonos To Line-In On Media Start"
+msgstr "Basculer les Sonos sur Entrée de ligne au démarrage du média"
+
+msgctxt "#32031"
+msgid "Coordinator"
+msgstr "Coordinateur"
+
+msgctxt "#32032"
+msgid "is not the group coordinator for zone"
+msgstr "n'est pas le coordinateur du groupe pour la zone"
+
+msgctxt "#32033"
+msgid "Some functions may not work correctly if the speaker is not a
coordinator"
+msgstr "Certaines fonctions pourraient ne pas fonctionner correctement si le
haut-parleur n'est par un coordinateur"
+
+msgctxt "#32034"
+msgid "Automation"
+msgstr "Automatisation"
+
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Disposition"
+
+msgctxt "#32036"
+msgid "Controller,Slideshow,Bio,Albums"
+msgstr "Contrôleur,Diaporama,Bio,Albums"
+
+msgctxt "#32037"
+msgid "Controller,Slideshow"
+msgstr "Contrôleur,Diaporama"
+
+msgctxt "#32038"
+msgid "Use Skin Icons Instead Of Sonos Icons"
+msgstr "Utiliser les icônes de l'habillage au lieu de celles de Sonos"
+
+msgctxt "#32039"
+msgid "Slideshow Only"
+msgstr "Diaporama uniquement"
+
+msgctxt "#32040"
+msgid "Do Not Display Notification If Controller Is Showing"
+msgstr "Ne pas afficher les notifications si le contrôleur est affiché"
+
msgctxt "#32060"
msgid "The following setting in ArtistSlideshow must be enabled"
msgstr "Le paramètre suivant doit être activé dans le diaporama des
artistes"
@@ -164,6 +208,10 @@ msgctxt "#32103"
msgid "Launch Sonos Controller"
msgstr "Lancer le contrôleur Sonos"
+msgctxt "#32104"
+msgid "Sonos Playlists"
+msgstr "Listes de lectures Sonos"
+
msgctxt "#32110"
msgid "Artists"
msgstr "Artistes"
diff --git a/script.sonos/resources/language/French/strings.po
b/script.sonos/resources/language/French/strings.po
index c9fcc54..6dfa309 100644
--- a/script.sonos/resources/language/French/strings.po
+++ b/script.sonos/resources/language/French/strings.po
@@ -40,6 +40,10 @@ msgctxt "#32015"
msgid "Controller"
msgstr "Manette"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Disposition"
+
msgctxt "#32062"
msgid "Next"
msgstr "Suivant"
diff --git a/script.sonos/resources/language/Galician/strings.po
b/script.sonos/resources/language/Galician/strings.po
index c467697..0c341e2 100644
--- a/script.sonos/resources/language/Galician/strings.po
+++ b/script.sonos/resources/language/Galician/strings.po
@@ -136,6 +136,10 @@ msgctxt "#32029"
msgid "Automatically Update IP Address On Startup"
msgstr "Actualizar Automaticamente o Enderezo IP no Inicio"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Deseño"
+
msgctxt "#32060"
msgid "The following setting in ArtistSlideshow must be enabled"
msgstr "O seguinte axuste do ArtistSlideshow debe estar activado"
diff --git a/script.sonos/resources/language/German/strings.po
b/script.sonos/resources/language/German/strings.po
index 9bc6d84..3c719d3 100644
--- a/script.sonos/resources/language/German/strings.po
+++ b/script.sonos/resources/language/German/strings.po
@@ -34,7 +34,7 @@ msgstr "Benachrichtigungen aktivieren (benötigt Neustart)"
msgctxt "#32004"
msgid "Display Notification For (Seconds)"
-msgstr "zeige Benachrichtigungen für (Sekunden)"
+msgstr "Benachrichtigungen anzeigen für (Sekunden)"
msgctxt "#32005"
msgid "Notification Check Frequency (Seconds)"
@@ -136,6 +136,50 @@ msgctxt "#32029"
msgid "Automatically Update IP Address On Startup"
msgstr "Aktualisiere IP-Adresse beim Start automatisch"
+msgctxt "#32030"
+msgid "Switch Sonos To Line-In On Media Start"
+msgstr "Schalte Sonos um zum Line-In beim Medienstart"
+
+msgctxt "#32031"
+msgid "Coordinator"
+msgstr "Koordinator"
+
+msgctxt "#32032"
+msgid "is not the group coordinator for zone"
+msgstr "ist nicht der Gruppenkoordinator für die Zone"
+
+msgctxt "#32033"
+msgid "Some functions may not work correctly if the speaker is not a
coordinator"
+msgstr "Einige Funktionen funktionieren möglicherweise nicht richtig, wenn
der Sprecher kein Koordinator ist"
+
+msgctxt "#32034"
+msgid "Automation"
+msgstr "Automatisierung"
+
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Layout"
+
+msgctxt "#32036"
+msgid "Controller,Slideshow,Bio,Albums"
+msgstr "Controller, Diaschau, Bio, Alben"
+
+msgctxt "#32037"
+msgid "Controller,Slideshow"
+msgstr "Controller, Diaschau"
+
+msgctxt "#32038"
+msgid "Use Skin Icons Instead Of Sonos Icons"
+msgstr "Benutze Oberflächen-Icons statt Sonos-Icons"
+
+msgctxt "#32039"
+msgid "Slideshow Only"
+msgstr "Nur Diaschau"
+
+msgctxt "#32040"
+msgid "Do Not Display Notification If Controller Is Showing"
+msgstr "Keine Benachrichtigungen wenn der Controller angezeigt wird"
+
msgctxt "#32060"
msgid "The following setting in ArtistSlideshow must be enabled"
msgstr "Die folgende Einstellung in 'ArtistSlideshow' muss aktiviert sein"
@@ -164,6 +208,10 @@ msgctxt "#32103"
msgid "Launch Sonos Controller"
msgstr "Starte Sonos-Controller"
+msgctxt "#32104"
+msgid "Sonos Playlists"
+msgstr "Sonos-Wiedergabelisten"
+
msgctxt "#32110"
msgid "Artists"
msgstr "Interpreten"
diff --git a/script.sonos/resources/language/Greek/strings.po
b/script.sonos/resources/language/Greek/strings.po
index 5dd296e..b9877ee 100644
--- a/script.sonos/resources/language/Greek/strings.po
+++ b/script.sonos/resources/language/Greek/strings.po
@@ -136,6 +136,50 @@ msgctxt "#32029"
msgid "Automatically Update IP Address On Startup"
msgstr "ÎÏ
ÏÏμαÏη ÎνημÎÏÏÏη ÎιεÏθÏ
νÏÎ·Ï IP καÏά
Ïην ÎκκίνηÏη"
+msgctxt "#32030"
+msgid "Switch Sonos To Line-In On Media Start"
+msgstr "Îναλλαγή ÏοÏ
Sonos Ïε ÎίÏοδο ÎÏοÏ
καÏά
Ïην ÎναÏαÏαγÏγή"
+
+msgctxt "#32031"
+msgid "Coordinator"
+msgstr "ÎιαÏειÏιÏÏήÏ"
+
+msgctxt "#32032"
+msgid "is not the group coordinator for zone"
+msgstr "δεν είναι ο ÏÏ
νÏονιÏÏÎ®Ï ÏοÏ
γκÏοÏ
Ï Î³Î¹Î±
Ïη ζÏνη"
+
+msgctxt "#32033"
+msgid "Some functions may not work correctly if the speaker is not a
coordinator"
+msgstr "ÎνδÎÏεÏαι να μη δοÏ
λÎÏοÏ
ν Ïλα ÏÏÏÏά αν
Ïο ηÏείο δεν είναι ÏÏ
νÏονιÏÏήÏ"
+
+msgctxt "#32034"
+msgid "Automation"
+msgstr "ÎÏ
ÏομαÏοÏοίηÏη"
+
+msgctxt "#32035"
+msgid "Layout"
+msgstr "ÎιάÏαξη"
+
+msgctxt "#32036"
+msgid "Controller,Slideshow,Bio,Albums"
+msgstr "ΧειÏιÏÏήÏιο,Î
αÏ.ÎιαÏανειÏν,ÎιογÏαÏία,ÎλμÏοÏ
μ"
+
+msgctxt "#32037"
+msgid "Controller,Slideshow"
+msgstr "ΧειÏιÏÏήÏιο,ΠαÏ.ÎιαÏανειÏν"
+
+msgctxt "#32038"
+msgid "Use Skin Icons Instead Of Sonos Icons"
+msgstr "ΧÏήÏη ÎικονιδίÏν ÎελÏÏοÏ
Ï ÎνÏί ÎÏ
ÏÏν
ΤοÏ
Sonos"
+
+msgctxt "#32039"
+msgid "Slideshow Only"
+msgstr "ÎÏνο ΠαÏοÏ
ÏίαÏη ÎιαÏανειÏν"
+
+msgctxt "#32040"
+msgid "Do Not Display Notification If Controller Is Showing"
+msgstr "Îα Îην ÎμÏανίζονÏαι ÎιδοÏοιήÏÎµÎ¹Ï Îε
Τα ΧειÏιÏÏήÏια"
+
msgctxt "#32060"
msgid "The following setting in ArtistSlideshow must be enabled"
msgstr "ΠακÏλοÏ
θη ÏÏθμιÏη ÏÏο ArtistSlideshow ÏÏÎÏει
να ενεÏγοÏοιηθεί"
@@ -164,6 +208,10 @@ msgctxt "#32103"
msgid "Launch Sonos Controller"
msgstr "ÎναÏξη ÏοÏ
ΧειÏιÏÏηÏίοÏ
Sonos"
+msgctxt "#32104"
+msgid "Sonos Playlists"
+msgstr "ÎίÏÏÎµÏ ÎναÏ/Î³Î®Ï Sonos"
+
msgctxt "#32110"
msgid "Artists"
msgstr "ÎαλλιÏÎÏνεÏ"
diff --git a/script.sonos/resources/language/Hungarian/strings.po
b/script.sonos/resources/language/Hungarian/strings.po
index 4207a2e..bb8dfbd 100644
--- a/script.sonos/resources/language/Hungarian/strings.po
+++ b/script.sonos/resources/language/Hungarian/strings.po
@@ -92,6 +92,10 @@ msgctxt "#32019"
msgid "Batch Size"
msgstr "Köteg Méret"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Ãttekintés"
+
msgctxt "#32062"
msgid "Next"
msgstr "KövetkezÅ"
diff --git a/script.sonos/resources/language/Icelandic/strings.po
b/script.sonos/resources/language/Icelandic/strings.po
index 1ba24aa..49a7107 100644
--- a/script.sonos/resources/language/Icelandic/strings.po
+++ b/script.sonos/resources/language/Icelandic/strings.po
@@ -32,6 +32,10 @@ msgctxt "#32012"
msgid "Debugging"
msgstr "Aflúsa"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "SÃðuuppsetning"
+
msgctxt "#32062"
msgid "Next"
msgstr "Næst"
diff --git a/script.sonos/resources/language/Italian/strings.po
b/script.sonos/resources/language/Italian/strings.po
index 1573c59..3bc398b 100644
--- a/script.sonos/resources/language/Italian/strings.po
+++ b/script.sonos/resources/language/Italian/strings.po
@@ -124,6 +124,10 @@ msgctxt "#32029"
msgid "Automatically Update IP Address On Startup"
msgstr "Aggiorna Automaticamente l'indirizzo IP all'avvio"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Impaginazione"
+
msgctxt "#32060"
msgid "The following setting in ArtistSlideshow must be enabled"
msgstr "La seguente impostazione in ArtistSlideShow deve essere abilitata"
diff --git a/script.sonos/resources/language/Korean/strings.po
b/script.sonos/resources/language/Korean/strings.po
index 5aa1c90..4b2238f 100644
--- a/script.sonos/resources/language/Korean/strings.po
+++ b/script.sonos/resources/language/Korean/strings.po
@@ -36,6 +36,10 @@ msgctxt "#32012"
msgid "Debugging"
msgstr "ëë²ê¹
"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "íë©´ 구ì±"
+
msgctxt "#32062"
msgid "Next"
msgstr "ë¤ì"
diff --git a/script.sonos/resources/language/Lithuanian/strings.po
b/script.sonos/resources/language/Lithuanian/strings.po
index b7dc954..512b9dd 100644
--- a/script.sonos/resources/language/Lithuanian/strings.po
+++ b/script.sonos/resources/language/Lithuanian/strings.po
@@ -136,6 +136,50 @@ msgctxt "#32029"
msgid "Automatically Update IP Address On Startup"
msgstr "AutomatiÅ¡kai atnaujinti IP adresÄ
paleidžiant"
+msgctxt "#32030"
+msgid "Switch Sonos To Line-In On Media Start"
+msgstr "Perjungti į Sonos į Line-In įÄjimÄ
paleidus media įraÅ¡Ä
"
+
+msgctxt "#32031"
+msgid "Coordinator"
+msgstr "Koordinatorius"
+
+msgctxt "#32032"
+msgid "is not the group coordinator for zone"
+msgstr "nÄra koordinatorius zonoje"
+
+msgctxt "#32033"
+msgid "Some functions may not work correctly if the speaker is not a
coordinator"
+msgstr "Kai kurios funkcijos gali veikti netinkamai, jei garsiakalbis nÄra
koordinatorius"
+
+msgctxt "#32034"
+msgid "Automation"
+msgstr "Automatizavimas"
+
+msgctxt "#32035"
+msgid "Layout"
+msgstr "IÅ¡dÄstymas"
+
+msgctxt "#32036"
+msgid "Controller,Slideshow,Bio,Albums"
+msgstr "Valdiklis, skaidrių peržiūra, biografija, albumai"
+
+msgctxt "#32037"
+msgid "Controller,Slideshow"
+msgstr "Valdiklis, skaidrių peržiūra"
+
+msgctxt "#32038"
+msgid "Use Skin Icons Instead Of Sonos Icons"
+msgstr "Naudoti teminÄs iÅ¡vaizdos piktogramas vietoje Sonos piktogramų"
+
+msgctxt "#32039"
+msgid "Slideshow Only"
+msgstr "Tik skaidrių peržiūra"
+
+msgctxt "#32040"
+msgid "Do Not Display Notification If Controller Is Showing"
+msgstr "Nerodyti pranešimų, jei rodomas valdiklis"
+
msgctxt "#32060"
msgid "The following setting in ArtistSlideshow must be enabled"
msgstr "ArtistSlideshow turi būti įjungti šie nustatymai"
@@ -164,6 +208,10 @@ msgctxt "#32103"
msgid "Launch Sonos Controller"
msgstr "Paleisti Sonos valdiklį"
+msgctxt "#32104"
+msgid "Sonos Playlists"
+msgstr "Sonos grojaraÅ¡Äiai"
+
msgctxt "#32110"
msgid "Artists"
msgstr "AtlikÄjai"
diff --git a/script.sonos/resources/language/Malay/strings.po
b/script.sonos/resources/language/Malay/strings.po
index 3acf2d7..8bc56a5 100644
--- a/script.sonos/resources/language/Malay/strings.po
+++ b/script.sonos/resources/language/Malay/strings.po
@@ -24,6 +24,10 @@ msgctxt "#32015"
msgid "Controller"
msgstr "Pengawal"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Bentangan"
+
msgctxt "#32062"
msgid "Next"
msgstr "Seterusnya"
diff --git a/script.sonos/resources/language/Norwegian/strings.po
b/script.sonos/resources/language/Norwegian/strings.po
index d601ee1..5c5c61d 100644
--- a/script.sonos/resources/language/Norwegian/strings.po
+++ b/script.sonos/resources/language/Norwegian/strings.po
@@ -136,6 +136,10 @@ msgctxt "#32029"
msgid "Automatically Update IP Address On Startup"
msgstr "Automatisk oppdater IP adresse ved oppstart"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Utforming"
+
msgctxt "#32060"
msgid "The following setting in ArtistSlideshow must be enabled"
msgstr "Følgende innstilling i ArtistSlideshow må være aktivert"
diff --git a/script.sonos/resources/language/Polish/strings.po
b/script.sonos/resources/language/Polish/strings.po
index 7de9b6d..2f61877 100644
--- a/script.sonos/resources/language/Polish/strings.po
+++ b/script.sonos/resources/language/Polish/strings.po
@@ -136,6 +136,10 @@ msgctxt "#32029"
msgid "Automatically Update IP Address On Startup"
msgstr "Aktualizuj adres IP przy uruchomieniu"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "WyglÄ
d"
+
msgctxt "#32060"
msgid "The following setting in ArtistSlideshow must be enabled"
msgstr " MuszÄ
byÄ wÅÄ
czone nastÄpujÄ
ce ustawienia w ArtistSlideshow"
diff --git a/script.sonos/resources/language/Portuguese (Brazil)/strings.po
b/script.sonos/resources/language/Portuguese (Brazil)/strings.po
index 0b6259f..4eb7b98 100644
--- a/script.sonos/resources/language/Portuguese (Brazil)/strings.po
+++ b/script.sonos/resources/language/Portuguese (Brazil)/strings.po
@@ -136,6 +136,50 @@ msgctxt "#32029"
msgid "Automatically Update IP Address On Startup"
msgstr "Atualizar automaticamente o endereço de IP ao inicializar"
+msgctxt "#32030"
+msgid "Switch Sonos To Line-In On Media Start"
+msgstr "Alternar Sonos para Line-in ao iniciar mÃdia"
+
+msgctxt "#32031"
+msgid "Coordinator"
+msgstr "Coordenador"
+
+msgctxt "#32032"
+msgid "is not the group coordinator for zone"
+msgstr "não é o coordenador do grupo para a zona"
+
+msgctxt "#32033"
+msgid "Some functions may not work correctly if the speaker is not a
coordinator"
+msgstr "Algumas funções podem não funcionar corretamente se o alto-falante
não for um coordenador"
+
+msgctxt "#32034"
+msgid "Automation"
+msgstr "Automação"
+
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Layout"
+
+msgctxt "#32036"
+msgid "Controller,Slideshow,Bio,Albums"
+msgstr "Controlador,Slideshow,Bio,Ãlbuns"
+
+msgctxt "#32037"
+msgid "Controller,Slideshow"
+msgstr "Controlador,Slideshow"
+
+msgctxt "#32038"
+msgid "Use Skin Icons Instead Of Sonos Icons"
+msgstr "Usar Ãcones da Skin ao invés de Ãcones do Sonos"
+
+msgctxt "#32039"
+msgid "Slideshow Only"
+msgstr "Somente slideshow"
+
+msgctxt "#32040"
+msgid "Do Not Display Notification If Controller Is Showing"
+msgstr "Não mostrar Notificação se Controlador estiver sendo apresentado."
+
msgctxt "#32060"
msgid "The following setting in ArtistSlideshow must be enabled"
msgstr "O ajuste seguinte deve estar ativo no ArtistSlideshow"
@@ -164,6 +208,10 @@ msgctxt "#32103"
msgid "Launch Sonos Controller"
msgstr "Lançar Controlador Sonos"
+msgctxt "#32104"
+msgid "Sonos Playlists"
+msgstr "Listas de reprodução Sonos"
+
msgctxt "#32110"
msgid "Artists"
msgstr "Artistas"
diff --git a/script.sonos/resources/language/Portuguese/strings.po
b/script.sonos/resources/language/Portuguese/strings.po
index ed4bfb3..dae17b0 100644
--- a/script.sonos/resources/language/Portuguese/strings.po
+++ b/script.sonos/resources/language/Portuguese/strings.po
@@ -128,6 +128,10 @@ msgctxt "#32029"
msgid "Automatically Update IP Address On Startup"
msgstr "Actualizar Automaticamente o Endereço IP ao Iniciar"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Dispor"
+
msgctxt "#32060"
msgid "The following setting in ArtistSlideshow must be enabled"
msgstr "A seguinte definição tem de estar activa em ArtistSlideshow"
diff --git a/script.sonos/resources/language/Russian/strings.po
b/script.sonos/resources/language/Russian/strings.po
index 65bb93c..bb313c0 100644
--- a/script.sonos/resources/language/Russian/strings.po
+++ b/script.sonos/resources/language/Russian/strings.po
@@ -40,6 +40,10 @@ msgctxt "#32015"
msgid "Controller"
msgstr "ÐонÑÑоллеÑ"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "ÐакеÑâ¦"
+
msgctxt "#32062"
msgid "Next"
msgstr "СледÑÑÑ."
diff --git a/script.sonos/resources/language/Slovak/strings.po
b/script.sonos/resources/language/Slovak/strings.po
index a9fec9e..a4cd86e 100644
--- a/script.sonos/resources/language/Slovak/strings.po
+++ b/script.sonos/resources/language/Slovak/strings.po
@@ -36,6 +36,10 @@ msgctxt "#32012"
msgid "Debugging"
msgstr "Ladenie / Debug"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Rozloženie"
+
msgctxt "#32062"
msgid "Next"
msgstr "Násl."
diff --git a/script.sonos/resources/language/Spanish (Mexico)/strings.po
b/script.sonos/resources/language/Spanish (Mexico)/strings.po
index 175cddd..5e776af 100644
--- a/script.sonos/resources/language/Spanish (Mexico)/strings.po
+++ b/script.sonos/resources/language/Spanish (Mexico)/strings.po
@@ -32,6 +32,10 @@ msgctxt "#32012"
msgid "Debugging"
msgstr "Debugging"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Disposición"
+
msgctxt "#32062"
msgid "Next"
msgstr "Siguiente"
diff --git a/script.sonos/resources/language/Spanish/strings.po
b/script.sonos/resources/language/Spanish/strings.po
index 1bf3358..9b899f8 100644
--- a/script.sonos/resources/language/Spanish/strings.po
+++ b/script.sonos/resources/language/Spanish/strings.po
@@ -136,6 +136,10 @@ msgctxt "#32029"
msgid "Automatically Update IP Address On Startup"
msgstr "Actualizar Dirección IP Automáticamente Al Arrancar"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Diseño"
+
msgctxt "#32060"
msgid "The following setting in ArtistSlideshow must be enabled"
msgstr "La siguiente configuración en ArtistSlideshow debe estar habilitada"
diff --git a/script.sonos/resources/language/Swedish/strings.po
b/script.sonos/resources/language/Swedish/strings.po
index 34378ba..5118a27 100644
--- a/script.sonos/resources/language/Swedish/strings.po
+++ b/script.sonos/resources/language/Swedish/strings.po
@@ -136,6 +136,50 @@ msgctxt "#32029"
msgid "Automatically Update IP Address On Startup"
msgstr "Uppdatera IP-adress automatiskt vid uppstart"
+msgctxt "#32030"
+msgid "Switch Sonos To Line-In On Media Start"
+msgstr "Ãndra Sonos till 'Line-In PÃ¥' vid Media start"
+
+msgctxt "#32031"
+msgid "Coordinator"
+msgstr "Koordinator"
+
+msgctxt "#32032"
+msgid "is not the group coordinator for zone"
+msgstr "är inte 'grupp-koordinator' för zon"
+
+msgctxt "#32033"
+msgid "Some functions may not work correctly if the speaker is not a
coordinator"
+msgstr "Vissa funktioner kan fungera sämre om högtalaren inte är en
koordinator"
+
+msgctxt "#32034"
+msgid "Automation"
+msgstr "Automatisering"
+
+msgctxt "#32035"
+msgid "Layout"
+msgstr "Layout"
+
+msgctxt "#32036"
+msgid "Controller,Slideshow,Bio,Albums"
+msgstr "Kontroller,Slideshow,Bio,Album"
+
+msgctxt "#32037"
+msgid "Controller,Slideshow"
+msgstr "Kontroller,Slideshow"
+
+msgctxt "#32038"
+msgid "Use Skin Icons Instead Of Sonos Icons"
+msgstr "Använd Skal-ikoner inställer för Sonos-ikoner"
+
+msgctxt "#32039"
+msgid "Slideshow Only"
+msgstr "Endast Slideshow"
+
+msgctxt "#32040"
+msgid "Do Not Display Notification If Controller Is Showing"
+msgstr "Visa inte avisering om kontroller visas"
+
msgctxt "#32060"
msgid "The following setting in ArtistSlideshow must be enabled"
msgstr "Följande inställningar måste vara aktiverade i ArtistSlideshow"
@@ -164,6 +208,10 @@ msgctxt "#32103"
msgid "Launch Sonos Controller"
msgstr "Starta Sonos Kontroller"
+msgctxt "#32104"
+msgid "Sonos Playlists"
+msgstr "Sonos Spellistor"
+
msgctxt "#32110"
msgid "Artists"
msgstr "Artister"
diff --git a/script.sonos/resources/language/Thai/strings.po
b/script.sonos/resources/language/Thai/strings.po
index 916028b..3b8798b 100644
--- a/script.sonos/resources/language/Thai/strings.po
+++ b/script.sonos/resources/language/Thai/strings.po
@@ -32,6 +32,10 @@ msgctxt "#32012"
msgid "Debugging"
msgstr "à¹à¸à¹à¸à¸¸à¸à¸à¸à¸à¸£à¹à¸à¸"
+msgctxt "#32035"
+msgid "Layout"
+msgstr "วาà¸à¹à¸à¸"
+
msgctxt "#32062"
msgid "Next"
msgstr "à¸à¹à¸à¹à¸"
diff --git a/script.sonos/resources/language/Vietnamese (Viet Nam)/strings.po
b/script.sonos/resources/language/Vietnamese (Viet Nam)/strings.po
index 63c188c..e0dc622 100644
--- a/script.sonos/resources/language/Vietnamese (Viet Nam)/strings.po
+++ b/script.sonos/resources/language/Vietnamese (Viet Nam)/strings.po
@@ -1,4 +1,4 @@
-# XBMC Media Center language file
+# Kodi Media Center language file
# Addon Name: Sonos
# Addon id: script.sonos
# Addon Provider: robwebset
@@ -8,7 +8,7 @@ msgstr ""
"Report-Msgid-Bugs-To: [email protected]\n"
"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: XBMC Translation Team\n"
+"Last-Translator: Kodi Translation Team\n"
"Language-Team: Vietnamese (Viet Nam)
(http://www.transifex.com/projects/p/xbmc-addons/language/vi_VN/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -16,10 +16,6 @@ msgstr ""
"Language: vi_VN\n"
"Plural-Forms: nplurals=1; plural=0;\n"
-msgctxt "#32012"
-msgid "Advanced"
-msgstr "Nâng ca"
-
msgctxt "#32110"
msgid "Artists"
msgstr "NghỠsĩ"
@@ -28,10 +24,6 @@ msgctxt "#32111"
msgid "Albums"
msgstr "Bá» sưu táºp"
-msgctxt "#32113"
-msgid "Genres"
-msgstr "ThỠloại"
-
msgctxt "#32114"
msgid "Tracks"
msgstr "BaÌi"
diff --git a/script.sonos/resources/lib/settings.py
b/script.sonos/resources/lib/settings.py
index ff8e6ff..71e2a2e 100644
--- a/script.sonos/resources/lib/settings.py
+++ b/script.sonos/resources/lib/settings.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+import os
import xbmc
import xbmcaddon
import logging
@@ -22,6 +23,22 @@ def log(txt, loglevel=xbmc.LOGDEBUG):
xbmc.log(msg=message.encode("utf-8"), level=loglevel)
+# There has been problems with calling join with non ascii characters,
+# so we have this method to try and do the conversion for us
+def os_path_join(dir, file):
+ # Convert each argument - if an error, then it will use the default value
+ # that was passed in
+ try:
+ dir = dir.decode("utf-8")
+ except:
+ pass
+ try:
+ file = file.decode("utf-8")
+ except:
+ pass
+ return os.path.join(dir, file)
+
+
# Class used to supply XBMC logging to the soco scripts
class SocoLogging(logging.Handler):
def emit(self, message):
diff --git a/script.sonos/resources/lib/soco/__init__.py
b/script.sonos/resources/lib/soco/__init__.py
index e7c55e4..8d6ba63 100644
--- a/script.sonos/resources/lib/soco/__init__.py
+++ b/script.sonos/resources/lib/soco/__init__.py
@@ -9,7 +9,7 @@
# Will be parsed by setup.py to determine package metadata
__author__ = 'The SoCo-Team <[email protected]>'
-__version__ = '0.8.1'
+__version__ = '0.8.3'
__website__ = 'https://github.com/SoCo/SoCo'
__license__ = 'MIT License'
diff --git a/script.sonos/resources/lib/soco/core.py
b/script.sonos/resources/lib/soco/core.py
index ddfce37..5d6158c 100644
--- a/script.sonos/resources/lib/soco/core.py
+++ b/script.sonos/resources/lib/soco/core.py
@@ -20,7 +20,7 @@ from .services import AlarmClock
from .groups import ZoneGroup
from .exceptions import CannotCreateDIDLMetadata
from .data_structures import get_ml_item, QueueItem, URI, MLSonosPlaylist,\
- MLShare
+ MLShare, SearchResult, Queue, MusicLibraryItem
from .utils import really_utf8, camel_to_underscore
from .xml import XML
from soco import config
@@ -139,7 +139,7 @@ class _ArgsSingleton(type):
return cls._instances[key][args]
-class _SocoSingletonBase( # pylint: disable=too-few-public-methods
+class _SocoSingletonBase( # pylint: disable=too-few-public-methods,no-init
_ArgsSingleton(str('ArgsSingletonMeta'), (object,), {})):
""" The base class for the SoCo class.
@@ -180,7 +180,6 @@ class SoCo(_SocoSingletonBase):
join -- Join this speaker to another "master" speaker.
unjoin -- Remove this speaker from a group.
get_queue -- Get information about the queue.
- get_folders -- Get search folders from the music library
get_artists -- Get artists from the music library
get_album_artists -- Get album artists from the music library
get_albums -- Get albums from the music library
@@ -190,6 +189,7 @@ class SoCo(_SocoSingletonBase):
get_playlists -- Get playlists from the music library
get_music_library_information -- Get information from the music library
get_current_transport_info -- get speakers playing state
+ browse_by_idstring -- Browse (get sub-elements) a given type
add_uri_to_queue -- Adds an URI to the queue
add_to_queue -- Add a track to the end of the queue
remove_from_queue -- Remove a track from the queue
@@ -197,6 +197,9 @@ class SoCo(_SocoSingletonBase):
get_favorite_radio_shows -- Get favorite radio shows from Sonos'
Radio app.
get_favorite_radio_stations -- Get favorite radio stations.
+ create_sonos_playlist -- Creates a new Sonos' playlist
+ add_item_to_sonos_playlist -- Adds a queueable item to a Sonos'
+ playlist
Properties::
@@ -220,6 +223,19 @@ class SoCo(_SocoSingletonBase):
_class_group = 'SoCo'
+ # Key words used when performing searches
+ SEARCH_TRANSLATION = {'artists': 'A:ARTIST',
+ 'album_artists': 'A:ALBUMARTIST',
+ 'albums': 'A:ALBUM',
+ 'genres': 'A:GENRE',
+ 'composers': 'A:COMPOSER',
+ 'tracks': 'A:TRACKS',
+ 'playlists': 'A:PLAYLISTS',
+ 'share': 'S:',
+ 'sonos_playlists': 'SQ:',
+ 'categories': 'A:'}
+
+ # pylint: disable=super-on-old-class
def __init__(self, ip_address):
# Note: Creation of a SoCo instance should be as cheap and quick as
# possible. Do not make any network calls here
@@ -405,7 +421,7 @@ class SoCo(_SocoSingletonBase):
warnings.warn("speaker_ip is deprecated. Use ip_address instead.")
return self.ip_address
- def play_from_queue(self, index):
+ def play_from_queue(self, index, start=True):
""" Play a track from the queue by index. The index number is
required as an argument, where the first index is 0.
@@ -438,7 +454,9 @@ class SoCo(_SocoSingletonBase):
])
# finally, just play what's set
- return self.play()
+ if start:
+ return self.play()
+ return False
def play(self):
"""Play the currently selected track.
@@ -454,12 +472,17 @@ class SoCo(_SocoSingletonBase):
('Speed', 1)
])
- def play_uri(self, uri='', meta=''):
+ def play_uri(self, uri='', meta='', title='', start=True):
""" Play a given stream. Pauses the queue.
+ If there is no metadata passed in and there is a title set then a
+ metadata object will be created. This is often the case if you have
+ a custom stream, it will need at least the title in the metadata in
+ order to play.
Arguments:
uri -- URI of a stream to be played.
- meta --- The track metadata to show in the player, DIDL format.
+ meta -- The track metadata to show in the player, DIDL format.
+ title -- The track title to show in the player
Returns:
True if the Sonos speaker successfully started playing the track.
@@ -467,14 +490,29 @@ class SoCo(_SocoSingletonBase):
Raises SoCoException (or a subclass) upon errors.
"""
+ if meta == '' and title != '':
+ meta_template = '<DIDL-Lite xmlns:dc="http://purl.org/dc/elements'\
+ '/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" '\
+ 'xmlns:r="urn:schemas-rinconnetworks-com:metadata-1-0/" '\
+ 'xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/">'\
+ '<item id="R:0/0/0" parentID="R:0/0" restricted="true">'\
+ '<dc:title>{title}</dc:title><upnp:class>'\
+ 'object.item.audioItem.audioBroadcast</upnp:class><desc '\
+ 'id="cdudn" nameSpace="urn:schemas-rinconnetworks-com:'\
+ 'metadata-1-0/">{service}</desc></item></DIDL-Lite>'
+ tunein_service = 'SA_RINCON65031_'
+ # Radio stations need to have at least a title to play
+ meta = meta_template.format(title=title, service=tunein_service)
self.avTransport.SetAVTransportURI([
('InstanceID', 0),
('CurrentURI', uri),
('CurrentURIMetaData', meta)
])
- # The track is enqueued, now play it.
- return self.play()
+ # The track is enqueued, now play it if needed
+ if start:
+ return self.play()
+ return False
def pause(self):
""" Pause the currently playing track.
@@ -947,6 +985,9 @@ class SoCo(_SocoSingletonBase):
track['position'] = response['RelTime']
metadata = response['TrackMetaData']
+ # Store the entire Metadata entry in the track, this can then be
+ # used if needed by the client to restart a given URI
+ track['metadata'] = metadata
# Duration seems to be '0:00:00' when listening to radio
if metadata != '' and track['duration'] == '0:00:00':
metadata = XML.fromstring(really_utf8(metadata))
@@ -1093,12 +1134,14 @@ class SoCo(_SocoSingletonBase):
return playstate
- def get_queue(self, start=0, max_items=100):
+ def get_queue(self, start=0, max_items=100, full_album_art_uri=False):
""" Get information about the queue
:param start: Starting number of returned matches
:param max_items: Maximum number of returned matches
- :returns: A list of :py:class:`~.soco.data_structures.QueueItem`.
+ :param full_album_art_uri: If the album art URI should include the
+ IP address
+ :returns: A :py:class:`~.soco.data_structures.Queue` object
This method is heavly based on Sam Soffes (aka soffes) ruby
implementation
@@ -1114,18 +1157,31 @@ class SoCo(_SocoSingletonBase):
('SortCriteria', '')
])
result = response['Result']
+
+ metadata = {}
+ for tag in ['NumberReturned', 'TotalMatches', 'UpdateID']:
+ metadata[camel_to_underscore(tag)] = int(response[tag])
+
+ # I'm not sure this necessary (any more). Even with an empty queue,
+ # there is still a result object. This shoud be investigated.
if not result:
- return queue
+ # pylint: disable=star-args
+ return Queue(queue, **metadata)
result_dom = XML.fromstring(really_utf8(result))
for element in result_dom.findall(
'{urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/}item'):
item = QueueItem.from_xml(element)
+ # Check if the album art URI should be fully qualified
+ if full_album_art_uri:
+ self._update_album_art_to_full_uri(item)
queue.append(item)
- return queue
+ # pylint: disable=star-args
+ return Queue(queue, **metadata)
- def get_sonos_playlists(self, start=0, max_items=100):
+ def get_sonos_playlists(self, start=0, max_items=100,
+ full_album_art_uri=False):
""" Convenience method for:
get_music_library_information('sonos_playlists')
Refer to the docstring for that method
@@ -1134,65 +1190,73 @@ class SoCo(_SocoSingletonBase):
out = self.get_music_library_information(
'sonos_playlists',
start,
- max_items)
+ max_items,
+ full_album_art_uri)
return out
- def get_artists(self, start=0, max_items=100):
+ def get_artists(self, start=0, max_items=100, full_album_art_uri=False):
""" Convinience method for :py:meth:`get_music_library_information`
with `search_type='artists'`. For details on remaining arguments refer
to the docstring for that method.
"""
- out = self.get_music_library_information('artists', start, max_items)
+ out = self.get_music_library_information('artists', start, max_items,
+ full_album_art_uri)
return out
- def get_album_artists(self, start=0, max_items=100):
+ def get_album_artists(self, start=0, max_items=100,
+ full_album_art_uri=False):
""" Convinience method for :py:meth:`get_music_library_information`
with `search_type='album_artists'`. For details on remaining arguments
refer to the docstring for that method.
"""
out = self.get_music_library_information('album_artists',
- start, max_items)
+ start, max_items,
+ full_album_art_uri)
return out
- def get_albums(self, start=0, max_items=100):
+ def get_albums(self, start=0, max_items=100, full_album_art_uri=False):
""" Convinience method for :py:meth:`get_music_library_information`
with `search_type='albums'`. For details on remaining arguments refer
to the docstring for that method.
"""
- out = self.get_music_library_information('albums', start, max_items)
+ out = self.get_music_library_information('albums', start, max_items,
+ full_album_art_uri)
return out
- def get_genres(self, start=0, max_items=100):
+ def get_genres(self, start=0, max_items=100, full_album_art_uri=False):
""" Convinience method for :py:meth:`get_music_library_information`
with `search_type='genres'`. For details on remaining arguments refer
to the docstring for that method.
"""
- out = self.get_music_library_information('genres', start, max_items)
+ out = self.get_music_library_information('genres', start, max_items,
+ full_album_art_uri)
return out
- def get_composers(self, start=0, max_items=100):
+ def get_composers(self, start=0, max_items=100, full_album_art_uri=False):
""" Convinience method for :py:meth:`get_music_library_information`
with `search_type='composers'`. For details on remaining arguments
refer to the docstring for that method.
"""
- out = self.get_music_library_information('composers', start, max_items)
+ out = self.get_music_library_information('composers', start, max_items,
+ full_album_art_uri)
return out
- def get_tracks(self, start=0, max_items=100):
+ def get_tracks(self, start=0, max_items=100, full_album_art_uri=False):
""" Convinience method for :py:meth:`get_music_library_information`
with `search_type='tracks'`. For details on remaining arguments refer
to the docstring for that method.
"""
- out = self.get_music_library_information('tracks', start, max_items)
+ out = self.get_music_library_information('tracks', start, max_items,
+ full_album_art_uri)
return out
- def get_playlists(self, start=0, max_items=100):
+ def get_playlists(self, start=0, max_items=100, full_album_art_uri=False):
""" Convinience method for :py:meth:`get_music_library_information`
with `search_type='playlists'`. For details on remaining arguments
refer to the docstring for that method.
@@ -1201,11 +1265,12 @@ class SoCo(_SocoSingletonBase):
imported from the music library, they are not the Sonos playlists.
"""
- out = self.get_music_library_information('playlists', start, max_items)
+ out = self.get_music_library_information('playlists', start, max_items,
+ full_album_art_uri)
return out
def get_music_library_information(self, search_type, start=0,
- max_items=100):
+ max_items=100, full_album_art_uri=False):
""" Retrieve information about the music library
:param search_type: The kind of information to retrieve. Can be one of:
@@ -1218,20 +1283,9 @@ class SoCo(_SocoSingletonBase):
may be restricted by the unit, presumably due to transfer
size consideration, so check the returned number against the
requested.
- :returns: A dictionary with metadata for the search, with the
- keys 'number_returned', 'update_id', 'total_matches' and an
- 'item_list' list with the search results. The search results
- are instances of one of
- :py:class:`~.soco.data_structures.MLArtist`,
- :py:class:`~.soco.data_structures.MLAlbumArtist`,
- :py:class:`~.soco.data_structures.MLAlbum`,
- :py:class:`~.soco.data_structures.MLGenre`,
- :py:class:`~.soco.data_structures.MLComposer`,
- :py:class:`~.soco.data_structures.MLTrack`,
- :py:class:`~.soco.data_structures.MLShare`,
- :py:class:`~.soco.data_structures.MLSonosPlaylist and
- :py:class:`~.soco.data_structures.MLPlaylist` depending on the
- type of the search.
+ :param full_album_art_uri: If the album art URI should include the
+ IP address
+ :returns: A :py:class:`~.soco.data_structures.SearchResult` object
:raises: :py:class:`SoCoException` upon errors
NOTE: The playlists that are returned with the 'playlists' search, are
@@ -1244,23 +1298,13 @@ class SoCo(_SocoSingletonBase):
project.
"""
- search_translation = {'artists': 'A:ARTIST',
- 'album_artists': 'A:ALBUMARTIST',
- 'albums': 'A:ALBUM',
- 'genres': 'A:GENRE',
- 'composers': 'A:COMPOSER',
- 'tracks': 'A:TRACKS',
- 'playlists': 'A:PLAYLISTS',
- 'share': 'S:',
- 'sonos_playlists': 'SQ:',
- 'categories': 'A:'}
- search = search_translation[search_type]
- response, out = self._music_lib_search(search, start, max_items)
- out['search_type'] = search_type
- out['item_list'] = []
+ search = self.SEARCH_TRANSLATION[search_type]
+ response, metadata = self._music_lib_search(search, start, max_items)
+ metadata['search_type'] = search_type
# Parse the results
dom = XML.fromstring(really_utf8(response['Result']))
+ item_list = []
for container in dom:
if search_type == 'sonos_playlists':
item = MLSonosPlaylist.from_xml(container)
@@ -1268,12 +1312,17 @@ class SoCo(_SocoSingletonBase):
item = MLShare.from_xml(container)
else:
item = get_ml_item(container)
+ # Check if the album art URI should be fully qualified
+ if full_album_art_uri:
+ self._update_album_art_to_full_uri(item)
# Append the item to the list
- out['item_list'].append(item)
+ item_list.append(item)
- return out
+ # pylint: disable=star-args
+ return SearchResult(item_list, **metadata)
- def browse(self, ml_item=None, start=0, max_items=100):
+ def browse(self, ml_item=None, start=0, max_items=100,
+ full_album_art_uri=False):
"""Browse (get sub-elements) a music library item
Keyword arguments:
@@ -1282,11 +1331,11 @@ class SoCo(_SocoSingletonBase):
returned
start (int): The starting index of the results
max_items (int): The maximum number of items to return
+ full_album_art_uri(bool): If the album art URI should include the
+ IP address
Returns:
- dict: A dictionary with metadata for the search, with the
- keys 'number_returned', 'update_id', 'total_matches' and an
- 'item_list' list with the search results.
+ dict: A :py:class:`~.soco.data_structures.SearchResult` object
Raises:
AttributeError: If ``ml_item`` has no ``item_id`` attribute
@@ -1298,17 +1347,57 @@ class SoCo(_SocoSingletonBase):
else:
search = ml_item.item_id
- response, out = self._music_lib_search(search, start, max_items)
- out['search_type'] = 'browse'
- out['item_list'] = []
+ response, metadata = self._music_lib_search(search, start, max_items)
+ metadata['search_type'] = 'browse'
# Parse the results
dom = XML.fromstring(really_utf8(response['Result']))
+ item_list = []
for container in dom:
item = get_ml_item(container)
- out['item_list'].append(item)
+ # Check if the album art URI should be fully qualified
+ if full_album_art_uri:
+ self._update_album_art_to_full_uri(item)
+ item_list.append(item)
- return out
+ # pylint: disable=star-args
+ return SearchResult(item_list, **metadata)
+
+ # pylint: disable=too-many-arguments
+ def browse_by_idstring(self, search_type, idstring, start=0,
+ max_items=100, full_album_art_uri=False):
+ """Browse (get sub-elements) a given type
+
+ :param search_type: The kind of information to retrieve. Can be one of:
+ 'artists', 'album_artists', 'albums', 'genres', 'composers',
+ 'tracks', 'share', 'sonos_playlists', and 'playlists', where
+ playlists are the imported file based playlists from the
+ music library
+ :param idstring: String ID to search for
+ :param start: Starting number of returned matches
+ :param max_items: Maximum number of returned matches. NOTE: The maximum
+ may be restricted by the unit, presumably due to transfer
+ size consideration, so check the returned number against the
+ requested.
+ :param full_album_art_uri: If the album art URI should include the
+ IP address
+ :returns: A dictionary with metadata for the search, with the
+ keys 'number_returned', 'update_id', 'total_matches' and an
+ 'item_list' list with the search results.
+ """
+ search = self.SEARCH_TRANSLATION[search_type]
+
+ # Check if the string ID already has the type, if so we do not want to
+ # add one
+ if idstring.startswith(search):
+ search = ""
+
+ search_uri = "#{0}{1}".format(search, idstring)
+
+ search_item = MusicLibraryItem(uri=search_uri, title='', parent_id='')
+
+ # Call the base version
+ return self.browse(search_item, start, max_items, full_album_art_uri)
def _music_lib_search(self, search, start, max_items):
"""Perform a music library search and extract search numbers
@@ -1500,6 +1589,77 @@ class SoCo(_SocoSingletonBase):
return result
+ def _update_album_art_to_full_uri(self, item):
+ """Updated the Album Art URI to be fully qualified
+
+ :param item: The item to update the URI for
+ """
+ if not getattr(item, 'album_art_uri', False):
+ return
+
+ # Add on the full album art link, as the URI version
+ # does not include the ipaddress
+ if not item.album_art_uri.startswith(('http:', 'https:')):
+ item.album_art_uri = 'http://' + self.ip_address + ':1400' +\
+ item.album_art_uri
+
+ def create_sonos_playlist(self, title):
+ """ Create a new Sonos' playlist .
+
+ :params title: Name of the playlist
+
+ :returns: An instance of
+ :py:class:`~.soco.data_structures.MLSonosPlaylist`
+
+ """
+ response = self.avTransport.CreateSavedQueue([
+ ('InstanceID', 0),
+ ('Title', title),
+ ('EnqueuedURI', ''),
+ ('EnqueuedURIMetaData', ''),
+ ])
+
+ obj_id = response['AssignedObjectID'].split(':', 2)[1]
+ uri = "file:///jffs/settings/savedqueues.rsq#{0}".format(obj_id)
+
+ return MLSonosPlaylist(uri, title, 'SQ:')
+
+ def add_item_to_sonos_playlist(self, queueable_item, sonos_playlist):
+ """ Adds a queueable item to a Sonos' playlist
+ :param queueable_item: the item to add to the Sonos' playlist
+ :param sonos_playlist: the Sonos' playlist to which the item should
+ be added
+
+ """
+ # Check if the required attributes are there
+ for attribute in ['didl_metadata', 'uri']:
+ if not hasattr(queueable_item, attribute):
+ message = 'queueable_item has no attribute {0}'.\
+ format(attribute)
+ raise AttributeError(message)
+ # Get the metadata
+ try:
+ metadata = XML.tostring(queueable_item.didl_metadata)
+ except CannotCreateDIDLMetadata as exception:
+ message = ('The queueable item could not be enqueued, because it '
+ 'raised a CannotCreateDIDLMetadata exception with the '
+ 'following message:\n{0}').format(str(exception))
+ raise ValueError(message)
+ if isinstance(metadata, str):
+ metadata = metadata.encode('utf-8')
+
+ response, _ = self._music_lib_search(sonos_playlist.item_id, 0, 1)
+ update_id = response['UpdateID']
+ self.avTransport.AddURIToSavedQueue([
+ ('InstanceID', 0),
+ ('UpdateID', update_id),
+ ('ObjectID', sonos_playlist.item_id),
+ ('EnqueuedURI', queueable_item.uri),
+ ('EnqueuedURIMetaData', metadata),
+ ('AddAtIndex', 4294967295) # this field has always this value, we
+ # do not known the meaning of this
+ # "magic" number.
+ ])
# definition section
diff --git a/script.sonos/resources/lib/soco/data_structures.py
b/script.sonos/resources/lib/soco/data_structures.py
index 9291c22..26d6bc7 100644
--- a/script.sonos/resources/lib/soco/data_structures.py
+++ b/script.sonos/resources/lib/soco/data_structures.py
@@ -7,7 +7,11 @@ such as music tracks or genres
"""
-from __future__ import unicode_literals
+from __future__ import unicode_literals, print_function
+
+import warnings
+warnings.simplefilter('always', DeprecationWarning)
+import textwrap
from .xml import XML
from .exceptions import CannotCreateDIDLMetadata
@@ -539,6 +543,12 @@ class MLSonosPlaylist(MusicLibraryItem):
item_class = 'object.container.playlistContainer'
+ @property
+ def item_id(self): # pylint: disable=C0103
+ """Returns the id."""
+ out = 'SQ:' + super(MLSonosPlaylist, self).item_id
+ return out
+
class MLShare(MusicLibraryItem):
"""Class that represents a music library share.
@@ -1300,6 +1310,104 @@ class MSCollection(MusicServiceItem):
super(MSCollection, self).__init__(**content)
+###############################################################################
+# CONTAINERS #
+###############################################################################
+class ListOfMusicInfoItems(list):
+ """Abstract container class for a list of music information items"""
+
+ def __init__(self, items, number_returned, total_matches, update_id):
+ super(ListOfMusicInfoItems, self).__init__(items)
+ self._metadata = {
+ 'item_list': list(items),
+ 'number_returned': number_returned,
+ 'total_matches': total_matches,
+ 'update_id': update_id,
+ }
+
+ def __getitem__(self, key):
+ """Legacy get metadata by string key or list item(s) by index
+
+ DEPRECATION: This overriding form of __getitem__ will be removed in
+ the 3rd release after 0.8. The metadata can be fetched via the named
+ attributes
+ """
+ if key in self._metadata:
+ if key == 'item_list':
+ message = """
+ Calling [\'item_list\'] on search results to obtain the objects
+ is no longer necessary, since the object returned from searches
+ now is a list. This deprecated way of getting the items will
+ be removed from the third release after 0.8."""
+ else:
+ message = """
+ Getting metadata items by indexing the search result like a
+ dictionary [\'{0}\'] is deprecated. Please use the named
+ attribute {1}.{0} instead. The deprecated way of retrieving the
+ metadata will be removed from the third release after
+ 0.8""".format(key, self.__class__.__name__)
+ message = textwrap.dedent(message).replace('\n', ' ').lstrip()
+ warnings.warn(message, DeprecationWarning, stacklevel=2)
+ return self._metadata[key]
+ else:
+ return super(ListOfMusicInfoItems, self).__getitem__(key)
+
+ @property
+ def number_returned(self):
+ """The number of returned matches"""
+ return self._metadata['number_returned']
+
+ @property
+ def total_matches(self):
+ """The number of total matches"""
+ return self._metadata['total_matches']
+
+ @property
+ def update_id(self):
+ """The update ID"""
+ return self._metadata['update_id']
+
+
+class SearchResult(ListOfMusicInfoItems):
+ """Container class that represents a search or browse result
+
+ (browse is just a special case of search)
+ """
+
+ def __init__(self, items, search_type, number_returned,
+ total_matches, update_id):
+ super(SearchResult, self).__init__(
+ items, number_returned, total_matches, update_id
+ )
+ self._metadata['search_type'] = search_type
+
+ def __repr__(self):
+ return '{0}(items={1}, search_type=\'{2}\')'.format(
+ self.__class__.__name__,
+ super(SearchResult, self).__repr__(),
+ self.search_type)
+
+ @property
+ def search_type(self):
+ """The search type"""
+ return self._metadata['search_type']
+
+
+class Queue(ListOfMusicInfoItems):
+ """Container class that represents a queue"""
+
+ def __init__(self, items, number_returned, total_matches, update_id):
+ super(Queue, self).__init__(
+ items, number_returned, total_matches, update_id
+ )
+
+ def __repr__(self):
+ return '{0}(items={1})'.format(
+ self.__class__.__name__,
+ super(Queue, self).__repr__(),
+ )
+
+
DIDL_CLASS_TO_CLASS = {'object.item.audioItem.musicTrack': MLTrack,
'object.container.album.musicAlbum': MLAlbum,
'object.container.person.musicArtist': MLArtist,
diff --git a/script.sonos/resources/lib/soco/event_structures.py
b/script.sonos/resources/lib/soco/event_structures.py
index 345895e..ff340cd 100644
--- a/script.sonos/resources/lib/soco/event_structures.py
+++ b/script.sonos/resources/lib/soco/event_structures.py
@@ -161,6 +161,9 @@ class LastChangeEvent(object):
result['transportTitle'] = LastChangeEvent._get_element_data(
nsdc, item, 'title')
+ result['restartPending'] = LastChangeEvent._get_val_data(
+ rns, instanceid, 'RestartPending')
+
return cls(result)
@staticmethod
@@ -313,3 +316,8 @@ class LastChangeEvent(object):
def transport_title(self):
"""Get the transport title"""
return self.content.get('transportTitle', None)
+
+ @property
+ def restart_pending(self):
+ """Get the restart pending"""
+ return self.content.get('restartPending', None)
diff --git a/script.sonos/resources/lib/soco/events.py
b/script.sonos/resources/lib/soco/events.py
index 716f723..2c1b678 100644
--- a/script.sonos/resources/lib/soco/events.py
+++ b/script.sonos/resources/lib/soco/events.py
@@ -235,6 +235,7 @@ class Subscription(object):
"""
def __init__(self, interval, stop_flag, sub, *args, **kwargs):
+ # pylint: disable=bad-super-call
super(AutoRenewThread, self).__init__(*args, **kwargs)
self.interval = interval
self.sub = sub
diff --git a/script.sonos/resources/lib/soco/services.py
b/script.sonos/resources/lib/soco/services.py
index bd022bc..0465e78 100644
--- a/script.sonos/resources/lib/soco/services.py
+++ b/script.sonos/resources/lib/soco/services.py
@@ -196,6 +196,7 @@ class Service(object):
tags = []
for name, value in args:
+ # pylint: disable=bad-format-string
tag = "<{name}>{value}</{name}>".format(
name=name, value=escape("%s" % value, {'"': """}))
# % converts to unicode because we are using unicode literals.
@@ -282,6 +283,7 @@ class Service(object):
# </s:Envelope>
arguments = self.wrap_arguments(args)
+ # pylint: disable=bad-format-string
body = self.soap_body_template.format(
arguments=arguments, action=action, service_type=self.service_type,
version=self.version)
diff --git a/script.sonos/resources/lib/sonos.py
b/script.sonos/resources/lib/sonos.py
index 5d2cb65..58be529 100644
--- a/script.sonos/resources/lib/sonos.py
+++ b/script.sonos/resources/lib/sonos.py
@@ -1,12 +1,10 @@
# -*- coding: utf-8 -*-
-import cgi
import traceback
import logging
# Load the Soco classes
from soco import SoCo
from soco.event_structures import LastChangeEvent
-from soco.data_structures import MusicLibraryItem
# Use the SoCo logger
LOGGER = logging.getLogger('soco')
@@ -16,79 +14,6 @@ LOGGER = logging.getLogger('soco')
# Sonos class to add extra support on top of SoCo
#########################################################################
class Sonos(SoCo):
- # Format of the meta data (borrowed from sample code)
- meta_template = '<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/"
xmlns:r="urn:schemas-rinconnetworks-com:metadata-1-0/"
xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"><item id="R:0/0/0"
parentID="R:0/0"
restricted="true"><dc:title>{title}</dc:title><upnp:class>object.item.audioItem.audioBroadcast</upnp:class><desc
id="cdudn"
nameSpace="urn:schemas-rinconnetworks-com:metadata-1-0/">{service}</desc></item></DIDL-Lite>'
- tunein_service = 'SA_RINCON65031_'
-
- # Converts non complete URIs to complete URIs with IP address
- def _updateAlbumArtToFullUri(self, musicInfo):
- if hasattr(musicInfo, 'album_art_uri'):
- # Add on the full album art link, as the URI version does not
include the ipaddress
- if (musicInfo.album_art_uri is not None) and
(musicInfo.album_art_uri != ""):
- if not musicInfo.album_art_uri.startswith(('http:', 'https:')):
- musicInfo.album_art_uri = 'http://' + self.ip_address +
':1400' + musicInfo.album_art_uri
-
- # Override method so that the album art http reference can be added
- def get_music_library_information(self, search_type, start=0,
max_items=100, sub_category=''):
- # Call the normal view if not browsing deeper
- if (sub_category is None) or (sub_category == ''):
- musicInfo = SoCo.get_music_library_information(self, search_type,
start, max_items)
- else:
- # Call the browse version
- musicInfo = self.browse(search_type, sub_category, start,
max_items)
-
- if musicInfo is not None:
- for anItem in musicInfo['item_list']:
- # Make sure the album art URI is the full path
- self._updateAlbumArtToFullUri(anItem)
-
- return musicInfo
-
- def browse(self, search_type, sub_category, start=0, max_items=100):
- # Make sure the sub category is valid for the message, escape invalid
characters
- sub_category = cgi.escape(sub_category)
-
- search_translation = {'artists': 'A:ARTIST',
- 'album_artists': 'A:ALBUMARTIST',
- 'albums': 'A:ALBUM',
- 'genres': 'A:GENRE',
- 'composers': 'A:COMPOSER',
- 'tracks': 'A:TRACKS',
- 'playlists': 'A:PLAYLISTS',
- 'share': 'S:',
- 'sonos_playlists': 'SQ:',
- 'categories': 'A:'}
- search = search_translation[search_type]
-
- search_uri = "#%s%s" % (search, sub_category)
- search_item = MusicLibraryItem(uri=search_uri, title='', parent_id='')
-
- # Call the base version
- return SoCo.browse(self, search_item, start, max_items)
-
- # Override method so that the album art http reference can be added
- def get_queue(self, start=0, max_items=100):
- list = SoCo.get_queue(self, start=start, max_items=max_items)
-
- if list is not None:
- for anItem in list:
- # Make sure the album art URI is the full path
- self._updateAlbumArtToFullUri(anItem)
-
- return list
-
- # For radio playing a title is required
- def play_uri(self, uri='', title=None, metadata=''):
- # Radio stations need to have at least a title to play
- if (metadata == '') and (title is not None):
- title_esc = cgi.escape(title)
- metadata = Sonos.meta_template.format(title=title_esc,
service=Sonos.tunein_service)
-
- # Need to replace any special characters in the URI
- uri = cgi.escape(uri)
- # Now play the track
- SoCo.play_uri(self, uri, metadata)
-
# Reads the current Random and repeat status
def getPlayMode(self):
isRandom = False
diff --git a/script.sonos/resources/settings.xml
b/script.sonos/resources/settings.xml
index 87aafb4..3f3f8d9 100644
--- a/script.sonos/resources/settings.xml
+++ b/script.sonos/resources/settings.xml
@@ -25,7 +25,7 @@
<setting id="autoResumeSonos" subsetting="true"
enable="eq(-1,true)" label="32027" type="slider" default="0" range="0,3,60"
option="int"/>
</category>
<category label="32018">
- <setting id="batchSize" label="32019" type="slider"
default="100" range="10,10,1000" option="int"/>
+ <setting id="batchSize" label="32019" type="slider"
default="100" range="10,10,486" option="int"/>
<setting id="maxListEntries" label="32020" type="slider"
default="1000" range="0,100,3000" option="int"/>
<setting id="useSkinIcons" type="bool" label="32038"
default="false"/>
</category>
-----------------------------------------------------------------------
Summary of changes:
script.sonos/addon.xml | 2 +-
script.sonos/changelog.txt | 3 +
script.sonos/plugin.py | 114 +++++++-
.../resources/language/Belarusian/strings.po | 4 +
script.sonos/resources/language/Burmese/strings.po | 8 +
script.sonos/resources/language/Catalan/strings.po | 4 +
.../resources/language/Chinese (Simple)/strings.po | 4 +
.../language/Chinese (Traditional)/strings.po | 4 +
script.sonos/resources/language/Czech/strings.po | 4 +
script.sonos/resources/language/Danish/strings.po | 4 +
script.sonos/resources/language/Dutch/strings.po | 48 +++
.../language/English (Australia)/strings.po | 4 +
.../language/English (New Zealand)/strings.po | 4 +
.../resources/language/English (US)/strings.po | 48 +++
script.sonos/resources/language/English/strings.po | 59 ++++-
.../resources/language/Estonian/strings.po | 4 +
script.sonos/resources/language/Finnish/strings.po | 4 +
.../resources/language/French (Canada)/strings.po | 48 +++
script.sonos/resources/language/French/strings.po | 4 +
.../resources/language/Galician/strings.po | 4 +
script.sonos/resources/language/German/strings.po | 50 +++-
script.sonos/resources/language/Greek/strings.po | 48 +++
.../resources/language/Hungarian/strings.po | 4 +
.../resources/language/Icelandic/strings.po | 4 +
script.sonos/resources/language/Italian/strings.po | 4 +
script.sonos/resources/language/Korean/strings.po | 4 +
.../resources/language/Lithuanian/strings.po | 48 +++
script.sonos/resources/language/Malay/strings.po | 4 +
.../resources/language/Norwegian/strings.po | 4 +
script.sonos/resources/language/Polish/strings.po | 4 +
.../language/Portuguese (Brazil)/strings.po | 48 +++
.../resources/language/Portuguese/strings.po | 4 +
script.sonos/resources/language/Russian/strings.po | 4 +
script.sonos/resources/language/Slovak/strings.po | 4 +
.../resources/language/Spanish (Mexico)/strings.po | 4 +
script.sonos/resources/language/Spanish/strings.po | 4 +
script.sonos/resources/language/Swedish/strings.po | 48 +++
script.sonos/resources/language/Thai/strings.po | 4 +
.../language/Vietnamese (Viet Nam)/strings.po | 12 +-
script.sonos/resources/lib/settings.py | 17 +
script.sonos/resources/lib/soco/__init__.py | 2 +-
script.sonos/resources/lib/soco/core.py | 298 ++++++++++++++-----
script.sonos/resources/lib/soco/data_structures.py | 110 +++++++-
.../resources/lib/soco/event_structures.py | 8 +
script.sonos/resources/lib/soco/events.py | 1 +
script.sonos/resources/lib/soco/services.py | 2 +
script.sonos/resources/lib/soco/snapshot.py | 172 +++++++++++
script.sonos/resources/lib/sonos.py | 75 -----
script.sonos/resources/lib/speech.py | 323 ++++++++++++++++++++
script.sonos/resources/settings.xml | 2 +-
50 files changed, 1528 insertions(+), 166 deletions(-)
create mode 100644 script.sonos/resources/lib/soco/snapshot.py
create mode 100644 script.sonos/resources/lib/speech.py
hooks/post-receive
--
Scripts
------------------------------------------------------------------------------
Slashdot TV. Video for Nerds. Stuff that Matters.
http://pubads.g.doubleclick.net/gampad/clk?id=160591471&iu=/4140/ostg.clktrk
_______________________________________________
Xbmc-addons mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/xbmc-addons