mirror of
https://github.com/openhab/openhab-addons.git
synced 2025-01-25 14:55:55 +01:00
[sonos] Fix warnings (#15708)
* Fix warnings * Fix discovery error logging for offline devices Fixes #6793 Signed-off-by: Jacob Laursen <jacob-github@vindvejr.dk>
This commit is contained in:
parent
7516ca557d
commit
ed9fbf0731
@ -22,7 +22,6 @@ import org.eclipse.jdt.annotation.Nullable;
|
|||||||
import org.openhab.binding.sonos.internal.handler.ZonePlayerHandler;
|
import org.openhab.binding.sonos.internal.handler.ZonePlayerHandler;
|
||||||
import org.openhab.core.audio.AudioFormat;
|
import org.openhab.core.audio.AudioFormat;
|
||||||
import org.openhab.core.audio.AudioHTTPServer;
|
import org.openhab.core.audio.AudioHTTPServer;
|
||||||
import org.openhab.core.audio.AudioSink;
|
|
||||||
import org.openhab.core.audio.AudioSinkSync;
|
import org.openhab.core.audio.AudioSinkSync;
|
||||||
import org.openhab.core.audio.AudioStream;
|
import org.openhab.core.audio.AudioStream;
|
||||||
import org.openhab.core.audio.FileAudioStream;
|
import org.openhab.core.audio.FileAudioStream;
|
||||||
@ -39,7 +38,7 @@ import org.slf4j.Logger;
|
|||||||
import org.slf4j.LoggerFactory;
|
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 Kai Kreuzer - Initial contribution and API
|
||||||
* @author Christoph Weitkamp - Added getSupportedStreams() and UnsupportedAudioStreamException
|
* @author Christoph Weitkamp - Added getSupportedStreams() and UnsupportedAudioStreamException
|
||||||
|
@ -25,6 +25,10 @@ import java.util.Set;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
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.NonNullByDefault;
|
||||||
import org.eclipse.jdt.annotation.Nullable;
|
import org.eclipse.jdt.annotation.Nullable;
|
||||||
import org.openhab.core.util.StringUtils;
|
import org.openhab.core.util.StringUtils;
|
||||||
@ -33,9 +37,7 @@ import org.slf4j.LoggerFactory;
|
|||||||
import org.xml.sax.Attributes;
|
import org.xml.sax.Attributes;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
import org.xml.sax.XMLReader;
|
|
||||||
import org.xml.sax.helpers.DefaultHandler;
|
import org.xml.sax.helpers.DefaultHandler;
|
||||||
import org.xml.sax.helpers.XMLReaderFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link SonosXMLParser} is a class of helper functions
|
* The {@link SonosXMLParser} is a class of helper functions
|
||||||
@ -48,15 +50,18 @@ public class SonosXMLParser {
|
|||||||
|
|
||||||
static final Logger LOGGER = LoggerFactory.getLogger(SonosXMLParser.class);
|
static final Logger LOGGER = LoggerFactory.getLogger(SonosXMLParser.class);
|
||||||
|
|
||||||
private static final MessageFormat METADATA_FORMAT = new MessageFormat(
|
private static final String METADATA_FORMAT_PATTERN = """
|
||||||
"<DIDL-Lite xmlns:dc=\"http://purl.org/dc/elements/1.1/\" "
|
<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" \
|
||||||
+ "xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\" "
|
xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" \
|
||||||
+ "xmlns:r=\"urn:schemas-rinconnetworks-com:metadata-1-0/\" "
|
xmlns:r="urn:schemas-rinconnetworks-com:metadata-1-0/" \
|
||||||
+ "xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\">"
|
xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/">\
|
||||||
+ "<item id=\"{0}\" parentID=\"{1}\" restricted=\"true\">" + "<dc:title>{2}</dc:title>"
|
<item id="{0}" parentID="{1}" restricted="true">\
|
||||||
+ "<upnp:class>{3}</upnp:class>"
|
<dc:title>{2}</dc:title>\
|
||||||
+ "<desc id=\"cdudn\" nameSpace=\"urn:schemas-rinconnetworks-com:metadata-1-0/\">" + "{4}</desc>"
|
<upnp:class>{3}</upnp:class>\
|
||||||
+ "</item></DIDL-Lite>");
|
<desc id="cdudn" nameSpace="urn:schemas-rinconnetworks-com:metadata-1-0/">{4}</desc>\
|
||||||
|
</item>\
|
||||||
|
</DIDL-Lite>\
|
||||||
|
""";
|
||||||
|
|
||||||
private enum Element {
|
private enum Element {
|
||||||
TITLE,
|
TITLE,
|
||||||
@ -90,13 +95,11 @@ public class SonosXMLParser {
|
|||||||
public static List<SonosAlarm> getAlarmsFromStringResult(String xml) {
|
public static List<SonosAlarm> getAlarmsFromStringResult(String xml) {
|
||||||
AlarmHandler handler = new AlarmHandler();
|
AlarmHandler handler = new AlarmHandler();
|
||||||
try {
|
try {
|
||||||
XMLReader reader = XMLReaderFactory.createXMLReader();
|
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||||
reader.setContentHandler(handler);
|
SAXParser saxParser = factory.newSAXParser();
|
||||||
reader.parse(new InputSource(new StringReader(xml)));
|
saxParser.parse(new InputSource(new StringReader(xml)), handler);
|
||||||
} catch (IOException e) {
|
} catch (IOException | SAXException | ParserConfigurationException e) {
|
||||||
LOGGER.error("Could not parse Alarms from string '{}'", xml);
|
LOGGER.warn("Could not parse Alarms from string '{}'", xml);
|
||||||
} catch (SAXException s) {
|
|
||||||
LOGGER.error("Could not parse Alarms from string '{}'", xml);
|
|
||||||
}
|
}
|
||||||
return handler.getAlarms();
|
return handler.getAlarms();
|
||||||
}
|
}
|
||||||
@ -108,13 +111,11 @@ public class SonosXMLParser {
|
|||||||
public static List<SonosEntry> getEntriesFromString(String xml) {
|
public static List<SonosEntry> getEntriesFromString(String xml) {
|
||||||
EntryHandler handler = new EntryHandler();
|
EntryHandler handler = new EntryHandler();
|
||||||
try {
|
try {
|
||||||
XMLReader reader = XMLReaderFactory.createXMLReader();
|
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||||
reader.setContentHandler(handler);
|
SAXParser saxParser = factory.newSAXParser();
|
||||||
reader.parse(new InputSource(new StringReader(xml)));
|
saxParser.parse(new InputSource(new StringReader(xml)), handler);
|
||||||
} catch (IOException e) {
|
} catch (IOException | SAXException | ParserConfigurationException e) {
|
||||||
LOGGER.error("Could not parse Entries from string '{}'", xml);
|
LOGGER.warn("Could not parse Entries from string '{}'", xml);
|
||||||
} catch (SAXException s) {
|
|
||||||
LOGGER.error("Could not parse Entries from string '{}'", xml);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return handler.getArtists();
|
return handler.getArtists();
|
||||||
@ -127,18 +128,18 @@ public class SonosXMLParser {
|
|||||||
* @param xml
|
* @param xml
|
||||||
* @return The value of the desc xml tag
|
* @return The value of the desc xml tag
|
||||||
* @throws SAXException
|
* @throws SAXException
|
||||||
|
* @throws ParserConfigurationException
|
||||||
*/
|
*/
|
||||||
public static @Nullable SonosResourceMetaData getResourceMetaData(String xml) throws SAXException {
|
public static @Nullable SonosResourceMetaData getResourceMetaData(String xml)
|
||||||
XMLReader reader = XMLReaderFactory.createXMLReader();
|
throws SAXException, ParserConfigurationException {
|
||||||
reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||||
|
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||||||
|
SAXParser saxParser = factory.newSAXParser();
|
||||||
ResourceMetaDataHandler handler = new ResourceMetaDataHandler();
|
ResourceMetaDataHandler handler = new ResourceMetaDataHandler();
|
||||||
reader.setContentHandler(handler);
|
|
||||||
try {
|
try {
|
||||||
reader.parse(new InputSource(new StringReader(xml)));
|
saxParser.parse(new InputSource(new StringReader(xml)), handler);
|
||||||
} catch (IOException e) {
|
} catch (IOException | SAXException e) {
|
||||||
LOGGER.error("Could not parse Resource MetaData from String '{}'", xml);
|
LOGGER.warn("Could not parse Resource MetaData from string '{}'", xml);
|
||||||
} catch (SAXException s) {
|
|
||||||
LOGGER.error("Could not parse Resource MetaData from string '{}'", xml);
|
|
||||||
}
|
}
|
||||||
return handler.getMetaData();
|
return handler.getMetaData();
|
||||||
}
|
}
|
||||||
@ -150,14 +151,11 @@ public class SonosXMLParser {
|
|||||||
public static List<SonosZoneGroup> getZoneGroupFromXML(String xml) {
|
public static List<SonosZoneGroup> getZoneGroupFromXML(String xml) {
|
||||||
ZoneGroupHandler handler = new ZoneGroupHandler();
|
ZoneGroupHandler handler = new ZoneGroupHandler();
|
||||||
try {
|
try {
|
||||||
XMLReader reader = XMLReaderFactory.createXMLReader();
|
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||||
reader.setContentHandler(handler);
|
SAXParser saxParser = factory.newSAXParser();
|
||||||
reader.parse(new InputSource(new StringReader(xml)));
|
saxParser.parse(new InputSource(new StringReader(xml)), handler);
|
||||||
} catch (IOException e) {
|
} catch (IOException | SAXException | ParserConfigurationException e) {
|
||||||
// This should never happen - we're not performing I/O!
|
LOGGER.warn("Could not parse ZoneGroup from string '{}'", xml);
|
||||||
LOGGER.error("Could not parse ZoneGroup from string '{}'", xml);
|
|
||||||
} catch (SAXException s) {
|
|
||||||
LOGGER.error("Could not parse ZoneGroup from string '{}'", xml);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return handler.getGroups();
|
return handler.getGroups();
|
||||||
@ -166,14 +164,11 @@ public class SonosXMLParser {
|
|||||||
public static List<String> getRadioTimeFromXML(String xml) {
|
public static List<String> getRadioTimeFromXML(String xml) {
|
||||||
OpmlHandler handler = new OpmlHandler();
|
OpmlHandler handler = new OpmlHandler();
|
||||||
try {
|
try {
|
||||||
XMLReader reader = XMLReaderFactory.createXMLReader();
|
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||||
reader.setContentHandler(handler);
|
SAXParser saxParser = factory.newSAXParser();
|
||||||
reader.parse(new InputSource(new StringReader(xml)));
|
saxParser.parse(new InputSource(new StringReader(xml)), handler);
|
||||||
} catch (IOException e) {
|
} catch (IOException | SAXException | ParserConfigurationException e) {
|
||||||
// This should never happen - we're not performing I/O!
|
LOGGER.warn("Could not parse RadioTime from string '{}'", xml);
|
||||||
LOGGER.error("Could not parse RadioTime from string '{}'", xml);
|
|
||||||
} catch (SAXException s) {
|
|
||||||
LOGGER.error("Could not parse RadioTime from string '{}'", xml);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return handler.getTextFields();
|
return handler.getTextFields();
|
||||||
@ -182,14 +177,11 @@ public class SonosXMLParser {
|
|||||||
public static Map<String, String> getRenderingControlFromXML(String xml) {
|
public static Map<String, String> getRenderingControlFromXML(String xml) {
|
||||||
RenderingControlEventHandler handler = new RenderingControlEventHandler();
|
RenderingControlEventHandler handler = new RenderingControlEventHandler();
|
||||||
try {
|
try {
|
||||||
XMLReader reader = XMLReaderFactory.createXMLReader();
|
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||||
reader.setContentHandler(handler);
|
SAXParser saxParser = factory.newSAXParser();
|
||||||
reader.parse(new InputSource(new StringReader(xml)));
|
saxParser.parse(new InputSource(new StringReader(xml)), handler);
|
||||||
} catch (IOException e) {
|
} catch (IOException | SAXException | ParserConfigurationException e) {
|
||||||
// This should never happen - we're not performing I/O!
|
LOGGER.warn("Could not parse Rendering Control from string '{}'", xml);
|
||||||
LOGGER.error("Could not parse Rendering Control from string '{}'", xml);
|
|
||||||
} catch (SAXException s) {
|
|
||||||
LOGGER.error("Could not parse Rendering Control from string '{}'", xml);
|
|
||||||
}
|
}
|
||||||
return handler.getChanges();
|
return handler.getChanges();
|
||||||
}
|
}
|
||||||
@ -197,14 +189,11 @@ public class SonosXMLParser {
|
|||||||
public static Map<String, String> getAVTransportFromXML(String xml) {
|
public static Map<String, String> getAVTransportFromXML(String xml) {
|
||||||
AVTransportEventHandler handler = new AVTransportEventHandler();
|
AVTransportEventHandler handler = new AVTransportEventHandler();
|
||||||
try {
|
try {
|
||||||
XMLReader reader = XMLReaderFactory.createXMLReader();
|
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||||
reader.setContentHandler(handler);
|
SAXParser saxParser = factory.newSAXParser();
|
||||||
reader.parse(new InputSource(new StringReader(xml)));
|
saxParser.parse(new InputSource(new StringReader(xml)), handler);
|
||||||
} catch (IOException e) {
|
} catch (IOException | SAXException | ParserConfigurationException e) {
|
||||||
// This should never happen - we're not performing I/O!
|
LOGGER.warn("Could not parse AV Transport from string '{}'", xml);
|
||||||
LOGGER.error("Could not parse AV Transport from string '{}'", xml);
|
|
||||||
} catch (SAXException s) {
|
|
||||||
LOGGER.error("Could not parse AV Transport from string '{}'", xml);
|
|
||||||
}
|
}
|
||||||
return handler.getChanges();
|
return handler.getChanges();
|
||||||
}
|
}
|
||||||
@ -212,14 +201,11 @@ public class SonosXMLParser {
|
|||||||
public static SonosMetaData getMetaDataFromXML(String xml) {
|
public static SonosMetaData getMetaDataFromXML(String xml) {
|
||||||
MetaDataHandler handler = new MetaDataHandler();
|
MetaDataHandler handler = new MetaDataHandler();
|
||||||
try {
|
try {
|
||||||
XMLReader reader = XMLReaderFactory.createXMLReader();
|
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||||
reader.setContentHandler(handler);
|
SAXParser saxParser = factory.newSAXParser();
|
||||||
reader.parse(new InputSource(new StringReader(xml)));
|
saxParser.parse(new InputSource(new StringReader(xml)), handler);
|
||||||
} catch (IOException e) {
|
} catch (IOException | SAXException | ParserConfigurationException e) {
|
||||||
// This should never happen - we're not performing I/O!
|
LOGGER.warn("Could not parse MetaData from string '{}'", xml);
|
||||||
LOGGER.error("Could not parse MetaData from string '{}'", xml);
|
|
||||||
} catch (SAXException s) {
|
|
||||||
LOGGER.error("Could not parse MetaData from string '{}'", xml);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return handler.getMetaData();
|
return handler.getMetaData();
|
||||||
@ -228,14 +214,11 @@ public class SonosXMLParser {
|
|||||||
public static List<SonosMusicService> getMusicServicesFromXML(String xml) {
|
public static List<SonosMusicService> getMusicServicesFromXML(String xml) {
|
||||||
MusicServiceHandler handler = new MusicServiceHandler();
|
MusicServiceHandler handler = new MusicServiceHandler();
|
||||||
try {
|
try {
|
||||||
XMLReader reader = XMLReaderFactory.createXMLReader();
|
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||||
reader.setContentHandler(handler);
|
SAXParser saxParser = factory.newSAXParser();
|
||||||
reader.parse(new InputSource(new StringReader(xml)));
|
saxParser.parse(new InputSource(new StringReader(xml)), handler);
|
||||||
} catch (IOException e) {
|
} catch (IOException | SAXException | ParserConfigurationException e) {
|
||||||
// This should never happen - we're not performing I/O!
|
LOGGER.warn("Could not parse music services from string '{}'", xml);
|
||||||
LOGGER.error("Could not parse music services from string '{}'", xml);
|
|
||||||
} catch (SAXException s) {
|
|
||||||
LOGGER.error("Could not parse music services from string '{}'", xml);
|
|
||||||
}
|
}
|
||||||
return handler.getServices();
|
return handler.getServices();
|
||||||
}
|
}
|
||||||
@ -305,14 +288,14 @@ public class SonosXMLParser {
|
|||||||
if (curIgnore == null) {
|
if (curIgnore == null) {
|
||||||
curIgnore = new ArrayList<>();
|
curIgnore = new ArrayList<>();
|
||||||
curIgnore.add("DIDL-Lite");
|
curIgnore.add("DIDL-Lite");
|
||||||
curIgnore.add("type");
|
curIgnore.add("r:type");
|
||||||
curIgnore.add("ordinal");
|
curIgnore.add("r:ordinal");
|
||||||
curIgnore.add("description");
|
curIgnore.add("r:description");
|
||||||
ignore = curIgnore;
|
ignore = curIgnore;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!curIgnore.contains(localName)) {
|
if (!curIgnore.contains(qName)) {
|
||||||
LOGGER.debug("Did not recognise element named {}", localName);
|
LOGGER.debug("Did not recognise element named {}", qName);
|
||||||
}
|
}
|
||||||
element = null;
|
element = null;
|
||||||
break;
|
break;
|
||||||
@ -373,7 +356,7 @@ public class SonosXMLParser {
|
|||||||
if (!desc.toString().isEmpty()) {
|
if (!desc.toString().isEmpty()) {
|
||||||
try {
|
try {
|
||||||
md = getResourceMetaData(desc.toString());
|
md = getResourceMetaData(desc.toString());
|
||||||
} catch (SAXException ignore) {
|
} catch (SAXException | ParserConfigurationException ignore) {
|
||||||
LOGGER.debug("Failed to parse embeded", ignore);
|
LOGGER.debug("Failed to parse embeded", ignore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -715,13 +698,14 @@ public class SonosXMLParser {
|
|||||||
* The events are all of the form <qName val="value"/> so we can get all
|
* The events are all of the form <qName val="value"/> so we can get all
|
||||||
* the info we need from here.
|
* the info we need from here.
|
||||||
*/
|
*/
|
||||||
if (localName == null) {
|
if (qName == null) {
|
||||||
// this means that localName isn't defined in EventType, which is expected for some elements
|
// this means that qName isn't defined in EventType, which is expected for some elements
|
||||||
LOGGER.info("{} is not defined in EventType. ", localName);
|
LOGGER.info("{} is not defined in EventType. ", qName);
|
||||||
} else {
|
} else {
|
||||||
String val = attributes == null ? null : attributes.getValue("val");
|
String val = attributes == null ? null : attributes.getValue("val");
|
||||||
if (val != null) {
|
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
|
@Override
|
||||||
public void startElement(@Nullable String uri, @Nullable String localName, @Nullable String qName,
|
public void startElement(@Nullable String uri, @Nullable String localName, @Nullable String qName,
|
||||||
@Nullable Attributes attributes) throws SAXException {
|
@Nullable Attributes attributes) throws SAXException {
|
||||||
String name = localName == null ? "" : localName;
|
String name = qName == null ? "" : qName;
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case "item":
|
case "item":
|
||||||
currentElement = CurrentElement.item;
|
currentElement = CurrentElement.item;
|
||||||
@ -761,25 +745,25 @@ public class SonosXMLParser {
|
|||||||
case "res":
|
case "res":
|
||||||
currentElement = CurrentElement.res;
|
currentElement = CurrentElement.res;
|
||||||
break;
|
break;
|
||||||
case "streamContent":
|
case "r:streamContent":
|
||||||
currentElement = CurrentElement.streamContent;
|
currentElement = CurrentElement.streamContent;
|
||||||
break;
|
break;
|
||||||
case "albumArtURI":
|
case "upnp:albumArtURI":
|
||||||
currentElement = CurrentElement.albumArtURI;
|
currentElement = CurrentElement.albumArtURI;
|
||||||
break;
|
break;
|
||||||
case "title":
|
case "dc:title":
|
||||||
currentElement = CurrentElement.title;
|
currentElement = CurrentElement.title;
|
||||||
break;
|
break;
|
||||||
case "class":
|
case "upnp:class":
|
||||||
currentElement = CurrentElement.upnpClass;
|
currentElement = CurrentElement.upnpClass;
|
||||||
break;
|
break;
|
||||||
case "creator":
|
case "dc:creator":
|
||||||
currentElement = CurrentElement.creator;
|
currentElement = CurrentElement.creator;
|
||||||
break;
|
break;
|
||||||
case "album":
|
case "upnp:album":
|
||||||
currentElement = CurrentElement.album;
|
currentElement = CurrentElement.album;
|
||||||
break;
|
break;
|
||||||
case "albumArtist":
|
case "r:albumArtist":
|
||||||
currentElement = CurrentElement.albumArtist;
|
currentElement = CurrentElement.albumArtist;
|
||||||
break;
|
break;
|
||||||
default:
|
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();
|
RoomNameHandler roomNameHandler = new RoomNameHandler();
|
||||||
try {
|
try {
|
||||||
XMLReader reader = XMLReaderFactory.createXMLReader();
|
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||||
reader.setContentHandler(roomNameHandler);
|
SAXParser saxParser = factory.newSAXParser();
|
||||||
URL url = new URL(descriptorXML);
|
saxParser.parse(new InputSource(descriptorURL.openStream()), roomNameHandler);
|
||||||
reader.parse(new InputSource(url.openStream()));
|
} catch (SAXException | ParserConfigurationException e) {
|
||||||
} catch (IOException | SAXException e) {
|
LOGGER.warn("Could not parse Sonos room name from URL '{}'", descriptorURL);
|
||||||
LOGGER.error("Could not parse Sonos room name from string '{}'", descriptorXML);
|
} catch (IOException e) {
|
||||||
|
LOGGER.debug("Could not fetch descriptor XML from URL '{}': {}", descriptorURL, e.getMessage());
|
||||||
}
|
}
|
||||||
return roomNameHandler.getRoomName();
|
return roomNameHandler.getRoomName();
|
||||||
}
|
}
|
||||||
@ -949,7 +934,7 @@ public class SonosXMLParser {
|
|||||||
@Override
|
@Override
|
||||||
public void startElement(@Nullable String uri, @Nullable String localName, @Nullable String qName,
|
public void startElement(@Nullable String uri, @Nullable String localName, @Nullable String qName,
|
||||||
@Nullable Attributes attributes) throws SAXException {
|
@Nullable Attributes attributes) throws SAXException {
|
||||||
if ("roomName".equalsIgnoreCase(localName)) {
|
if ("roomName".equalsIgnoreCase(qName)) {
|
||||||
roomNameTag = true;
|
roomNameTag = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -970,12 +955,13 @@ public class SonosXMLParser {
|
|||||||
public static @Nullable String parseModelDescription(URL descriptorURL) {
|
public static @Nullable String parseModelDescription(URL descriptorURL) {
|
||||||
ModelNameHandler modelNameHandler = new ModelNameHandler();
|
ModelNameHandler modelNameHandler = new ModelNameHandler();
|
||||||
try {
|
try {
|
||||||
XMLReader reader = XMLReaderFactory.createXMLReader();
|
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||||
reader.setContentHandler(modelNameHandler);
|
SAXParser saxParser = factory.newSAXParser();
|
||||||
URL url = new URL(descriptorURL.toString());
|
saxParser.parse(new InputSource(descriptorURL.openStream()), modelNameHandler);
|
||||||
reader.parse(new InputSource(url.openStream()));
|
} catch (SAXException | ParserConfigurationException e) {
|
||||||
} catch (IOException | SAXException e) {
|
LOGGER.warn("Could not parse Sonos model name from URL '{}'", descriptorURL);
|
||||||
LOGGER.error("Could not parse Sonos model name from string '{}'", descriptorURL.toString());
|
} catch (IOException e) {
|
||||||
|
LOGGER.debug("Could not fetch descriptor XML from URL '{}': {}", descriptorURL, e.getMessage());
|
||||||
}
|
}
|
||||||
return modelNameHandler.getModelName();
|
return modelNameHandler.getModelName();
|
||||||
}
|
}
|
||||||
@ -988,7 +974,7 @@ public class SonosXMLParser {
|
|||||||
@Override
|
@Override
|
||||||
public void startElement(@Nullable String uri, @Nullable String localName, @Nullable String qName,
|
public void startElement(@Nullable String uri, @Nullable String localName, @Nullable String qName,
|
||||||
@Nullable Attributes attributes) throws SAXException {
|
@Nullable Attributes attributes) throws SAXException {
|
||||||
if ("modelName".equalsIgnoreCase(localName)) {
|
if ("modelName".equalsIgnoreCase(qName)) {
|
||||||
modelNameTag = true;
|
modelNameTag = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1079,8 +1065,6 @@ public class SonosXMLParser {
|
|||||||
|
|
||||||
title = StringUtils.escapeXml(title);
|
title = StringUtils.escapeXml(title);
|
||||||
|
|
||||||
String metadata = METADATA_FORMAT.format(new Object[] { id, parentId, title, upnpClass, desc });
|
return new MessageFormat(METADATA_FORMAT_PATTERN).format(new Object[] { id, parentId, title, upnpClass, desc });
|
||||||
|
|
||||||
return metadata;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,6 +108,6 @@ public class ZonePlayerDiscoveryParticipant implements UpnpDiscoveryParticipant
|
|||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable String getSonosRoomName(RemoteDevice device) {
|
private @Nullable String getSonosRoomName(RemoteDevice device) {
|
||||||
return SonosXMLParser.getRoomName(device.getIdentity().getDescriptorURL().toString());
|
return SonosXMLParser.getRoomName(device.getIdentity().getDescriptorURL());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1689,11 +1689,12 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici
|
|||||||
*/
|
*/
|
||||||
protected void saveState() {
|
protected void saveState() {
|
||||||
synchronized (stateLock) {
|
synchronized (stateLock) {
|
||||||
savedState = new SonosZonePlayerState();
|
SonosZonePlayerState savedState = new SonosZonePlayerState();
|
||||||
String currentURI = getCurrentURI();
|
|
||||||
|
|
||||||
savedState.transportState = getTransportState();
|
savedState.transportState = getTransportState();
|
||||||
savedState.volume = getVolume();
|
savedState.volume = getVolume();
|
||||||
|
this.savedState = savedState;
|
||||||
|
|
||||||
|
String currentURI = getCurrentURI();
|
||||||
|
|
||||||
if (currentURI != null) {
|
if (currentURI != null) {
|
||||||
if (isPlayingStreamOrRadio(currentURI)) {
|
if (isPlayingStreamOrRadio(currentURI)) {
|
||||||
@ -2523,7 +2524,6 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("PMD.CompareObjectsWithEquals")
|
|
||||||
public boolean publicAddress(LineInType lineInType) {
|
public boolean publicAddress(LineInType lineInType) {
|
||||||
// check if sourcePlayer has a line-in connected
|
// check if sourcePlayer has a line-in connected
|
||||||
if ((lineInType != LineInType.DIGITAL && isAnalogLineInConnected())
|
if ((lineInType != LineInType.DIGITAL && isAnalogLineInConnected())
|
||||||
@ -2536,7 +2536,7 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici
|
|||||||
for (String player : group.getMembers()) {
|
for (String player : group.getMembers()) {
|
||||||
try {
|
try {
|
||||||
ZonePlayerHandler somePlayer = getHandlerByName(player);
|
ZonePlayerHandler somePlayer = getHandlerByName(player);
|
||||||
if (somePlayer != this) {
|
if (!somePlayer.equals(this)) {
|
||||||
somePlayer.becomeStandAlonePlayer();
|
somePlayer.becomeStandAlonePlayer();
|
||||||
somePlayer.stop();
|
somePlayer.stop();
|
||||||
addMember(StringType.valueOf(somePlayer.getUDN()));
|
addMember(StringType.valueOf(somePlayer.getUDN()));
|
||||||
|
@ -79,4 +79,43 @@ public class SonosXMLParserTest {
|
|||||||
assertEquals("Paris, France", result.get(2));
|
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 = """
|
||||||
|
<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="1" parentID="0" restricted="true">\
|
||||||
|
<dc:title>Can't Buy Me Love</dc:title>\
|
||||||
|
<upnp:class>object.item.audioItem.musicTrack</upnp:class>\
|
||||||
|
<desc id="cdudn" nameSpace="urn:schemas-rinconnetworks-com:metadata-1-0/">RINCON_AssociatedZPUDN</desc>\
|
||||||
|
</item>\
|
||||||
|
</DIDL-Lite>\
|
||||||
|
""";
|
||||||
|
String actual = SonosXMLParser.compileMetadataString(sonosEntry);
|
||||||
|
assertEquals(expected, actual);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
<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="-1" parentID="-1" restricted="true"><res protocolInfo="sonos.com-http:*:application/x-mpegURL:*" duration="0:03:33">x-sonosapi-hls-static:librarytrack%3ai.eoD8VQ5SZOB8QX7?sid=204&flags=8232&sn=9</res><r:streamContent></r:streamContent><r:radioShowMd></r:radioShowMd><r:streamInfo>bd:16,sr:22050,c:3,l:0,d:0</r:streamInfo><upnp:albumArtURI>/getaa?s=1&u=x-sonosapi-hls-static%3alibrarytrack%253ai.eoD8VQ5SZOB8QX7%3fsid%3d204%26flags%3d8232%26sn%3d9</upnp:albumArtURI><dc:title>Turn Down for What</dc:title><upnp:class>object.item.audioItem.musicTrack</upnp:class><dc:creator>DJ Snake & Lil Jon</dc:creator><upnp:album>Turn Down for What - Single</upnp:album></item></DIDL-Lite>
|
Loading…
Reference in New Issue
Block a user