[sonos] Added support of RadioApp music service (#13235)
* [sonos] Added support of RadioApp music service * Extract artist and song title from TITLE * Extract code in methods to reduce the size of the method updateMediaInformation * Create new class and add tests Fix #13208 Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
parent
4bf7a4a51e
commit
92d6f1c6e9
|
@ -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<String> 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<String> 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,7 +14,6 @@ package org.openhab.binding.sonos.internal.handler;
|
||||||
|
|
||||||
import static org.openhab.binding.sonos.internal.SonosBindingConstants.*;
|
import static org.openhab.binding.sonos.internal.SonosBindingConstants.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.text.ParseException;
|
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 STREAM_URI = "x-sonosapi-stream:";
|
||||||
private static final String RADIO_URI = "x-sonosapi-radio:";
|
private static final String RADIO_URI = "x-sonosapi-radio:";
|
||||||
private static final String RADIO_MP3_URI = "x-rincon-mp3radio:";
|
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 OPML_TUNE = "http://opml.radiotime.com/Tune.ashx";
|
||||||
private static final String FILE_URI = "x-file-cifs:";
|
private static final String FILE_URI = "x-file-cifs:";
|
||||||
private static final String SPDIF = ":spdif";
|
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_LOUDNESS = "SetLoudness";
|
||||||
private static final String ACTION_SET_EQ = "SetEQ";
|
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 TUNEIN_DEFAULT_SERVICE_TYPE = 65031;
|
||||||
|
|
||||||
private static final int MIN_BASS = -10;
|
private static final int MIN_BASS = -10;
|
||||||
|
@ -1228,18 +1226,14 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici
|
||||||
SonosMetaData currentTrack = getTrackMetadata();
|
SonosMetaData currentTrack = getTrackMetadata();
|
||||||
SonosMetaData currentUriMetaData = getCurrentURIMetadata();
|
SonosMetaData currentUriMetaData = getCurrentURIMetadata();
|
||||||
|
|
||||||
String artist = null;
|
|
||||||
String album = null;
|
|
||||||
String title = null;
|
|
||||||
String resultString = null;
|
|
||||||
String stationID = null;
|
String stationID = null;
|
||||||
boolean needsUpdating = false;
|
SonosMediaInformation mediaInfo = new SonosMediaInformation();
|
||||||
|
|
||||||
// if currentURI == null, we do nothing
|
// if currentURI == null, we do nothing
|
||||||
if (currentURI != null) {
|
if (currentURI != null) {
|
||||||
if (currentURI.isEmpty()) {
|
if (currentURI.isEmpty()) {
|
||||||
// Reset data
|
// Reset data
|
||||||
needsUpdating = true;
|
mediaInfo = new SonosMediaInformation(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (currentURI.contains(GROUP_URI)) we do nothing, because
|
// 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)) {
|
else if (isPlayingStream(currentURI) || isPlayingRadioStartedByAmazonEcho(currentURI)) {
|
||||||
// Radio stream (tune-in)
|
// Radio stream (tune-in)
|
||||||
boolean opmlUrlSucceeded = false;
|
|
||||||
stationID = extractStationId(currentURI);
|
stationID = extractStationId(currentURI);
|
||||||
String url = opmlUrl;
|
mediaInfo = SonosMediaInformation.parseTuneInMediaInfo(buildOpmlUrl(stationID),
|
||||||
if (url != null) {
|
currentUriMetaData != null ? currentUriMetaData.getTitle() : null, currentTrack);
|
||||||
String mac = getMACAddress();
|
|
||||||
if (stationID != null && !stationID.isEmpty() && mac != null && !mac.isEmpty()) {
|
|
||||||
url = url.replace("%id", stationID);
|
|
||||||
url = url.replace("%serial", mac);
|
|
||||||
|
|
||||||
String response = null;
|
|
||||||
try {
|
|
||||||
response = HttpUtil.executeUrl("GET", url, SOCKET_TIMEOUT);
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.debug("Request to device failed", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response != null) {
|
else if (isPlayingRadioApp(currentURI)) {
|
||||||
List<String> fields = SonosXMLParser.getRadioTimeFromXML(response);
|
mediaInfo = SonosMediaInformation.parseRadioAppMediaInfo(
|
||||||
|
currentUriMetaData != null ? currentUriMetaData.getTitle() : null, currentTrack);
|
||||||
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 (isPlayingLineIn(currentURI)) {
|
else if (isPlayingLineIn(currentURI)) {
|
||||||
if (currentTrack != null) {
|
mediaInfo = SonosMediaInformation.parseTrackTitle(currentTrack);
|
||||||
title = currentTrack.getTitle();
|
|
||||||
resultString = title;
|
|
||||||
needsUpdating = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (isPlayingRadio(currentURI)
|
else if (isPlayingRadio(currentURI)
|
||||||
|| (!currentURI.contains("x-rincon-mp3") && !currentURI.contains("x-sonosapi"))) {
|
|| (!currentURI.contains("x-rincon-mp3") && !currentURI.contains("x-sonosapi"))) {
|
||||||
// isPlayingRadio(currentURI) is true for Google Play Music radio or Apple Music radio
|
mediaInfo = SonosMediaInformation.parseTrack(currentTrack);
|
||||||
if (currentTrack != null) {
|
|
||||||
artist = !currentTrack.getAlbumArtist().isEmpty() ? currentTrack.getAlbumArtist()
|
|
||||||
: currentTrack.getCreator();
|
|
||||||
album = currentTrack.getAlbum();
|
|
||||||
title = currentTrack.getTitle();
|
|
||||||
resultString = artist + " - " + album + " - " + title;
|
|
||||||
needsUpdating = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1337,14 +1278,18 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici
|
||||||
}
|
}
|
||||||
memberHandler.onValueReceived("CurrentTuneInStationId", (stationID != null) ? stationID : "",
|
memberHandler.onValueReceived("CurrentTuneInStationId", (stationID != null) ? stationID : "",
|
||||||
SERVICE_AV_TRANSPORT);
|
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 : "",
|
memberHandler.onValueReceived("CurrentArtist", (artist != null) ? artist : "",
|
||||||
SERVICE_AV_TRANSPORT);
|
SERVICE_AV_TRANSPORT);
|
||||||
memberHandler.onValueReceived("CurrentAlbum", (album != null) ? album : "",
|
memberHandler.onValueReceived("CurrentAlbum", (album != null) ? album : "",
|
||||||
SERVICE_AV_TRANSPORT);
|
SERVICE_AV_TRANSPORT);
|
||||||
memberHandler.onValueReceived("CurrentTitle", (title != null) ? title : "",
|
memberHandler.onValueReceived("CurrentTitle", (title != null) ? title : "",
|
||||||
SERVICE_AV_TRANSPORT);
|
SERVICE_AV_TRANSPORT);
|
||||||
memberHandler.onValueReceived("CurrentURIFormatted", (resultString != null) ? resultString : "",
|
memberHandler.onValueReceived("CurrentURIFormatted", (combinedInfo != null) ? combinedInfo : "",
|
||||||
SERVICE_AV_TRANSPORT);
|
SERVICE_AV_TRANSPORT);
|
||||||
memberHandler.onValueReceived("CurrentAlbumArtURI", albumArtURI, 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());
|
logger.debug("Cannot update media data for group member ({})", e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (needsUpdating && handlerForImageUpdate != null) {
|
if (mediaInfo.needsUpdate() && handlerForImageUpdate != null) {
|
||||||
handlerForImageUpdate.updateAlbumArtChannel(true);
|
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) {
|
private @Nullable String extractStationId(String uri) {
|
||||||
String stationID = null;
|
String stationID = null;
|
||||||
if (isPlayingStream(uri)) {
|
if (isPlayingStream(uri)) {
|
||||||
|
@ -1711,8 +1669,7 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici
|
||||||
savedState.volume = getVolume();
|
savedState.volume = getVolume();
|
||||||
|
|
||||||
if (currentURI != null) {
|
if (currentURI != null) {
|
||||||
if (isPlayingStream(currentURI) || isPlayingRadioStartedByAmazonEcho(currentURI)
|
if (isPlayingStreamOrRadio(currentURI)) {
|
||||||
|| isPlayingRadio(currentURI)) {
|
|
||||||
// we are streaming music, like tune-in radio or Google Play Music radio
|
// we are streaming music, like tune-in radio or Google Play Music radio
|
||||||
SonosMetaData track = getTrackMetadata();
|
SonosMetaData track = getTrackMetadata();
|
||||||
SonosMetaData current = getCurrentURIMetadata();
|
SonosMetaData current = getCurrentURIMetadata();
|
||||||
|
@ -2653,8 +2610,7 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici
|
||||||
logger.debug("playNotificationSoundURI: currentURI {} metadata {}", currentURI,
|
logger.debug("playNotificationSoundURI: currentURI {} metadata {}", currentURI,
|
||||||
coordinator.getCurrentURIMetadataAsString());
|
coordinator.getCurrentURIMetadataAsString());
|
||||||
|
|
||||||
if (isPlayingStream(currentURI) || isPlayingRadioStartedByAmazonEcho(currentURI)
|
if (isPlayingStreamOrRadio(currentURI)) {
|
||||||
|| isPlayingRadio(currentURI)) {
|
|
||||||
handleNotifForRadioStream(currentURI, notificationURL, coordinator);
|
handleNotifForRadioStream(currentURI, notificationURL, coordinator);
|
||||||
} else if (isPlayingLineIn(currentURI)) {
|
} else if (isPlayingLineIn(currentURI)) {
|
||||||
handleNotifForLineIn(currentURI, notificationURL, coordinator);
|
handleNotifForLineIn(currentURI, notificationURL, coordinator);
|
||||||
|
@ -2692,13 +2648,24 @@ public class ZonePlayerHandler extends BaseThingHandler implements UpnpIOPartici
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isPlayingRadio(@Nullable String currentURI) {
|
private boolean isPlayingRadio(@Nullable String currentURI) {
|
||||||
|
// Google Play Music radio or Apple Music radio
|
||||||
return currentURI != null && currentURI.contains(RADIO_URI);
|
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) {
|
private boolean isPlayingRadioStartedByAmazonEcho(@Nullable String currentURI) {
|
||||||
return currentURI != null && currentURI.contains(RADIO_MP3_URI) && currentURI.contains(OPML_TUNE);
|
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) {
|
private boolean isPlayingLineIn(@Nullable String currentURI) {
|
||||||
return currentURI != null && (isPlayingAnalogLineIn(currentURI) || isPlayingOpticalLineIn(currentURI));
|
return currentURI != null && (isPlayingAnalogLineIn(currentURI) || isPlayingOpticalLineIn(currentURI));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue