import java.util.concurrent.Future;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.binding.squeezebox.internal.config.SqueezeBoxServerConfig;
import org.openhab.binding.squeezebox.internal.dto.ButtonDTO;
import org.openhab.binding.squeezebox.internal.dto.ButtonDTODeserializer;
}
}
+ @NonNullByDefault
+ private class KeyValue {
+ final String key;
+ final String value;
+
+ public KeyValue(String key, String value) {
+ this.key = key;
+ this.value = value;
+ }
+ };
+
+ private List<KeyValue> decodeKeyValueResponse(String[] response) {
+ final List<KeyValue> keysAndValues = new ArrayList<>();
+ if (response != null) {
+ for (String line : response) {
+ final String decoded = decode(line);
+ int colonPos = decoded.indexOf(":");
+ if (colonPos < 0) {
+ continue;
+ }
+ keysAndValues.add(new KeyValue(decoded.substring(0, colonPos), decoded.substring(colonPos + 1)));
+ }
+ }
+ return keysAndValues;
+ }
+
private void handlePlayersList(String message) {
final Set<String> connectedPlayers = new HashSet<>();
// Split out players
String[] playersList = message.split("playerindex\\S*\\s");
for (String playerParams : playersList) {
-
// For each player, split out parameters and decode parameter
- String[] parameterList = playerParams.split("\\s");
- for (int i = 0; i < parameterList.length; i++) {
- parameterList[i] = decode(parameterList[i]);
- }
-
- // parse out the MAC address first
- String macAddress = null;
- for (String parameter : parameterList) {
- if (parameter.contains("playerid")) {
- macAddress = parameter.substring(parameter.indexOf(":") + 1);
- break;
- }
- }
+ final Map<String, String> keysAndValues = decodeKeyValueResponse(playerParams.split("\\s")).stream()
+ .collect(Collectors.toMap(kv -> kv.key, kv -> kv.value));
+ final String macAddress = keysAndValues.get("playerid");
// if none found then ignore this set of params
if (macAddress == null) {
continue;
}
- final SqueezeBoxPlayer player = new SqueezeBoxPlayer();
- player.setMacAddress(macAddress);
- // populate the player state
- for (String parameter : parameterList) {
- if (parameter.startsWith("ip:")) {
- player.setIpAddr(parameter.substring(parameter.indexOf(":") + 1));
- } else if (parameter.startsWith("uuid:")) {
- player.setUuid(parameter.substring(parameter.indexOf(":") + 1));
- } else if (parameter.startsWith("name:")) {
- player.setName(parameter.substring(parameter.indexOf(":") + 1));
- } else if (parameter.startsWith("model:")) {
- player.setModel(parameter.substring(parameter.indexOf(":") + 1));
- } else if (parameter.startsWith("connected:")) {
- if ("1".equals(parameter.substring(parameter.indexOf(":") + 1))) {
- connectedPlayers.add(macAddress);
- }
- }
+ final SqueezeBoxPlayer player = new SqueezeBoxPlayer(macAddress, keysAndValues.get("name"),
+ keysAndValues.get("ip"), keysAndValues.get("model"), keysAndValues.get("uuid"));
+ if ("1".equals(keysAndValues.get("connected"))) {
+ connectedPlayers.add(macAddress);
}
// Save player if we haven't seen it yet
if (!players.containsKey(macAddress)) {
players.put(macAddress, player);
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.playerAdded(player);
- }
- });
+ updatePlayer(listener -> listener.playerAdded(player));
// tell the server we want to subscribe to player updates
- sendCommand(player.getMacAddress() + " status - 1 subscribe:10 tags:yagJlNKjc");
+ sendCommand(player.macAddress + " status - 1 subscribe:10 tags:yagJlNKjc");
}
}
for (final SqueezeBoxPlayer player : players.values()) {
- final String mac = player.getMacAddress();
- final boolean connected = connectedPlayers.contains(mac);
- updatePlayer(listener -> listener.connectedStateChangeEvent(mac, connected));
+ final boolean connected = connectedPlayers.contains(player.macAddress);
+ updatePlayer(listener -> listener.connectedStateChangeEvent(player.macAddress, connected));
}
}
break;
case "ir":
final String ircode = messageParts[2];
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.irCodeChangeEvent(mac, ircode);
- }
- });
+ updatePlayer(listener -> listener.irCodeChangeEvent(mac, ircode));
break;
default:
logger.trace("Unhandled player update message type '{}'.", messageType);
switch (action) {
case "volume":
String volumeStringValue = decode(messageParts[3]);
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- try {
- int volume = Integer.parseInt(volumeStringValue);
-
- // Check if we received a relative volume change, or an absolute
- // volume value.
- if (volumeStringValue.contains("+") || (volumeStringValue.contains("-"))) {
- listener.relativeVolumeChangeEvent(mac, volume);
- } else {
- listener.absoluteVolumeChangeEvent(mac, volume);
- }
- } catch (NumberFormatException e) {
- logger.warn("Unable to parse volume [{}] received from mixer message.",
- volumeStringValue, e);
+ updatePlayer(listener -> {
+ try {
+ int volume = Integer.parseInt(volumeStringValue);
+
+ // Check if we received a relative volume change, or an absolute
+ // volume value.
+ if (volumeStringValue.contains("+") || (volumeStringValue.contains("-"))) {
+ listener.relativeVolumeChangeEvent(mac, volume);
+ } else {
+ listener.absoluteVolumeChangeEvent(mac, volume);
}
+ } catch (NumberFormatException e) {
+ logger.warn("Unable to parse volume [{}] received from mixer message.", volumeStringValue,
+ e);
}
});
break;
String coverid = null;
String artworkUrl = null;
- for (String messagePart : messageParts) {
+ for (KeyValue entry : decodeKeyValueResponse(messageParts)) {
// Parameter Power
- if (messagePart.startsWith("power%3A")) {
- final boolean power = "1".matches(messagePart.substring("power%3A".length()));
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.powerChangeEvent(mac, power);
- }
- });
+ if ("power".equals(entry.key)) {
+ final boolean power = "1".equals(entry.value);
+ updatePlayer(listener -> listener.powerChangeEvent(mac, power));
}
// Parameter Volume
- else if (messagePart.startsWith("mixer%20volume%3A")) {
- String value = messagePart.substring("mixer%20volume%3A".length());
- final int volume = (int) Double.parseDouble(value);
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.absoluteVolumeChangeEvent(mac, volume);
- }
- });
+ else if ("mixer volume".equals(entry.key)) {
+ final int volume = (int) Double.parseDouble(entry.value);
+ updatePlayer(listener -> listener.absoluteVolumeChangeEvent(mac, volume));
}
// Parameter Mode
- else if (messagePart.startsWith("mode%3A")) {
- final String mode = messagePart.substring("mode%3A".length());
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.modeChangeEvent(mac, mode);
- }
- });
+ else if ("mode".equals(entry.key)) {
+ updatePlayer(listener -> listener.modeChangeEvent(mac, entry.value));
}
// Parameter Playing Time
- else if (messagePart.startsWith("time%3A")) {
- String value = messagePart.substring("time%3A".length());
- final int time = (int) Double.parseDouble(value);
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.currentPlayingTimeEvent(mac, time);
- }
- });
+ else if ("time".equals(entry.key)) {
+ final int time = (int) Double.parseDouble(entry.value);
+ updatePlayer(listener -> listener.currentPlayingTimeEvent(mac, time));
}
// Parameter duration
- else if (messagePart.startsWith("duration%3A")) {
- String value = messagePart.substring("duration%3A".length());
- final int duration = (int) Double.parseDouble(value);
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.durationEvent(mac, duration);
- }
- });
+ else if ("duration".equals(entry.key)) {
+ final int duration = (int) Double.parseDouble(entry.value);
+ updatePlayer(listener -> listener.durationEvent(mac, duration));
}
// Parameter Playing Playlist Index
- else if (messagePart.startsWith("playlist_cur_index%3A")) {
- String value = messagePart.substring("playlist_cur_index%3A".length());
- final int index = (int) Double.parseDouble(value);
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.currentPlaylistIndexEvent(mac, index);
- }
- });
+ else if ("playlist_cur_index".equals(entry.key)) {
+ final int index = (int) Double.parseDouble(entry.value);
+ updatePlayer(listener -> listener.currentPlaylistIndexEvent(mac, index));
}
// Parameter Playlist Number Tracks
- else if (messagePart.startsWith("playlist_tracks%3A")) {
- String value = messagePart.substring("playlist_tracks%3A".length());
- final int track = (int) Double.parseDouble(value);
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.numberPlaylistTracksEvent(mac, track);
- }
- });
+ else if ("playlist_tracks".equals(entry.key)) {
+ final int track = (int) Double.parseDouble(entry.value);
+ updatePlayer(listener -> listener.numberPlaylistTracksEvent(mac, track));
}
// Parameter Playlist Repeat Mode
- else if (messagePart.startsWith("playlist%20repeat%3A")) {
- String value = messagePart.substring("playlist%20repeat%3A".length());
- final int repeat = (int) Double.parseDouble(value);
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.currentPlaylistRepeatEvent(mac, repeat);
- }
- });
+ else if ("playlist repeat".equals(entry.key)) {
+ final int repeat = (int) Double.parseDouble(entry.value);
+ updatePlayer(listener -> listener.currentPlaylistRepeatEvent(mac, repeat));
}
// Parameter Playlist Shuffle Mode
- else if (messagePart.startsWith("playlist%20shuffle%3A")) {
- String value = messagePart.substring("playlist%20shuffle%3A".length());
- final int shuffle = (int) Double.parseDouble(value);
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.currentPlaylistShuffleEvent(mac, shuffle);
- }
- });
+ else if ("playlist shuffle".equals(entry.key)) {
+ final int shuffle = (int) Double.parseDouble(entry.value);
+ updatePlayer(listener -> listener.currentPlaylistShuffleEvent(mac, shuffle));
}
// Parameter Title
- else if (messagePart.startsWith("title%3A")) {
- final String value = messagePart.substring("title%3A".length());
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.titleChangeEvent(mac, decode(value));
- }
- });
+ else if ("title".equals(entry.key)) {
+ updatePlayer(listener -> listener.titleChangeEvent(mac, entry.value));
}
// Parameter Remote Title (radio)
- else if (messagePart.startsWith("remote_title%3A")) {
- remoteTitle = messagePart.substring("remote_title%3A".length());
+ else if ("remote_title".equals(entry.key)) {
+ remoteTitle = entry.value;
}
// Parameter Artist
- else if (messagePart.startsWith("artist%3A")) {
- artist = messagePart.substring("artist%3A".length());
+ else if ("artist".equals(entry.key)) {
+ artist = entry.value;
}
// Parameter Album
- else if (messagePart.startsWith("album%3A")) {
- album = messagePart.substring("album%3A".length());
+ else if ("album".equals(entry.key)) {
+ album = entry.value;
}
// Parameter Genre
- else if (messagePart.startsWith("genre%3A")) {
- genre = messagePart.substring("genre%3A".length());
+ else if ("genre".equals(entry.key)) {
+ genre = entry.value;
}
// Parameter Year
- else if (messagePart.startsWith("year%3A")) {
- year = messagePart.substring("year%3A".length());
+ else if ("year".equals(entry.key)) {
+ year = entry.value;
}
// Parameter artwork_url contains url to cover art
- else if (messagePart.startsWith("artwork_url%3A")) {
- artworkUrl = messagePart.substring("artwork_url%3A".length());
+ else if ("artwork_url".equals(entry.key)) {
+ artworkUrl = entry.value;
}
// When coverart is "1" coverid will contain a unique coverart id
- else if (messagePart.startsWith("coverart%3A")) {
- coverart = "1".matches(messagePart.substring("coverart%3A".length()));
+ else if ("coverart".equals(entry.key)) {
+ coverart = "1".equals(entry.value);
}
// Id for covert art (only valid when coverart is "1")
- else if (messagePart.startsWith("coverid%3A")) {
- coverid = messagePart.substring("coverid%3A".length());
+ else if ("coverid".equals(entry.key)) {
+ coverid = entry.value;
} else {
// Added to be able to see additional status message types
- logger.trace("Unhandled status message type '{}'", messagePart);
+ logger.trace("Unhandled status message type '{}' (value '{}')", entry.key, entry.value);
}
}
final String finalGenre = genre;
final String finalYear = year;
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.coverArtChangeEvent(mac, finalUrl);
- listener.remoteTitleChangeEvent(mac, decode(finalRemoteTitle));
- listener.artistChangeEvent(mac, decode(finalArtist));
- listener.albumChangeEvent(mac, decode(finalAlbum));
- listener.genreChangeEvent(mac, decode(finalGenre));
- listener.yearChangeEvent(mac, decode(finalYear));
- }
+ updatePlayer(listener -> {
+ listener.coverArtChangeEvent(mac, finalUrl);
+ listener.remoteTitleChangeEvent(mac, finalRemoteTitle);
+ listener.artistChangeEvent(mac, finalArtist);
+ listener.albumChangeEvent(mac, finalAlbum);
+ listener.genreChangeEvent(mac, finalGenre);
+ listener.yearChangeEvent(mac, finalYear);
});
}
} else if (artwork_url != null) {
if (artwork_url.startsWith("http")) {
// Typically indicates that cover art is not local to LMS
- url = decode(artwork_url);
- } else if (artwork_url.startsWith("%2F")) {
+ url = artwork_url;
+ } else if (artwork_url.startsWith("/")) {
// Typically used for default coverart for plugins (e.g. Pandora, etc.)
- url = hostAndPort + decode(artwork_url);
+ url = hostAndPort + artwork_url;
} else {
// Another variation of default coverart for plugins (e.g. Pandora, etc.)
- url = hostAndPort + "/" + decode(artwork_url);
+ url = hostAndPort + "/" + artwork_url;
}
}
return url;
// Execute in separate thread to avoid delaying listener
scheduler.execute(() -> updateCustomButtons(mac));
// Set the track duration to 0
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.durationEvent(mac, 0);
- }
- });
+ updatePlayer(listener -> listener.durationEvent(mac, 0));
} else if (action.equals("pause")) {
if (messageParts.length < 4) {
return;
return;
}
final String value = mode;
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.modeChangeEvent(mac, value);
- }
- });
+ updatePlayer(listener -> listener.modeChangeEvent(mac, value));
}
private void handleSourceChangeMessage(String mac, String rawSource) {
String source = URLDecoder.decode(rawSource);
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.sourceChangeEvent(mac, source);
- }
- });
+ updatePlayer(listener -> listener.sourceChangeEvent(mac, source));
}
private void handlePrefsetMessage(final String mac, String[] messageParts) {
String value = messageParts[4];
if (function.equals("power")) {
final boolean power = value.equals("1");
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.powerChangeEvent(mac, power);
- }
- });
+ updatePlayer(listener -> listener.powerChangeEvent(mac, power));
} else if (function.equals("volume")) {
final int volume = (int) Double.parseDouble(value);
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.absoluteVolumeChangeEvent(mac, volume);
- }
- });
+ updatePlayer(listener -> listener.absoluteVolumeChangeEvent(mac, volume));
}
}
}
List<Favorite> favorites = new ArrayList<>();
Favorite f = null;
boolean isTypePlaylist = false;
- for (String part : messageParts) {
+ for (KeyValue entry : decodeKeyValueResponse(messageParts)) {
// Favorite ID (in form xxxxxxxxx.n)
- if (part.startsWith("id%3A")) {
- String id = part.substring("id%3A".length());
- f = new Favorite(id);
+ if ("id".equals(entry.key)) {
+ f = new Favorite(entry.value);
favorites.add(f);
isTypePlaylist = false;
}
// Favorite name
- else if (part.startsWith("name%3A")) {
- String name = decode(part.substring("name%3A".length()));
- if (f != null) {
- f.name = name;
- }
- } else if (part.equals("type%3Aplaylist")) {
+ else if ("name".equals(entry.key)) {
+ f.name = entry.value;
+ } else if ("type".equals(entry.key) && "playlist".equals(entry.value)) {
isTypePlaylist = true;
}
// When "1", favorite is a submenu with additional favorites
- else if (part.startsWith("hasitems%3A")) {
- boolean hasitems = "1".matches(part.substring("hasitems%3A".length()));
+ else if ("hasitems".equals(entry.key)) {
+ boolean hasitems = "1".equals(entry.value);
if (f != null) {
// Except for some favorites (e.g. Spotify) use hasitems:1 and type:playlist
if (hasitems && isTypePlaylist == false) {
}
}
}
- updatePlayersFavoritesList(favorites);
+ updatePlayer(listener -> listener.updateFavoritesListEvent(favorites));
updateChannelFavoritesList(favorites);
}
- private void updatePlayersFavoritesList(List<Favorite> favorites) {
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.updateFavoritesListEvent(favorites);
- }
- });
- }
-
private void updateChannelFavoritesList(List<Favorite> favorites) {
final Channel channel = getThing().getChannel(CHANNEL_FAVORITES_LIST);
if (channel == null) {
}
final String like = likeCommand;
final String unlike = unlikeCommand;
- updatePlayer(new PlayerUpdateEvent() {
- @Override
- public void updateListener(SqueezeBoxPlayerEventListener listener) {
- listener.buttonsChangeEvent(mac, like, unlike);
- }
- });
+ updatePlayer(listener -> listener.buttonsChangeEvent(mac, like, unlike));
}
}