diff --git a/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/SonosAudioSink.java b/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/SonosAudioSink.java
index 93146411ffe..1d9abbfc4fa 100644
--- a/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/SonosAudioSink.java
+++ b/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/SonosAudioSink.java
@@ -22,7 +22,6 @@ import org.eclipse.jdt.annotation.Nullable;
import org.openhab.binding.sonos.internal.handler.ZonePlayerHandler;
import org.openhab.core.audio.AudioFormat;
import org.openhab.core.audio.AudioHTTPServer;
-import org.openhab.core.audio.AudioSink;
import org.openhab.core.audio.AudioSinkSync;
import org.openhab.core.audio.AudioStream;
import org.openhab.core.audio.FileAudioStream;
@@ -39,7 +38,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
- * This makes a Sonos speaker to serve as an {@link AudioSink}-
+ * This makes a Sonos speaker to serve as an {@link org.openhab.core.audio.AudioSink}-
*
* @author Kai Kreuzer - Initial contribution and API
* @author Christoph Weitkamp - Added getSupportedStreams() and UnsupportedAudioStreamException
diff --git a/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/SonosXMLParser.java b/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/SonosXMLParser.java
index a4bdef75c8b..d1939f0987b 100644
--- a/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/SonosXMLParser.java
+++ b/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/SonosXMLParser.java
@@ -25,6 +25,10 @@ import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.util.StringUtils;
@@ -33,9 +37,7 @@ import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
-import org.xml.sax.helpers.XMLReaderFactory;
/**
* The {@link SonosXMLParser} is a class of helper functions
@@ -48,15 +50,18 @@ public class SonosXMLParser {
static final Logger LOGGER = LoggerFactory.getLogger(SonosXMLParser.class);
- private static final MessageFormat METADATA_FORMAT = new MessageFormat(
- ""
- + "- " + "{2}"
- + "{3}"
- + "" + "{4}"
- + "
");
+ private static final String METADATA_FORMAT_PATTERN = """
+ \
+ - \
+ {2}\
+ {3}\
+ {4}\
+
\
+ \
+ """;
private enum Element {
TITLE,
@@ -90,13 +95,11 @@ public class SonosXMLParser {
public static List getAlarmsFromStringResult(String xml) {
AlarmHandler handler = new AlarmHandler();
try {
- XMLReader reader = XMLReaderFactory.createXMLReader();
- reader.setContentHandler(handler);
- reader.parse(new InputSource(new StringReader(xml)));
- } catch (IOException e) {
- LOGGER.error("Could not parse Alarms from string '{}'", xml);
- } catch (SAXException s) {
- LOGGER.error("Could not parse Alarms from string '{}'", xml);
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ SAXParser saxParser = factory.newSAXParser();
+ saxParser.parse(new InputSource(new StringReader(xml)), handler);
+ } catch (IOException | SAXException | ParserConfigurationException e) {
+ LOGGER.warn("Could not parse Alarms from string '{}'", xml);
}
return handler.getAlarms();
}
@@ -108,13 +111,11 @@ public class SonosXMLParser {
public static List getEntriesFromString(String xml) {
EntryHandler handler = new EntryHandler();
try {
- XMLReader reader = XMLReaderFactory.createXMLReader();
- reader.setContentHandler(handler);
- reader.parse(new InputSource(new StringReader(xml)));
- } catch (IOException e) {
- LOGGER.error("Could not parse Entries from string '{}'", xml);
- } catch (SAXException s) {
- LOGGER.error("Could not parse Entries from string '{}'", xml);
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ SAXParser saxParser = factory.newSAXParser();
+ saxParser.parse(new InputSource(new StringReader(xml)), handler);
+ } catch (IOException | SAXException | ParserConfigurationException e) {
+ LOGGER.warn("Could not parse Entries from string '{}'", xml);
}
return handler.getArtists();
@@ -127,18 +128,18 @@ public class SonosXMLParser {
* @param xml
* @return The value of the desc xml tag
* @throws SAXException
+ * @throws ParserConfigurationException
*/
- public static @Nullable SonosResourceMetaData getResourceMetaData(String xml) throws SAXException {
- XMLReader reader = XMLReaderFactory.createXMLReader();
- reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+ public static @Nullable SonosResourceMetaData getResourceMetaData(String xml)
+ throws SAXException, ParserConfigurationException {
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+ SAXParser saxParser = factory.newSAXParser();
ResourceMetaDataHandler handler = new ResourceMetaDataHandler();
- reader.setContentHandler(handler);
try {
- reader.parse(new InputSource(new StringReader(xml)));
- } catch (IOException e) {
- LOGGER.error("Could not parse Resource MetaData from String '{}'", xml);
- } catch (SAXException s) {
- LOGGER.error("Could not parse Resource MetaData from string '{}'", xml);
+ saxParser.parse(new InputSource(new StringReader(xml)), handler);
+ } catch (IOException | SAXException e) {
+ LOGGER.warn("Could not parse Resource MetaData from string '{}'", xml);
}
return handler.getMetaData();
}
@@ -150,14 +151,11 @@ public class SonosXMLParser {
public static List getZoneGroupFromXML(String xml) {
ZoneGroupHandler handler = new ZoneGroupHandler();
try {
- XMLReader reader = XMLReaderFactory.createXMLReader();
- reader.setContentHandler(handler);
- reader.parse(new InputSource(new StringReader(xml)));
- } catch (IOException e) {
- // This should never happen - we're not performing I/O!
- LOGGER.error("Could not parse ZoneGroup from string '{}'", xml);
- } catch (SAXException s) {
- LOGGER.error("Could not parse ZoneGroup from string '{}'", xml);
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ SAXParser saxParser = factory.newSAXParser();
+ saxParser.parse(new InputSource(new StringReader(xml)), handler);
+ } catch (IOException | SAXException | ParserConfigurationException e) {
+ LOGGER.warn("Could not parse ZoneGroup from string '{}'", xml);
}
return handler.getGroups();
@@ -166,14 +164,11 @@ public class SonosXMLParser {
public static List getRadioTimeFromXML(String xml) {
OpmlHandler handler = new OpmlHandler();
try {
- XMLReader reader = XMLReaderFactory.createXMLReader();
- reader.setContentHandler(handler);
- reader.parse(new InputSource(new StringReader(xml)));
- } catch (IOException e) {
- // This should never happen - we're not performing I/O!
- LOGGER.error("Could not parse RadioTime from string '{}'", xml);
- } catch (SAXException s) {
- LOGGER.error("Could not parse RadioTime from string '{}'", xml);
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ SAXParser saxParser = factory.newSAXParser();
+ saxParser.parse(new InputSource(new StringReader(xml)), handler);
+ } catch (IOException | SAXException | ParserConfigurationException e) {
+ LOGGER.warn("Could not parse RadioTime from string '{}'", xml);
}
return handler.getTextFields();
@@ -182,14 +177,11 @@ public class SonosXMLParser {
public static Map getRenderingControlFromXML(String xml) {
RenderingControlEventHandler handler = new RenderingControlEventHandler();
try {
- XMLReader reader = XMLReaderFactory.createXMLReader();
- reader.setContentHandler(handler);
- reader.parse(new InputSource(new StringReader(xml)));
- } catch (IOException e) {
- // This should never happen - we're not performing I/O!
- LOGGER.error("Could not parse Rendering Control from string '{}'", xml);
- } catch (SAXException s) {
- LOGGER.error("Could not parse Rendering Control from string '{}'", xml);
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ SAXParser saxParser = factory.newSAXParser();
+ saxParser.parse(new InputSource(new StringReader(xml)), handler);
+ } catch (IOException | SAXException | ParserConfigurationException e) {
+ LOGGER.warn("Could not parse Rendering Control from string '{}'", xml);
}
return handler.getChanges();
}
@@ -197,14 +189,11 @@ public class SonosXMLParser {
public static Map getAVTransportFromXML(String xml) {
AVTransportEventHandler handler = new AVTransportEventHandler();
try {
- XMLReader reader = XMLReaderFactory.createXMLReader();
- reader.setContentHandler(handler);
- reader.parse(new InputSource(new StringReader(xml)));
- } catch (IOException e) {
- // This should never happen - we're not performing I/O!
- LOGGER.error("Could not parse AV Transport from string '{}'", xml);
- } catch (SAXException s) {
- LOGGER.error("Could not parse AV Transport from string '{}'", xml);
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ SAXParser saxParser = factory.newSAXParser();
+ saxParser.parse(new InputSource(new StringReader(xml)), handler);
+ } catch (IOException | SAXException | ParserConfigurationException e) {
+ LOGGER.warn("Could not parse AV Transport from string '{}'", xml);
}
return handler.getChanges();
}
@@ -212,14 +201,11 @@ public class SonosXMLParser {
public static SonosMetaData getMetaDataFromXML(String xml) {
MetaDataHandler handler = new MetaDataHandler();
try {
- XMLReader reader = XMLReaderFactory.createXMLReader();
- reader.setContentHandler(handler);
- reader.parse(new InputSource(new StringReader(xml)));
- } catch (IOException e) {
- // This should never happen - we're not performing I/O!
- LOGGER.error("Could not parse MetaData from string '{}'", xml);
- } catch (SAXException s) {
- LOGGER.error("Could not parse MetaData from string '{}'", xml);
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ SAXParser saxParser = factory.newSAXParser();
+ saxParser.parse(new InputSource(new StringReader(xml)), handler);
+ } catch (IOException | SAXException | ParserConfigurationException e) {
+ LOGGER.warn("Could not parse MetaData from string '{}'", xml);
}
return handler.getMetaData();
@@ -228,14 +214,11 @@ public class SonosXMLParser {
public static List getMusicServicesFromXML(String xml) {
MusicServiceHandler handler = new MusicServiceHandler();
try {
- XMLReader reader = XMLReaderFactory.createXMLReader();
- reader.setContentHandler(handler);
- reader.parse(new InputSource(new StringReader(xml)));
- } catch (IOException e) {
- // This should never happen - we're not performing I/O!
- LOGGER.error("Could not parse music services from string '{}'", xml);
- } catch (SAXException s) {
- LOGGER.error("Could not parse music services from string '{}'", xml);
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ SAXParser saxParser = factory.newSAXParser();
+ saxParser.parse(new InputSource(new StringReader(xml)), handler);
+ } catch (IOException | SAXException | ParserConfigurationException e) {
+ LOGGER.warn("Could not parse music services from string '{}'", xml);
}
return handler.getServices();
}
@@ -305,14 +288,14 @@ public class SonosXMLParser {
if (curIgnore == null) {
curIgnore = new ArrayList<>();
curIgnore.add("DIDL-Lite");
- curIgnore.add("type");
- curIgnore.add("ordinal");
- curIgnore.add("description");
+ curIgnore.add("r:type");
+ curIgnore.add("r:ordinal");
+ curIgnore.add("r:description");
ignore = curIgnore;
}
- if (!curIgnore.contains(localName)) {
- LOGGER.debug("Did not recognise element named {}", localName);
+ if (!curIgnore.contains(qName)) {
+ LOGGER.debug("Did not recognise element named {}", qName);
}
element = null;
break;
@@ -373,7 +356,7 @@ public class SonosXMLParser {
if (!desc.toString().isEmpty()) {
try {
md = getResourceMetaData(desc.toString());
- } catch (SAXException ignore) {
+ } catch (SAXException | ParserConfigurationException ignore) {
LOGGER.debug("Failed to parse embeded", ignore);
}
}
@@ -715,13 +698,14 @@ public class SonosXMLParser {
* The events are all of the form so we can get all
* the info we need from here.
*/
- if (localName == null) {
- // this means that localName isn't defined in EventType, which is expected for some elements
- LOGGER.info("{} is not defined in EventType. ", localName);
+ if (qName == null) {
+ // this means that qName isn't defined in EventType, which is expected for some elements
+ LOGGER.info("{} is not defined in EventType. ", qName);
} else {
String val = attributes == null ? null : attributes.getValue("val");
if (val != null) {
- changes.put(localName, val);
+ String key = qName.contains(":") ? qName.split(":")[1] : qName;
+ changes.put(key, val);
}
}
}
@@ -749,7 +733,7 @@ public class SonosXMLParser {
@Override
public void startElement(@Nullable String uri, @Nullable String localName, @Nullable String qName,
@Nullable Attributes attributes) throws SAXException {
- String name = localName == null ? "" : localName;
+ String name = qName == null ? "" : qName;
switch (name) {
case "item":
currentElement = CurrentElement.item;
@@ -761,25 +745,25 @@ public class SonosXMLParser {
case "res":
currentElement = CurrentElement.res;
break;
- case "streamContent":
+ case "r:streamContent":
currentElement = CurrentElement.streamContent;
break;
- case "albumArtURI":
+ case "upnp:albumArtURI":
currentElement = CurrentElement.albumArtURI;
break;
- case "title":
+ case "dc:title":
currentElement = CurrentElement.title;
break;
- case "class":
+ case "upnp:class":
currentElement = CurrentElement.upnpClass;
break;
- case "creator":
+ case "dc:creator":
currentElement = CurrentElement.creator;
break;
- case "album":
+ case "upnp:album":
currentElement = CurrentElement.album;
break;
- case "albumArtist":
+ case "r:albumArtist":
currentElement = CurrentElement.albumArtist;
break;
default:
@@ -928,15 +912,16 @@ public class SonosXMLParser {
}
}
- public static @Nullable String getRoomName(String descriptorXML) {
+ public static @Nullable String getRoomName(URL descriptorURL) {
RoomNameHandler roomNameHandler = new RoomNameHandler();
try {
- XMLReader reader = XMLReaderFactory.createXMLReader();
- reader.setContentHandler(roomNameHandler);
- URL url = new URL(descriptorXML);
- reader.parse(new InputSource(url.openStream()));
- } catch (IOException | SAXException e) {
- LOGGER.error("Could not parse Sonos room name from string '{}'", descriptorXML);
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ SAXParser saxParser = factory.newSAXParser();
+ saxParser.parse(new InputSource(descriptorURL.openStream()), roomNameHandler);
+ } catch (SAXException | ParserConfigurationException e) {
+ LOGGER.warn("Could not parse Sonos room name from URL '{}'", descriptorURL);
+ } catch (IOException e) {
+ LOGGER.debug("Could not fetch descriptor XML from URL '{}': {}", descriptorURL, e.getMessage());
}
return roomNameHandler.getRoomName();
}
@@ -949,7 +934,7 @@ public class SonosXMLParser {
@Override
public void startElement(@Nullable String uri, @Nullable String localName, @Nullable String qName,
@Nullable Attributes attributes) throws SAXException {
- if ("roomName".equalsIgnoreCase(localName)) {
+ if ("roomName".equalsIgnoreCase(qName)) {
roomNameTag = true;
}
}
@@ -970,12 +955,13 @@ public class SonosXMLParser {
public static @Nullable String parseModelDescription(URL descriptorURL) {
ModelNameHandler modelNameHandler = new ModelNameHandler();
try {
- XMLReader reader = XMLReaderFactory.createXMLReader();
- reader.setContentHandler(modelNameHandler);
- URL url = new URL(descriptorURL.toString());
- reader.parse(new InputSource(url.openStream()));
- } catch (IOException | SAXException e) {
- LOGGER.error("Could not parse Sonos model name from string '{}'", descriptorURL.toString());
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ SAXParser saxParser = factory.newSAXParser();
+ saxParser.parse(new InputSource(descriptorURL.openStream()), modelNameHandler);
+ } catch (SAXException | ParserConfigurationException e) {
+ LOGGER.warn("Could not parse Sonos model name from URL '{}'", descriptorURL);
+ } catch (IOException e) {
+ LOGGER.debug("Could not fetch descriptor XML from URL '{}': {}", descriptorURL, e.getMessage());
}
return modelNameHandler.getModelName();
}
@@ -988,7 +974,7 @@ public class SonosXMLParser {
@Override
public void startElement(@Nullable String uri, @Nullable String localName, @Nullable String qName,
@Nullable Attributes attributes) throws SAXException {
- if ("modelName".equalsIgnoreCase(localName)) {
+ if ("modelName".equalsIgnoreCase(qName)) {
modelNameTag = true;
}
}
@@ -1079,8 +1065,6 @@ public class SonosXMLParser {
title = StringUtils.escapeXml(title);
- String metadata = METADATA_FORMAT.format(new Object[] { id, parentId, title, upnpClass, desc });
-
- return metadata;
+ return new MessageFormat(METADATA_FORMAT_PATTERN).format(new Object[] { id, parentId, title, upnpClass, desc });
}
}
diff --git a/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/discovery/ZonePlayerDiscoveryParticipant.java b/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/discovery/ZonePlayerDiscoveryParticipant.java
index 2c632d9a6e6..59fd2549e07 100644
--- a/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/discovery/ZonePlayerDiscoveryParticipant.java
+++ b/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/discovery/ZonePlayerDiscoveryParticipant.java
@@ -108,6 +108,6 @@ public class ZonePlayerDiscoveryParticipant implements UpnpDiscoveryParticipant
}
private @Nullable String getSonosRoomName(RemoteDevice device) {
- return SonosXMLParser.getRoomName(device.getIdentity().getDescriptorURL().toString());
+ return SonosXMLParser.getRoomName(device.getIdentity().getDescriptorURL());
}
}
diff --git a/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/handler/ZonePlayerHandler.java b/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/handler/ZonePlayerHandler.java
index 154a536cfe8..a6b68398c95 100644
--- a/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/handler/ZonePlayerHandler.java
+++ b/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/handler/ZonePlayerHandler.java
@@ -1689,11 +1689,12 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici
*/
protected void saveState() {
synchronized (stateLock) {
- savedState = new SonosZonePlayerState();
- String currentURI = getCurrentURI();
-
+ SonosZonePlayerState savedState = new SonosZonePlayerState();
savedState.transportState = getTransportState();
savedState.volume = getVolume();
+ this.savedState = savedState;
+
+ String currentURI = getCurrentURI();
if (currentURI != null) {
if (isPlayingStreamOrRadio(currentURI)) {
@@ -2523,7 +2524,6 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici
}
}
- @SuppressWarnings("PMD.CompareObjectsWithEquals")
public boolean publicAddress(LineInType lineInType) {
// check if sourcePlayer has a line-in connected
if ((lineInType != LineInType.DIGITAL && isAnalogLineInConnected())
@@ -2536,7 +2536,7 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici
for (String player : group.getMembers()) {
try {
ZonePlayerHandler somePlayer = getHandlerByName(player);
- if (somePlayer != this) {
+ if (!somePlayer.equals(this)) {
somePlayer.becomeStandAlonePlayer();
somePlayer.stop();
addMember(StringType.valueOf(somePlayer.getUDN()));
diff --git a/bundles/org.openhab.binding.sonos/src/test/java/org/openhab/binding/sonos/internal/SonosXMLParserTest.java b/bundles/org.openhab.binding.sonos/src/test/java/org/openhab/binding/sonos/internal/SonosXMLParserTest.java
index 61949785a2b..65857dd5a0a 100644
--- a/bundles/org.openhab.binding.sonos/src/test/java/org/openhab/binding/sonos/internal/SonosXMLParserTest.java
+++ b/bundles/org.openhab.binding.sonos/src/test/java/org/openhab/binding/sonos/internal/SonosXMLParserTest.java
@@ -79,4 +79,43 @@ public class SonosXMLParserTest {
assertEquals("Paris, France", result.get(2));
}
}
+
+ @Test
+ public void getMetaDataFromXML() throws IOException {
+ InputStream resourceStream = getClass().getResourceAsStream("/MetaData.xml");
+ assertNotNull(resourceStream);
+ final String xml = new String(resourceStream.readAllBytes(), StandardCharsets.UTF_8);
+ SonosMetaData sonosMetaData = SonosXMLParser.getMetaDataFromXML(xml);
+ assertEquals("-1", sonosMetaData.getId());
+ assertEquals("-1", sonosMetaData.getParentId());
+ assertEquals("Turn Down for What - Single", sonosMetaData.getAlbum());
+ assertEquals("DJ Snake & Lil Jon", sonosMetaData.getCreator());
+ assertEquals("Turn Down for What", sonosMetaData.getTitle());
+ assertEquals("object.item.audioItem.musicTrack", sonosMetaData.getUpnpClass());
+ assertEquals("x-sonosapi-hls-static:librarytrack%3ai.eoD8VQ5SZOB8QX7?sid=204&flags=8232&sn=9",
+ sonosMetaData.getResource());
+ assertEquals(
+ "/getaa?s=1&u=x-sonosapi-hls-static%3alibrarytrack%253ai.eoD8VQ5SZOB8QX7%3fsid%3d204%26flags%3d8232%26sn%3d9",
+ sonosMetaData.getAlbumArtUri());
+ }
+
+ @Test
+ public void compileMetadataString() {
+ SonosEntry sonosEntry = new SonosEntry("1", "Can't Buy Me Love", "0", "A Hard Day's Night", "", "",
+ "object.item.audioItem.musicTrack", "");
+ String expected = """
+ \
+ - \
+ Can't Buy Me Love\
+ object.item.audioItem.musicTrack\
+ RINCON_AssociatedZPUDN\
+
\
+ \
+ """;
+ String actual = SonosXMLParser.compileMetadataString(sonosEntry);
+ assertEquals(expected, actual);
+ }
}
diff --git a/bundles/org.openhab.binding.sonos/src/test/resources/MetaData.xml b/bundles/org.openhab.binding.sonos/src/test/resources/MetaData.xml
new file mode 100644
index 00000000000..865dbe89eea
--- /dev/null
+++ b/bundles/org.openhab.binding.sonos/src/test/resources/MetaData.xml
@@ -0,0 +1 @@
+- x-sonosapi-hls-static:librarytrack%3ai.eoD8VQ5SZOB8QX7?sid=204&flags=8232&sn=9bd:16,sr:22050,c:3,l:0,d:0/getaa?s=1&u=x-sonosapi-hls-static%3alibrarytrack%253ai.eoD8VQ5SZOB8QX7%3fsid%3d204%26flags%3d8232%26sn%3d9Turn Down for Whatobject.item.audioItem.musicTrackDJ Snake & Lil JonTurn Down for What - Single