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 "Bà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, {'"': "&quot;"}))
             # % 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

Reply via email to