diff --git a/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/handler/SonosMediaInformation.java b/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/handler/SonosMediaInformation.java index 264e867e5..c35e8f448 100644 --- a/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/handler/SonosMediaInformation.java +++ b/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/handler/SonosMediaInformation.java @@ -12,7 +12,6 @@ */ package org.openhab.binding.sonos.internal.handler; -import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -20,9 +19,6 @@ import org.eclipse.jdt.annotation.NonNullByDefault; import org.eclipse.jdt.annotation.Nullable; import org.openhab.binding.sonos.internal.SonosMetaData; import org.openhab.binding.sonos.internal.SonosXMLParser; -import org.openhab.core.io.net.http.HttpUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * The {@link SonosMediaInformation} is responsible for extracting media information from XML metadata @@ -32,10 +28,6 @@ import org.slf4j.LoggerFactory; @NonNullByDefault public class SonosMediaInformation { - private static final int HTTP_TIMEOUT = 5000; - - private static final Logger LOGGER = LoggerFactory.getLogger(SonosMediaInformation.class); - private @Nullable String artist; private @Nullable String album; private @Nullable String title; @@ -79,34 +71,16 @@ public class SonosMediaInformation { return needsUpdate; } - public static SonosMediaInformation parseTuneInMediaInfo(@Nullable String opmlUrl, @Nullable String radioTitle, + public static SonosMediaInformation parseTuneInMediaInfo(@Nullable String opmlData, @Nullable String radioTitle, @Nullable SonosMetaData trackMetaData) { String title = null; String combinedInfo = null; - if (opmlUrl != null) { - String response = null; - try { - response = HttpUtil.executeUrl("GET", opmlUrl, HTTP_TIMEOUT); - } catch (IOException e) { - LOGGER.debug("Request to device failed", e); - } - - if (response != null) { - List fields = SonosXMLParser.getRadioTimeFromXML(response); - - if (!fields.isEmpty()) { - combinedInfo = ""; - for (String field : fields) { - if (combinedInfo.isEmpty()) { - // radio name should be first field - title = field; - } else { - combinedInfo += " - "; - } - combinedInfo += field; - } - return new SonosMediaInformation(null, null, title, combinedInfo, true); - } + if (opmlData != null) { + List fields = SonosXMLParser.getRadioTimeFromXML(opmlData); + if (!fields.isEmpty()) { + title = fields.get(0); + combinedInfo = String.join(" - ", fields); + return new SonosMediaInformation(null, null, title, combinedInfo, true); } } if (radioTitle != null && !radioTitle.isEmpty()) { 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 3b751d622..8037a8bcf 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 @@ -14,6 +14,7 @@ package org.openhab.binding.sonos.internal.handler; import static org.openhab.binding.sonos.internal.SonosBindingConstants.*; +import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.text.ParseException; @@ -164,6 +165,8 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici private static final int MIN_HEIGHT_LEVEL = -10; private static final int MAX_HEIGHT_LEVEL = 10; + private static final int HTTP_TIMEOUT = 5000; + private final Logger logger = LoggerFactory.getLogger(ZonePlayerHandler.class); private final ThingRegistry localThingRegistry; @@ -1249,7 +1252,7 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici else if (isPlayingStream(currentURI) || isPlayingRadioStartedByAmazonEcho(currentURI)) { // Radio stream (tune-in) stationID = extractStationId(currentURI); - mediaInfo = SonosMediaInformation.parseTuneInMediaInfo(buildOpmlUrl(stationID), + mediaInfo = SonosMediaInformation.parseTuneInMediaInfo(getOpmlData(stationID), currentUriMetaData != null ? currentUriMetaData.getTitle() : null, currentTrack); } @@ -1308,14 +1311,21 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici } } - private @Nullable String buildOpmlUrl(@Nullable String stationId) { + private @Nullable String getOpmlData(@Nullable String stationId) { String url = opmlUrl; if (url != null && stationId != null && !stationId.isEmpty()) { String mac = getMACAddress(); if (mac != null && !mac.isEmpty()) { url = url.replace("%id", stationId); url = url.replace("%serial", mac); - return url; + String response = null; + try { + response = HttpUtil.executeUrl("GET", url, HTTP_TIMEOUT); + } catch (IOException e) { + logger.debug("OPML request failed ({})", url, e); + } + logger.trace("OPML response = {}", response); + return response; } } return null; diff --git a/bundles/org.openhab.binding.sonos/src/test/java/org/openhab/binding/sonos/internal/SonosMediaInformationTest.java b/bundles/org.openhab.binding.sonos/src/test/java/org/openhab/binding/sonos/internal/SonosMediaInformationTest.java index a9e48681e..e13015691 100644 --- a/bundles/org.openhab.binding.sonos/src/test/java/org/openhab/binding/sonos/internal/SonosMediaInformationTest.java +++ b/bundles/org.openhab.binding.sonos/src/test/java/org/openhab/binding/sonos/internal/SonosMediaInformationTest.java @@ -14,6 +14,10 @@ package org.openhab.binding.sonos.internal; import static org.junit.jupiter.api.Assertions.*; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + import org.eclipse.jdt.annotation.NonNullByDefault; import org.junit.jupiter.api.Test; import org.openhab.binding.sonos.internal.handler.SonosMediaInformation; @@ -26,23 +30,47 @@ import org.openhab.binding.sonos.internal.handler.SonosMediaInformation; @NonNullByDefault public class SonosMediaInformationTest { + private static final SonosMetaData METADATA_STREAM_CONTENT = new SonosMetaData("yyy", "yyy", "yyy", "Morning Live", + "yyy", "yyy", "yyy", "yyy", "yyy", "yyy"); + private static final SonosMetaData METADATA_EMPTY_STREAM_CONTENT = new SonosMetaData("yyy", "yyy", "yyy", "", "yyy", + "yyy", "yyy", "yyy", "yyy", "yyy"); + + private static final SonosMetaData METADATA_RADIOAPP_1 = new SonosMetaData("yyy", "yyy", "yyy", + "TYPE=SNG|TITLE Green Day - Time Of Your Life (Good Riddance)|ARTIST |ALBUM ", "yyy", "yyy", "yyy", "yyy", + "yyy", "yyy"); + private static final SonosMetaData METADATA_RADIOAPP_2 = new SonosMetaData("yyy", "yyy", "yyy", + "TYPE=SNG|TITLE Time Of Your Life (Good Riddance)|ARTIST Green Day|ALBUM Nimrod", "yyy", "yyy", "yyy", + "yyy", "yyy", "yyy"); + private static final SonosMetaData METADATA_RADIOAPP_ADVERTISEMENT = new SonosMetaData("yyy", "yyy", "yyy", + "TYPE=SNG|TITLE Advertisement_Stop|ARTIST |ALBUM ", "yyy", "yyy", "yyy", "yyy", "yyy", "yyy"); + + private static final SonosMetaData METADATA_ARTIST_ALBUM_TITLE = new SonosMetaData("xxx", "xxx", "xxx", "xxx", + "xxx", "Time Of Your Life (Good Riddance)", "xxx", "xxx", "Nimrod", "Green Day"); + private static final SonosMetaData METADATA_EMPTY_CREATOR_ARTIST = new SonosMetaData("xxx", "xxx", "xxx", "xxx", + "xxx", "Time Of Your Life (Good Riddance)", "xxx", "", "Nimrod", ""); + private static final SonosMetaData METADATA_EMPTY_ALBUM = new SonosMetaData("xxx", "xxx", "xxx", "xxx", "xxx", + "Time Of Your Life (Good Riddance)", "xxx", "Green Day", "", ""); + private static final SonosMetaData METADATA_EMPTY_TITLE = new SonosMetaData("xxx", "xxx", "xxx", "xxx", "xxx", "", + "xxx", "xxx", "Nimrod", "Green Day"); + private static final SonosMetaData METADATA_ONLY_TITLE = new SonosMetaData("", "", "", "", "", + "Time Of Your Life (Good Riddance)", "", "", "", ""); + private static final SonosMetaData METADATA_EMPTY = new SonosMetaData("", "", "", "", "", "", "", "", "", ""); + @Test public void parseTuneInMediaInfoWithStreamContent() { - SonosMetaData trackMetaData = new SonosMetaData("yyy", "yyy", "yyy", "Mroning Live", "yyy", "yyy", "yyy", "yyy", - "yyy", "yyy"); - SonosMediaInformation result = SonosMediaInformation.parseTuneInMediaInfo(null, "Radio One", trackMetaData); + SonosMediaInformation result = SonosMediaInformation.parseTuneInMediaInfo(null, "Radio One", + METADATA_STREAM_CONTENT); assertNull(result.getArtist()); assertNull(result.getAlbum()); assertEquals("Radio One", result.getTitle()); - assertEquals("Radio One - Mroning Live", result.getCombinedInfo()); + assertEquals("Radio One - Morning Live", result.getCombinedInfo()); assertEquals(true, result.needsUpdate()); } @Test public void parseTuneInMediaInfoWithoutStreamContent() { - SonosMetaData trackMetaData = new SonosMetaData("yyy", "yyy", "yyy", "", "yyy", "yyy", "yyy", "yyy", "yyy", - "yyy"); - SonosMediaInformation result = SonosMediaInformation.parseTuneInMediaInfo(null, "Radio One", trackMetaData); + SonosMediaInformation result = SonosMediaInformation.parseTuneInMediaInfo(null, "Radio One", + METADATA_EMPTY_STREAM_CONTENT); assertNull(result.getArtist()); assertNull(result.getAlbum()); assertEquals("Radio One", result.getTitle()); @@ -52,9 +80,7 @@ public class SonosMediaInformationTest { @Test public void parseTuneInMediaInfoWithoutTitle() { - SonosMetaData trackMetaData = new SonosMetaData("yyy", "yyy", "yyy", "Mroning Live", "yyy", "yyy", "yyy", "yyy", - "yyy", "yyy"); - SonosMediaInformation result = SonosMediaInformation.parseTuneInMediaInfo(null, "", trackMetaData); + SonosMediaInformation result = SonosMediaInformation.parseTuneInMediaInfo(null, "", METADATA_STREAM_CONTENT); assertNull(result.getArtist()); assertNull(result.getAlbum()); assertNull(result.getTitle()); @@ -72,12 +98,23 @@ public class SonosMediaInformationTest { assertEquals(false, result.needsUpdate()); } + @Test + public void parseTuneInMediaInfoWithOPMLRequest() throws IOException { + InputStream resourceStream = getClass().getResourceAsStream("/OPML.xml"); + assertNotNull(resourceStream); + final String opmlResult = new String(resourceStream.readAllBytes(), StandardCharsets.UTF_8); + SonosMediaInformation result = SonosMediaInformation.parseTuneInMediaInfo(opmlResult, "Radio One", + METADATA_STREAM_CONTENT); + assertNull(result.getArtist()); + assertNull(result.getAlbum()); + assertEquals("RTL2 105.9", result.getTitle()); + assertEquals("RTL2 105.9 - Le Son Pop-Rock - Paris, France", result.getCombinedInfo()); + assertEquals(true, result.needsUpdate()); + } + @Test public void parseRadioAppMediaInfoWithSongTitle() { - SonosMetaData trackMetaData = new SonosMetaData("yyy", "yyy", "yyy", - "TYPE=SNG|TITLE Green Day - Time Of Your Life (Good Riddance)|ARTIST |ALBUM ", "yyy", "yyy", "yyy", - "yyy", "yyy", "yyy"); - SonosMediaInformation result = SonosMediaInformation.parseRadioAppMediaInfo("Radio Two", trackMetaData); + SonosMediaInformation result = SonosMediaInformation.parseRadioAppMediaInfo("Radio Two", METADATA_RADIOAPP_1); assertEquals("Green Day", result.getArtist()); assertEquals("", result.getAlbum()); assertEquals("Time Of Your Life (Good Riddance)", result.getTitle()); @@ -87,10 +124,7 @@ public class SonosMediaInformationTest { @Test public void parseRadioAppMediaInfoWithSongTitleArtistAlbum() { - SonosMetaData trackMetaData = new SonosMetaData("yyy", "yyy", "yyy", - "TYPE=SNG|TITLE Time Of Your Life (Good Riddance)|ARTIST Green Day|ALBUM Nimrod", "yyy", "yyy", "yyy", - "yyy", "yyy", "yyy"); - SonosMediaInformation result = SonosMediaInformation.parseRadioAppMediaInfo("Radio Two", trackMetaData); + SonosMediaInformation result = SonosMediaInformation.parseRadioAppMediaInfo("Radio Two", METADATA_RADIOAPP_2); assertEquals("Green Day", result.getArtist()); assertEquals("Nimrod", result.getAlbum()); assertEquals("Time Of Your Life (Good Riddance)", result.getTitle()); @@ -100,9 +134,8 @@ public class SonosMediaInformationTest { @Test public void parseRadioAppMediaInfoWithdvertisement() { - SonosMetaData trackMetaData = new SonosMetaData("yyy", "yyy", "yyy", - "TYPE=SNG|TITLE Advertisement_Stop|ARTIST |ALBUM ", "yyy", "yyy", "yyy", "yyy", "yyy", "yyy"); - SonosMediaInformation result = SonosMediaInformation.parseRadioAppMediaInfo("Radio Two", trackMetaData); + SonosMediaInformation result = SonosMediaInformation.parseRadioAppMediaInfo("Radio Two", + METADATA_RADIOAPP_ADVERTISEMENT); assertEquals("", result.getArtist()); assertEquals("", result.getAlbum()); assertEquals("Radio Two", result.getTitle()); @@ -112,9 +145,8 @@ public class SonosMediaInformationTest { @Test public void parseRadioAppMediaInfoWithoutStreamContent() { - SonosMetaData trackMetaData = new SonosMetaData("yyy", "yyy", "yyy", "", "yyy", "yyy", "yyy", "yyy", "yyy", - "yyy"); - SonosMediaInformation result = SonosMediaInformation.parseRadioAppMediaInfo("Radio Two", trackMetaData); + SonosMediaInformation result = SonosMediaInformation.parseRadioAppMediaInfo("Radio Two", + METADATA_EMPTY_STREAM_CONTENT); assertNull(result.getArtist()); assertNull(result.getAlbum()); assertEquals("Radio Two", result.getTitle()); @@ -124,10 +156,7 @@ public class SonosMediaInformationTest { @Test public void parseRadioAppMediaInfoWithoutTitle() { - SonosMetaData trackMetaData = new SonosMetaData("yyy", "yyy", "yyy", - "TYPE=SNG|TITLE Green Day - Time Of Your Life (Good Riddance)|ARTIST |ALBUM ", "yyy", "yyy", "yyy", - "yyy", "yyy", "yyy"); - SonosMediaInformation result = SonosMediaInformation.parseRadioAppMediaInfo("", trackMetaData); + SonosMediaInformation result = SonosMediaInformation.parseRadioAppMediaInfo("", METADATA_RADIOAPP_1); assertNull(result.getArtist()); assertNull(result.getAlbum()); assertNull(result.getTitle()); @@ -147,9 +176,7 @@ public class SonosMediaInformationTest { @Test public void parseTrack() { - SonosMetaData trackMetaData = new SonosMetaData("xxx", "xxx", "xxx", "xxx", "xxx", - "Time Of Your Life (Good Riddance)", "xxx", "xxx", "Nimrod", "Green Day"); - SonosMediaInformation result = SonosMediaInformation.parseTrack(trackMetaData); + SonosMediaInformation result = SonosMediaInformation.parseTrack(METADATA_ARTIST_ALBUM_TITLE); assertEquals("Green Day", result.getArtist()); assertEquals("Nimrod", result.getAlbum()); assertEquals("Time Of Your Life (Good Riddance)", result.getTitle()); @@ -159,9 +186,7 @@ public class SonosMediaInformationTest { @Test public void parseTrackWithoutArtist() { - SonosMetaData trackMetaData = new SonosMetaData("xxx", "xxx", "xxx", "xxx", "xxx", - "Time Of Your Life (Good Riddance)", "xxx", "", "Nimrod", ""); - SonosMediaInformation result = SonosMediaInformation.parseTrack(trackMetaData); + SonosMediaInformation result = SonosMediaInformation.parseTrack(METADATA_EMPTY_CREATOR_ARTIST); assertEquals("", result.getArtist()); assertEquals("Nimrod", result.getAlbum()); assertEquals("Time Of Your Life (Good Riddance)", result.getTitle()); @@ -171,9 +196,7 @@ public class SonosMediaInformationTest { @Test public void parseTrackWithoutAlbum() { - SonosMetaData trackMetaData = new SonosMetaData("xxx", "xxx", "xxx", "xxx", "xxx", - "Time Of Your Life (Good Riddance)", "xxx", "Green Day", "", ""); - SonosMediaInformation result = SonosMediaInformation.parseTrack(trackMetaData); + SonosMediaInformation result = SonosMediaInformation.parseTrack(METADATA_EMPTY_ALBUM); assertEquals("Green Day", result.getArtist()); assertEquals("", result.getAlbum()); assertEquals("Time Of Your Life (Good Riddance)", result.getTitle()); @@ -183,9 +206,7 @@ public class SonosMediaInformationTest { @Test public void parseTrackWithoutTitle() { - SonosMetaData trackMetaData = new SonosMetaData("xxx", "xxx", "xxx", "xxx", "xxx", "", "xxx", "xxx", "Nimrod", - "Green Day"); - SonosMediaInformation result = SonosMediaInformation.parseTrack(trackMetaData); + SonosMediaInformation result = SonosMediaInformation.parseTrack(METADATA_EMPTY_TITLE); assertEquals("Green Day", result.getArtist()); assertEquals("Nimrod", result.getAlbum()); assertEquals("", result.getTitle()); @@ -195,9 +216,7 @@ public class SonosMediaInformationTest { @Test public void parseTrackWithOnlyTitle() { - SonosMetaData trackMetaData = new SonosMetaData("", "", "", "", "", "Time Of Your Life (Good Riddance)", "", "", - "", ""); - SonosMediaInformation result = SonosMediaInformation.parseTrack(trackMetaData); + SonosMediaInformation result = SonosMediaInformation.parseTrack(METADATA_ONLY_TITLE); assertEquals("", result.getArtist()); assertEquals("", result.getAlbum()); assertEquals("Time Of Your Life (Good Riddance)", result.getTitle()); @@ -207,8 +226,7 @@ public class SonosMediaInformationTest { @Test public void parseTrackWithEmptyMetaData() { - SonosMetaData trackMetaData = new SonosMetaData("", "", "", "", "", "", "", "", "", ""); - SonosMediaInformation result = SonosMediaInformation.parseTrack(trackMetaData); + SonosMediaInformation result = SonosMediaInformation.parseTrack(METADATA_EMPTY); assertEquals("", result.getArtist()); assertEquals("", result.getAlbum()); assertEquals("", result.getTitle()); @@ -228,9 +246,7 @@ public class SonosMediaInformationTest { @Test public void parseTrackTitle() { - SonosMetaData trackMetaData = new SonosMetaData("xxx", "xxx", "xxx", "xxx", "xxx", - "Time Of Your Life (Good Riddance)", "xxx", "xxx", "Nimrod", "Green Day"); - SonosMediaInformation result = SonosMediaInformation.parseTrackTitle(trackMetaData); + SonosMediaInformation result = SonosMediaInformation.parseTrackTitle(METADATA_ARTIST_ALBUM_TITLE); assertNull(result.getArtist()); assertNull(result.getAlbum()); assertEquals("Time Of Your Life (Good Riddance)", result.getTitle()); 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 0dca9013e..9e54cc1d5 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 @@ -12,7 +12,12 @@ */ package org.openhab.binding.sonos.internal; -import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.*; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.List; import org.eclipse.jdt.annotation.NonNullByDefault; import org.junit.jupiter.api.Test; @@ -60,4 +65,18 @@ public class SonosXMLParserTest { public void buildThingTypeIdFromModelWithAdditionalTextInParenthesis() { assertEquals("OneSL", SonosXMLParser.buildThingTypeIdFromModelName("Sonos One SL (OpenHome)")); } + + @Test + public void getRadioTimeFromXML() throws IOException { + InputStream resourceStream = getClass().getResourceAsStream("/OPML.xml"); + assertNotNull(resourceStream); + final String opmlResult = new String(resourceStream.readAllBytes(), StandardCharsets.UTF_8); + List result = SonosXMLParser.getRadioTimeFromXML(opmlResult); + assertEquals(3, result.size()); + if (result.size() == 3) { + assertEquals("RTL2 105.9", result.get(0)); + assertEquals("Le Son Pop-Rock", result.get(1)); + assertEquals("Paris, France", result.get(2)); + } + } } diff --git a/bundles/org.openhab.binding.sonos/src/test/resources/OPML.xml b/bundles/org.openhab.binding.sonos/src/test/resources/OPML.xml new file mode 100644 index 000000000..c21483b6b --- /dev/null +++ b/bundles/org.openhab.binding.sonos/src/test/resources/OPML.xml @@ -0,0 +1,18 @@ + + + + 200 + 43200 + + + + + + + + http://cdn-radiotime-logos.tunein.com/_0.png?t=1 + RTL2officiel + + + +