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 new file mode 100644 index 000000000..264e867e5 --- /dev/null +++ b/bundles/org.openhab.binding.sonos/src/main/java/org/openhab/binding/sonos/internal/handler/SonosMediaInformation.java @@ -0,0 +1,202 @@ +/** + * Copyright (c) 2010-2022 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sonos.internal.handler; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +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 + * + * @author Laurent Garnier - Initial contribution + */ +@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; + private @Nullable String combinedInfo; + private boolean needsUpdate; + + public SonosMediaInformation() { + this(false); + } + + public SonosMediaInformation(boolean needsUpdate) { + this(null, null, null, null, needsUpdate); + } + + public SonosMediaInformation(@Nullable String artist, @Nullable String album, @Nullable String title, + @Nullable String combinedInfo, boolean needsUpdate) { + this.artist = artist; + this.album = album; + this.title = title; + this.combinedInfo = combinedInfo; + this.needsUpdate = needsUpdate; + } + + public @Nullable String getArtist() { + return artist; + } + + public @Nullable String getAlbum() { + return album; + } + + public @Nullable String getTitle() { + return title; + } + + public @Nullable String getCombinedInfo() { + return combinedInfo; + } + + public boolean needsUpdate() { + return needsUpdate; + } + + public static SonosMediaInformation parseTuneInMediaInfo(@Nullable String opmlUrl, @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 (radioTitle != null && !radioTitle.isEmpty()) { + title = radioTitle; + combinedInfo = title; + if (trackMetaData != null && !trackMetaData.getStreamContent().isEmpty()) { + combinedInfo += " - " + trackMetaData.getStreamContent(); + } + return new SonosMediaInformation(null, null, title, combinedInfo, true); + } + return new SonosMediaInformation(false); + } + + public static SonosMediaInformation parseRadioAppMediaInfo(@Nullable String radioTitle, + @Nullable SonosMetaData trackMetaData) { + if (radioTitle != null && !radioTitle.isEmpty()) { + String artist = null; + String album = null; + String title = radioTitle; + String combinedInfo = title; + if (trackMetaData != null) { + String[] contents = trackMetaData.getStreamContent().split("\\|"); + String contentTitle = null; + for (int i = 0; i < contents.length; i++) { + if (contents[i].startsWith("TITLE ")) { + contentTitle = contents[i].substring(6).trim(); + } + if (contents[i].startsWith("ARTIST ")) { + artist = contents[i].substring(7).trim(); + } + if (contents[i].startsWith("ALBUM ")) { + album = contents[i].substring(6).trim(); + } + } + if ((artist == null || artist.isEmpty()) && contentTitle != null && !contentTitle.isEmpty() + && !contentTitle.startsWith("Advertisement_")) { + // Try to extract artist and song title from contentTitle + int idx = contentTitle.indexOf(" - "); + if (idx > 0) { + artist = contentTitle.substring(0, idx); + title = contentTitle.substring(idx + 3); + } + } else if (artist != null && !artist.isEmpty() && album != null && !album.isEmpty() + && contentTitle != null && !contentTitle.isEmpty()) { + title = contentTitle; + } + if (artist != null && !artist.isEmpty()) { + combinedInfo += " - " + artist; + } + if (album != null && !album.isEmpty()) { + combinedInfo += " - " + album; + } + if (!radioTitle.equals(title)) { + combinedInfo += " - " + title; + } else if (contentTitle != null && !contentTitle.isEmpty() + && !contentTitle.startsWith("Advertisement_")) { + combinedInfo += " - " + contentTitle; + } + } + return new SonosMediaInformation(artist, album, title, combinedInfo, true); + } + return new SonosMediaInformation(false); + } + + public static SonosMediaInformation parseTrack(@Nullable SonosMetaData trackMetaData) { + if (trackMetaData != null) { + List infos = new ArrayList<>(); + String artist = !trackMetaData.getAlbumArtist().isEmpty() ? trackMetaData.getAlbumArtist() + : trackMetaData.getCreator(); + if (!artist.isEmpty()) { + infos.add(artist); + } + String album = trackMetaData.getAlbum(); + if (!album.isEmpty()) { + infos.add(album); + } + String title = trackMetaData.getTitle(); + if (!title.isEmpty()) { + infos.add(title); + } + return new SonosMediaInformation(artist, album, title, String.join(" - ", infos), true); + } + return new SonosMediaInformation(false); + } + + public static SonosMediaInformation parseTrackTitle(@Nullable SonosMetaData trackMetaData) { + if (trackMetaData != null) { + String title = trackMetaData.getTitle(); + return new SonosMediaInformation(null, null, title, title, true); + } + return new SonosMediaInformation(false); + } +} 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 e0784cce5..b55b9f4d7 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,7 +14,6 @@ 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; @@ -92,6 +91,7 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici private static final String STREAM_URI = "x-sonosapi-stream:"; private static final String RADIO_URI = "x-sonosapi-radio:"; private static final String RADIO_MP3_URI = "x-rincon-mp3radio:"; + private static final String RADIOAPP_URI = "x-sonosapi-hls:radioapp_"; private static final String OPML_TUNE = "http://opml.radiotime.com/Tune.ashx"; private static final String FILE_URI = "x-file-cifs:"; private static final String SPDIF = ":spdif"; @@ -150,8 +150,6 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici private static final String ACTION_SET_LOUDNESS = "SetLoudness"; private static final String ACTION_SET_EQ = "SetEQ"; - private static final int SOCKET_TIMEOUT = 5000; - private static final int TUNEIN_DEFAULT_SERVICE_TYPE = 65031; private static final int MIN_BASS = -10; @@ -1228,18 +1226,14 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici SonosMetaData currentTrack = getTrackMetadata(); SonosMetaData currentUriMetaData = getCurrentURIMetadata(); - String artist = null; - String album = null; - String title = null; - String resultString = null; String stationID = null; - boolean needsUpdating = false; + SonosMediaInformation mediaInfo = new SonosMediaInformation(); // if currentURI == null, we do nothing if (currentURI != null) { if (currentURI.isEmpty()) { // Reset data - needsUpdating = true; + mediaInfo = new SonosMediaInformation(true); } // if (currentURI.contains(GROUP_URI)) we do nothing, because @@ -1249,76 +1243,23 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici else if (isPlayingStream(currentURI) || isPlayingRadioStartedByAmazonEcho(currentURI)) { // Radio stream (tune-in) - boolean opmlUrlSucceeded = false; stationID = extractStationId(currentURI); - String url = opmlUrl; - if (url != null) { - String mac = getMACAddress(); - if (stationID != null && !stationID.isEmpty() && mac != null && !mac.isEmpty()) { - url = url.replace("%id", stationID); - url = url.replace("%serial", mac); + mediaInfo = SonosMediaInformation.parseTuneInMediaInfo(buildOpmlUrl(stationID), + currentUriMetaData != null ? currentUriMetaData.getTitle() : null, currentTrack); + } - String response = null; - try { - response = HttpUtil.executeUrl("GET", url, SOCKET_TIMEOUT); - } catch (IOException e) { - logger.debug("Request to device failed", e); - } - - if (response != null) { - List fields = SonosXMLParser.getRadioTimeFromXML(response); - - if (!fields.isEmpty()) { - opmlUrlSucceeded = true; - - resultString = ""; - for (String field : fields) { - if (resultString.isEmpty()) { - // radio name should be first field - title = field; - } else { - resultString += " - "; - } - resultString += field; - } - - needsUpdating = true; - } - } - } - } - if (!opmlUrlSucceeded) { - if (currentUriMetaData != null) { - title = currentUriMetaData.getTitle(); - if (currentTrack == null || currentTrack.getStreamContent().isEmpty()) { - resultString = title; - } else { - resultString = title + " - " + currentTrack.getStreamContent(); - } - needsUpdating = true; - } - } + else if (isPlayingRadioApp(currentURI)) { + mediaInfo = SonosMediaInformation.parseRadioAppMediaInfo( + currentUriMetaData != null ? currentUriMetaData.getTitle() : null, currentTrack); } else if (isPlayingLineIn(currentURI)) { - if (currentTrack != null) { - title = currentTrack.getTitle(); - resultString = title; - needsUpdating = true; - } + mediaInfo = SonosMediaInformation.parseTrackTitle(currentTrack); } else if (isPlayingRadio(currentURI) || (!currentURI.contains("x-rincon-mp3") && !currentURI.contains("x-sonosapi"))) { - // isPlayingRadio(currentURI) is true for Google Play Music radio or Apple Music radio - if (currentTrack != null) { - artist = !currentTrack.getAlbumArtist().isEmpty() ? currentTrack.getAlbumArtist() - : currentTrack.getCreator(); - album = currentTrack.getAlbum(); - title = currentTrack.getTitle(); - resultString = artist + " - " + album + " - " + title; - needsUpdating = true; - } + mediaInfo = SonosMediaInformation.parseTrack(currentTrack); } } @@ -1337,14 +1278,18 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici } memberHandler.onValueReceived("CurrentTuneInStationId", (stationID != null) ? stationID : "", SERVICE_AV_TRANSPORT); - if (needsUpdating) { + if (mediaInfo.needsUpdate()) { + String artist = mediaInfo.getArtist(); + String album = mediaInfo.getAlbum(); + String title = mediaInfo.getTitle(); + String combinedInfo = mediaInfo.getCombinedInfo(); memberHandler.onValueReceived("CurrentArtist", (artist != null) ? artist : "", SERVICE_AV_TRANSPORT); memberHandler.onValueReceived("CurrentAlbum", (album != null) ? album : "", SERVICE_AV_TRANSPORT); memberHandler.onValueReceived("CurrentTitle", (title != null) ? title : "", SERVICE_AV_TRANSPORT); - memberHandler.onValueReceived("CurrentURIFormatted", (resultString != null) ? resultString : "", + memberHandler.onValueReceived("CurrentURIFormatted", (combinedInfo != null) ? combinedInfo : "", SERVICE_AV_TRANSPORT); memberHandler.onValueReceived("CurrentAlbumArtURI", albumArtURI, SERVICE_AV_TRANSPORT); } @@ -1353,11 +1298,24 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici logger.debug("Cannot update media data for group member ({})", e.getMessage()); } } - if (needsUpdating && handlerForImageUpdate != null) { + if (mediaInfo.needsUpdate() && handlerForImageUpdate != null) { handlerForImageUpdate.updateAlbumArtChannel(true); } } + private @Nullable String buildOpmlUrl(@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; + } + } + return null; + } + private @Nullable String extractStationId(String uri) { String stationID = null; if (isPlayingStream(uri)) { @@ -1711,8 +1669,7 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici savedState.volume = getVolume(); if (currentURI != null) { - if (isPlayingStream(currentURI) || isPlayingRadioStartedByAmazonEcho(currentURI) - || isPlayingRadio(currentURI)) { + if (isPlayingStreamOrRadio(currentURI)) { // we are streaming music, like tune-in radio or Google Play Music radio SonosMetaData track = getTrackMetadata(); SonosMetaData current = getCurrentURIMetadata(); @@ -2653,8 +2610,7 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici logger.debug("playNotificationSoundURI: currentURI {} metadata {}", currentURI, coordinator.getCurrentURIMetadataAsString()); - if (isPlayingStream(currentURI) || isPlayingRadioStartedByAmazonEcho(currentURI) - || isPlayingRadio(currentURI)) { + if (isPlayingStreamOrRadio(currentURI)) { handleNotifForRadioStream(currentURI, notificationURL, coordinator); } else if (isPlayingLineIn(currentURI)) { handleNotifForLineIn(currentURI, notificationURL, coordinator); @@ -2692,13 +2648,24 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici } private boolean isPlayingRadio(@Nullable String currentURI) { + // Google Play Music radio or Apple Music radio return currentURI != null && currentURI.contains(RADIO_URI); } + private boolean isPlayingRadioApp(@Nullable String currentURI) { + // RadioApp music service + return currentURI != null && currentURI.contains(RADIOAPP_URI); + } + private boolean isPlayingRadioStartedByAmazonEcho(@Nullable String currentURI) { return currentURI != null && currentURI.contains(RADIO_MP3_URI) && currentURI.contains(OPML_TUNE); } + private boolean isPlayingStreamOrRadio(@Nullable String currentURI) { + return isPlayingStream(currentURI) || isPlayingRadioStartedByAmazonEcho(currentURI) + || isPlayingRadio(currentURI) || isPlayingRadioApp(currentURI); + } + private boolean isPlayingLineIn(@Nullable String currentURI) { return currentURI != null && (isPlayingAnalogLineIn(currentURI) || isPlayingOpticalLineIn(currentURI)); } 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 new file mode 100644 index 000000000..a9e48681e --- /dev/null +++ b/bundles/org.openhab.binding.sonos/src/test/java/org/openhab/binding/sonos/internal/SonosMediaInformationTest.java @@ -0,0 +1,250 @@ +/** + * Copyright (c) 2010-2022 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.binding.sonos.internal; + +import static org.junit.jupiter.api.Assertions.*; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; +import org.openhab.binding.sonos.internal.handler.SonosMediaInformation; + +/** + * Test for class SonosMediaInformation + * + * @author Laurent Garnier - Initial contribution + */ +@NonNullByDefault +public class SonosMediaInformationTest { + + @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); + assertNull(result.getArtist()); + assertNull(result.getAlbum()); + assertEquals("Radio One", result.getTitle()); + assertEquals("Radio One - Mroning 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); + assertNull(result.getArtist()); + assertNull(result.getAlbum()); + assertEquals("Radio One", result.getTitle()); + assertEquals("Radio One", result.getCombinedInfo()); + assertEquals(true, result.needsUpdate()); + } + + @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); + assertNull(result.getArtist()); + assertNull(result.getAlbum()); + assertNull(result.getTitle()); + assertNull(result.getCombinedInfo()); + assertEquals(false, result.needsUpdate()); + } + + @Test + public void parseTuneInMediaInfoWithNullParams() { + SonosMediaInformation result = SonosMediaInformation.parseTuneInMediaInfo(null, null, null); + assertNull(result.getArtist()); + assertNull(result.getAlbum()); + assertNull(result.getTitle()); + assertNull(result.getCombinedInfo()); + assertEquals(false, 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); + assertEquals("Green Day", result.getArtist()); + assertEquals("", result.getAlbum()); + assertEquals("Time Of Your Life (Good Riddance)", result.getTitle()); + assertEquals("Radio Two - Green Day - Time Of Your Life (Good Riddance)", result.getCombinedInfo()); + assertEquals(true, result.needsUpdate()); + } + + @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); + assertEquals("Green Day", result.getArtist()); + assertEquals("Nimrod", result.getAlbum()); + assertEquals("Time Of Your Life (Good Riddance)", result.getTitle()); + assertEquals("Radio Two - Green Day - Nimrod - Time Of Your Life (Good Riddance)", result.getCombinedInfo()); + assertEquals(true, result.needsUpdate()); + } + + @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); + assertEquals("", result.getArtist()); + assertEquals("", result.getAlbum()); + assertEquals("Radio Two", result.getTitle()); + assertEquals("Radio Two", result.getCombinedInfo()); + assertEquals(true, result.needsUpdate()); + } + + @Test + public void parseRadioAppMediaInfoWithoutStreamContent() { + SonosMetaData trackMetaData = new SonosMetaData("yyy", "yyy", "yyy", "", "yyy", "yyy", "yyy", "yyy", "yyy", + "yyy"); + SonosMediaInformation result = SonosMediaInformation.parseRadioAppMediaInfo("Radio Two", trackMetaData); + assertNull(result.getArtist()); + assertNull(result.getAlbum()); + assertEquals("Radio Two", result.getTitle()); + assertEquals("Radio Two", result.getCombinedInfo()); + assertEquals(true, result.needsUpdate()); + } + + @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); + assertNull(result.getArtist()); + assertNull(result.getAlbum()); + assertNull(result.getTitle()); + assertNull(result.getCombinedInfo()); + assertEquals(false, result.needsUpdate()); + } + + @Test + public void parseRadioAppMediaInfoWithNullParams() { + SonosMediaInformation result = SonosMediaInformation.parseRadioAppMediaInfo(null, null); + assertNull(result.getArtist()); + assertNull(result.getAlbum()); + assertNull(result.getTitle()); + assertNull(result.getCombinedInfo()); + assertEquals(false, result.needsUpdate()); + } + + @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); + assertEquals("Green Day", result.getArtist()); + assertEquals("Nimrod", result.getAlbum()); + assertEquals("Time Of Your Life (Good Riddance)", result.getTitle()); + assertEquals("Green Day - Nimrod - Time Of Your Life (Good Riddance)", result.getCombinedInfo()); + assertEquals(true, result.needsUpdate()); + } + + @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); + assertEquals("", result.getArtist()); + assertEquals("Nimrod", result.getAlbum()); + assertEquals("Time Of Your Life (Good Riddance)", result.getTitle()); + assertEquals("Nimrod - Time Of Your Life (Good Riddance)", result.getCombinedInfo()); + assertEquals(true, result.needsUpdate()); + } + + @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); + assertEquals("Green Day", result.getArtist()); + assertEquals("", result.getAlbum()); + assertEquals("Time Of Your Life (Good Riddance)", result.getTitle()); + assertEquals("Green Day - Time Of Your Life (Good Riddance)", result.getCombinedInfo()); + assertEquals(true, result.needsUpdate()); + } + + @Test + public void parseTrackWithoutTitle() { + SonosMetaData trackMetaData = new SonosMetaData("xxx", "xxx", "xxx", "xxx", "xxx", "", "xxx", "xxx", "Nimrod", + "Green Day"); + SonosMediaInformation result = SonosMediaInformation.parseTrack(trackMetaData); + assertEquals("Green Day", result.getArtist()); + assertEquals("Nimrod", result.getAlbum()); + assertEquals("", result.getTitle()); + assertEquals("Green Day - Nimrod", result.getCombinedInfo()); + assertEquals(true, result.needsUpdate()); + } + + @Test + public void parseTrackWithOnlyTitle() { + SonosMetaData trackMetaData = new SonosMetaData("", "", "", "", "", "Time Of Your Life (Good Riddance)", "", "", + "", ""); + SonosMediaInformation result = SonosMediaInformation.parseTrack(trackMetaData); + assertEquals("", result.getArtist()); + assertEquals("", result.getAlbum()); + assertEquals("Time Of Your Life (Good Riddance)", result.getTitle()); + assertEquals("Time Of Your Life (Good Riddance)", result.getCombinedInfo()); + assertEquals(true, result.needsUpdate()); + } + + @Test + public void parseTrackWithEmptyMetaData() { + SonosMetaData trackMetaData = new SonosMetaData("", "", "", "", "", "", "", "", "", ""); + SonosMediaInformation result = SonosMediaInformation.parseTrack(trackMetaData); + assertEquals("", result.getArtist()); + assertEquals("", result.getAlbum()); + assertEquals("", result.getTitle()); + assertEquals("", result.getCombinedInfo()); + assertEquals(true, result.needsUpdate()); + } + + @Test + public void parseTrackWithNullParam() { + SonosMediaInformation result = SonosMediaInformation.parseTrack(null); + assertNull(result.getArtist()); + assertNull(result.getAlbum()); + assertNull(result.getTitle()); + assertNull(result.getCombinedInfo()); + assertEquals(false, result.needsUpdate()); + } + + @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); + assertNull(result.getArtist()); + assertNull(result.getAlbum()); + assertEquals("Time Of Your Life (Good Riddance)", result.getTitle()); + assertEquals("Time Of Your Life (Good Riddance)", result.getCombinedInfo()); + assertEquals(true, result.needsUpdate()); + } + + @Test + public void parseTrackTitleWithNullParam() { + SonosMediaInformation result = SonosMediaInformation.parseTrackTitle(null); + assertNull(result.getArtist()); + assertNull(result.getAlbum()); + assertNull(result.getTitle()); + assertNull(result.getCombinedInfo()); + assertEquals(false, result.needsUpdate()); + } +}