diff --git a/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/discovery/SqueezeBoxPlayerDiscoveryParticipant.java b/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/discovery/SqueezeBoxPlayerDiscoveryParticipant.java index b6a749f5c2ff6..5cd1b03bdb7b4 100644 --- a/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/discovery/SqueezeBoxPlayerDiscoveryParticipant.java +++ b/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/discovery/SqueezeBoxPlayerDiscoveryParticipant.java @@ -85,31 +85,32 @@ public void cancelRequestPlayerJob() { public void playerAdded(SqueezeBoxPlayer player) { ThingUID bridgeUID = squeezeBoxServerHandler.getThing().getUID(); - ThingUID thingUID = new ThingUID(SQUEEZEBOXPLAYER_THING_TYPE, bridgeUID, player.macAddress.replace(":", "")); + ThingUID thingUID = new ThingUID(SQUEEZEBOXPLAYER_THING_TYPE, bridgeUID, + player.getMacAddress().replace(":", "")); if (!playerThingExists(thingUID)) { - logger.debug("player added {} : {} ", player.macAddress, player.name); + logger.debug("player added {} : {} ", player.getMacAddress(), player.getName()); Map properties = new HashMap<>(1); String representationPropertyName = "mac"; - properties.put(representationPropertyName, player.macAddress); + properties.put(representationPropertyName, player.getMacAddress()); // Added other properties - properties.put("modelId", player.model); - properties.put("name", player.name); - properties.put("uid", player.uuid); - properties.put("ip", player.ipAddr); + properties.put("modelId", player.getModel()); + properties.put("name", player.getName()); + properties.put("uid", player.getUuid()); + properties.put("ip", player.getIpAddr()); DiscoveryResult discoveryResult = DiscoveryResultBuilder.create(thingUID).withProperties(properties) - .withRepresentationProperty(representationPropertyName).withBridge(bridgeUID).withLabel(player.name) - .build(); + .withRepresentationProperty(representationPropertyName).withBridge(bridgeUID) + .withLabel(player.getName()).build(); thingDiscovered(discoveryResult); } } private boolean playerThingExists(ThingUID newThingUID) { - return squeezeBoxServerHandler.getThing().getThing(newThingUID) != null; + return squeezeBoxServerHandler.getThing().getThing(newThingUID) != null ? true : false; } /** diff --git a/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/handler/SqueezeBoxPlayer.java b/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/handler/SqueezeBoxPlayer.java index 955fe41e20199..1a47fc71e9754 100644 --- a/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/handler/SqueezeBoxPlayer.java +++ b/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/handler/SqueezeBoxPlayer.java @@ -12,33 +12,110 @@ */ package org.openhab.binding.squeezebox.internal.handler; -import org.eclipse.jdt.annotation.NonNullByDefault; -import org.eclipse.jdt.annotation.Nullable; - /** * Represents a Squeeze Player * * @author Dan Cunningham - Initial contribution * */ -@NonNullByDefault public class SqueezeBoxPlayer { - public final String macAddress; - @Nullable - public final String name; - @Nullable - public final String ipAddr; - @Nullable - public final String model; - @Nullable - public final String uuid; - - public SqueezeBoxPlayer(String mac, @Nullable String name, @Nullable String ip, @Nullable String model, - @Nullable String uuid) { - this.macAddress = mac; + public String macAddress; + public String name; + public String ipAddr; + public String model; + public String uuid; + + public SqueezeBoxPlayer() { + super(); + } + + /** + * UID of player + * + * @return + */ + public String getUuid() { + return uuid; + } + + /** + * UID of player + * + * @param uuid + */ + public void setUuid(String uuid) { + this.uuid = uuid; + } + + /** + * Mac Address of player + * + * @param macAddress + */ + public String getMacAddress() { + return macAddress; + } + + /** + * Mac Address of player + * + * @param macAddress + */ + public void setMacAddress(String macAddress) { + this.macAddress = macAddress; + } + + /** + * The name (label) of a player + * + * @return + */ + public String getName() { + return name; + } + + /** + * The name (label) of a player + * + * @param name + */ + public void setName(String name) { this.name = name; - this.ipAddr = ip; + } + + /** + * The ip address of a player + * + * @return + */ + public String getIpAddr() { + return ipAddr; + } + + /** + * The ip address of a player + * + * @param ipAddr + */ + public void setIpAddr(String ipAddr) { + this.ipAddr = ipAddr; + } + + /** + * The type of player + * + * @return + */ + public String getModel() { + return model; + } + + /** + * The type of player + * + * @param model + */ + public void setModel(String model) { this.model = model; - this.uuid = uuid; } } diff --git a/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/handler/SqueezeBoxPlayerHandler.java b/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/handler/SqueezeBoxPlayerHandler.java index 2750de9b811c0..a94461276336e 100644 --- a/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/handler/SqueezeBoxPlayerHandler.java +++ b/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/handler/SqueezeBoxPlayerHandler.java @@ -577,52 +577,83 @@ private void updateChannel(String mac, String channelID, State state) { * @return */ int currentVolume() { - return cachedStateAsInt(CHANNEL_VOLUME); + if (stateMap.containsKey(CHANNEL_VOLUME)) { + return ((DecimalType) stateMap.get(CHANNEL_VOLUME)).intValue(); + } else { + return 0; + } } int currentPlayingTime() { - return cachedStateAsInt(CHANNEL_CURRENT_PLAYING_TIME); + if (stateMap.containsKey(CHANNEL_CURRENT_PLAYING_TIME)) { + return ((DecimalType) stateMap.get(CHANNEL_CURRENT_PLAYING_TIME)).intValue(); + } else { + return 0; + } } int currentNumberPlaylistTracks() { - return cachedStateAsInt(CHANNEL_NUMBER_PLAYLIST_TRACKS); + if (stateMap.containsKey(CHANNEL_NUMBER_PLAYLIST_TRACKS)) { + return ((DecimalType) stateMap.get(CHANNEL_NUMBER_PLAYLIST_TRACKS)).intValue(); + } else { + return 0; + } } int currentPlaylistIndex() { - return cachedStateAsInt(CHANNEL_PLAYLIST_INDEX); + if (stateMap.containsKey(CHANNEL_PLAYLIST_INDEX)) { + return ((DecimalType) stateMap.get(CHANNEL_PLAYLIST_INDEX)).intValue(); + } else { + return 0; + } } boolean currentPower() { - return cachedStateAsBoolean(CHANNEL_POWER, OnOffType.ON); + if (stateMap.containsKey(CHANNEL_POWER)) { + return (stateMap.get(CHANNEL_POWER).equals(OnOffType.ON) ? true : false); + } else { + return false; + } } boolean currentStop() { - return cachedStateAsBoolean(CHANNEL_STOP, OnOffType.ON); + if (stateMap.containsKey(CHANNEL_STOP)) { + return (stateMap.get(CHANNEL_STOP).equals(OnOffType.ON) ? true : false); + } else { + return false; + } } boolean currentControl() { - return cachedStateAsBoolean(CHANNEL_CONTROL, PlayPauseType.PLAY); + if (stateMap.containsKey(CHANNEL_CONTROL)) { + return (stateMap.get(CHANNEL_CONTROL).equals(PlayPauseType.PLAY) ? true : false); + } else { + return false; + } } boolean currentMute() { - return cachedStateAsBoolean(CHANNEL_MUTE, OnOffType.ON); + if (stateMap.containsKey(CHANNEL_MUTE)) { + return (stateMap.get(CHANNEL_MUTE).equals(OnOffType.ON) ? true : false); + } else { + return false; + } } int currentShuffle() { - return cachedStateAsInt(CHANNEL_CURRENT_PLAYLIST_SHUFFLE); + if (stateMap.containsKey(CHANNEL_CURRENT_PLAYLIST_SHUFFLE)) { + return ((DecimalType) stateMap.get(CHANNEL_CURRENT_PLAYLIST_SHUFFLE)).intValue(); + } else { + return 0; + } } int currentRepeat() { - return cachedStateAsInt(CHANNEL_CURRENT_PLAYLIST_REPEAT); - } - - private boolean cachedStateAsBoolean(String key, @NonNull State activeState) { - return activeState.equals(stateMap.get(key)); - } - - private int cachedStateAsInt(String key) { - State state = stateMap.get(key); - return state instanceof DecimalType ? ((DecimalType) state).intValue() : 0; + if (stateMap.containsKey(CHANNEL_CURRENT_PLAYLIST_REPEAT)) { + return ((DecimalType) stateMap.get(CHANNEL_CURRENT_PLAYLIST_REPEAT)).intValue(); + } else { + return 0; + } } /** diff --git a/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/handler/SqueezeBoxPlayerState.java b/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/handler/SqueezeBoxPlayerState.java index a8223f29ec7d2..82603069f32e2 100644 --- a/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/handler/SqueezeBoxPlayerState.java +++ b/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/handler/SqueezeBoxPlayerState.java @@ -60,7 +60,7 @@ boolean isPlaying() { } boolean isShuffling() { - return savedShuffle != 0; + return savedShuffle == 0 ? false : true; } int getShuffle() { @@ -68,7 +68,7 @@ int getShuffle() { } boolean isRepeating() { - return savedRepeat != 0; + return savedRepeat == 0 ? false : true; } int getRepeat() { diff --git a/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/handler/SqueezeBoxServerHandler.java b/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/handler/SqueezeBoxServerHandler.java index a7f9a36ae23b9..fc5194d1817bb 100644 --- a/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/handler/SqueezeBoxServerHandler.java +++ b/bundles/org.openhab.binding.squeezebox/src/main/java/org/openhab/binding/squeezebox/internal/handler/SqueezeBoxServerHandler.java @@ -37,9 +37,7 @@ 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; @@ -537,65 +535,69 @@ private String encode(String raw) { } } - @NonNullByDefault - private class KeyValue { - final String key; - final String value; - - public KeyValue(String key, String value) { - this.key = key; - this.value = value; - } - }; - - private List decodeKeyValueResponse(String[] response) { - final List 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 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 - final Map keysAndValues = decodeKeyValueResponse(playerParams.split("\\s")).stream() - .collect(Collectors.toMap(kv -> kv.key, kv -> kv.value)); - final String macAddress = keysAndValues.get("playerid"); + 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; + } + } // if none found then ignore this set of params if (macAddress == null) { continue; } - 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); + 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); + } + } } // Save player if we haven't seen it yet if (!players.containsKey(macAddress)) { players.put(macAddress, player); - updatePlayer(listener -> listener.playerAdded(player)); + updatePlayer(new PlayerUpdateEvent() { + @Override + public void updateListener(SqueezeBoxPlayerEventListener listener) { + listener.playerAdded(player); + } + }); // tell the server we want to subscribe to player updates - sendCommand(player.macAddress + " status - 1 subscribe:10 tags:yagJlNKjc"); + sendCommand(player.getMacAddress() + " status - 1 subscribe:10 tags:yagJlNKjc"); } } for (final SqueezeBoxPlayer player : players.values()) { - final boolean connected = connectedPlayers.contains(player.macAddress); - updatePlayer(listener -> listener.connectedStateChangeEvent(player.macAddress, connected)); + final String mac = player.getMacAddress(); + final boolean connected = connectedPlayers.contains(mac); + updatePlayer(listener -> listener.connectedStateChangeEvent(mac, connected)); } } @@ -628,7 +630,12 @@ private void handlePlayerUpdate(String message) { break; case "ir": final String ircode = messageParts[2]; - updatePlayer(listener -> listener.irCodeChangeEvent(mac, ircode)); + updatePlayer(new PlayerUpdateEvent() { + @Override + public void updateListener(SqueezeBoxPlayerEventListener listener) { + listener.irCodeChangeEvent(mac, ircode); + } + }); break; default: logger.trace("Unhandled player update message type '{}'.", messageType); @@ -644,20 +651,23 @@ private void handleMixerMessage(String mac, String[] messageParts) { switch (action) { case "volume": String volumeStringValue = decode(messageParts[3]); - 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); + 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); } - } catch (NumberFormatException e) { - logger.warn("Unable to parse volume [{}] received from mixer message.", volumeStringValue, - e); } }); break; @@ -693,89 +703,148 @@ private void handleStatusMessage(final String mac, String[] messageParts) { String coverid = null; String artworkUrl = null; - for (KeyValue entry : decodeKeyValueResponse(messageParts)) { + for (String messagePart : messageParts) { // Parameter Power - if ("power".equals(entry.key)) { - final boolean power = "1".equals(entry.value); - updatePlayer(listener -> listener.powerChangeEvent(mac, 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); + } + }); } // Parameter Volume - else if ("mixer volume".equals(entry.key)) { - final int volume = (int) Double.parseDouble(entry.value); - updatePlayer(listener -> listener.absoluteVolumeChangeEvent(mac, 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); + } + }); } // Parameter Mode - else if ("mode".equals(entry.key)) { - updatePlayer(listener -> listener.modeChangeEvent(mac, entry.value)); + 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); + } + }); } // Parameter Playing Time - else if ("time".equals(entry.key)) { - final int time = (int) Double.parseDouble(entry.value); - updatePlayer(listener -> listener.currentPlayingTimeEvent(mac, 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); + } + }); } // Parameter duration - else if ("duration".equals(entry.key)) { - final int duration = (int) Double.parseDouble(entry.value); - updatePlayer(listener -> listener.durationEvent(mac, 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); + } + }); } // Parameter Playing Playlist Index - else if ("playlist_cur_index".equals(entry.key)) { - final int index = (int) Double.parseDouble(entry.value); - updatePlayer(listener -> listener.currentPlaylistIndexEvent(mac, 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); + } + }); } // Parameter Playlist Number Tracks - else if ("playlist_tracks".equals(entry.key)) { - final int track = (int) Double.parseDouble(entry.value); - updatePlayer(listener -> listener.numberPlaylistTracksEvent(mac, track)); + 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); + } + }); } // Parameter Playlist Repeat Mode - else if ("playlist repeat".equals(entry.key)) { - final int repeat = (int) Double.parseDouble(entry.value); - updatePlayer(listener -> listener.currentPlaylistRepeatEvent(mac, repeat)); + 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); + } + }); } // Parameter Playlist Shuffle Mode - else if ("playlist shuffle".equals(entry.key)) { - final int shuffle = (int) Double.parseDouble(entry.value); - updatePlayer(listener -> listener.currentPlaylistShuffleEvent(mac, shuffle)); + 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); + } + }); } // Parameter Title - else if ("title".equals(entry.key)) { - updatePlayer(listener -> listener.titleChangeEvent(mac, entry.value)); + 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)); + } + }); } // Parameter Remote Title (radio) - else if ("remote_title".equals(entry.key)) { - remoteTitle = entry.value; + else if (messagePart.startsWith("remote_title%3A")) { + remoteTitle = messagePart.substring("remote_title%3A".length()); } // Parameter Artist - else if ("artist".equals(entry.key)) { - artist = entry.value; + else if (messagePart.startsWith("artist%3A")) { + artist = messagePart.substring("artist%3A".length()); } // Parameter Album - else if ("album".equals(entry.key)) { - album = entry.value; + else if (messagePart.startsWith("album%3A")) { + album = messagePart.substring("album%3A".length()); } // Parameter Genre - else if ("genre".equals(entry.key)) { - genre = entry.value; + else if (messagePart.startsWith("genre%3A")) { + genre = messagePart.substring("genre%3A".length()); } // Parameter Year - else if ("year".equals(entry.key)) { - year = entry.value; + else if (messagePart.startsWith("year%3A")) { + year = messagePart.substring("year%3A".length()); } // Parameter artwork_url contains url to cover art - else if ("artwork_url".equals(entry.key)) { - artworkUrl = entry.value; + else if (messagePart.startsWith("artwork_url%3A")) { + artworkUrl = messagePart.substring("artwork_url%3A".length()); } // When coverart is "1" coverid will contain a unique coverart id - else if ("coverart".equals(entry.key)) { - coverart = "1".equals(entry.value); + else if (messagePart.startsWith("coverart%3A")) { + coverart = "1".matches(messagePart.substring("coverart%3A".length())); } // Id for covert art (only valid when coverart is "1") - else if ("coverid".equals(entry.key)) { - coverid = entry.value; + else if (messagePart.startsWith("coverid%3A")) { + coverid = messagePart.substring("coverid%3A".length()); } else { // Added to be able to see additional status message types - logger.trace("Unhandled status message type '{}' (value '{}')", entry.key, entry.value); + logger.trace("Unhandled status message type '{}'", messagePart); } } @@ -786,13 +855,16 @@ else if ("coverid".equals(entry.key)) { final String finalGenre = genre; final String finalYear = year; - 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); + 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)); + } }); } @@ -816,13 +888,13 @@ private String constructCoverArtUrl(String mac, boolean coverart, String coverid } else if (artwork_url != null) { if (artwork_url.startsWith("http")) { // Typically indicates that cover art is not local to LMS - url = artwork_url; - } else if (artwork_url.startsWith("/")) { + url = decode(artwork_url); + } else if (artwork_url.startsWith("%2F")) { // Typically used for default coverart for plugins (e.g. Pandora, etc.) - url = hostAndPort + artwork_url; + url = hostAndPort + decode(artwork_url); } else { // Another variation of default coverart for plugins (e.g. Pandora, etc.) - url = hostAndPort + "/" + artwork_url; + url = hostAndPort + "/" + decode(artwork_url); } } return url; @@ -839,7 +911,12 @@ private void handlePlaylistMessage(final String mac, String[] messageParts) { // Execute in separate thread to avoid delaying listener scheduler.execute(() -> updateCustomButtons(mac)); // Set the track duration to 0 - updatePlayer(listener -> listener.durationEvent(mac, 0)); + updatePlayer(new PlayerUpdateEvent() { + @Override + public void updateListener(SqueezeBoxPlayerEventListener listener) { + listener.durationEvent(mac, 0); + } + }); } else if (action.equals("pause")) { if (messageParts.length < 4) { return; @@ -858,12 +935,22 @@ private void handlePlaylistMessage(final String mac, String[] messageParts) { return; } final String value = mode; - updatePlayer(listener -> listener.modeChangeEvent(mac, value)); + updatePlayer(new PlayerUpdateEvent() { + @Override + public void updateListener(SqueezeBoxPlayerEventListener listener) { + listener.modeChangeEvent(mac, value); + } + }); } private void handleSourceChangeMessage(String mac, String rawSource) { String source = URLDecoder.decode(rawSource); - updatePlayer(listener -> listener.sourceChangeEvent(mac, source)); + updatePlayer(new PlayerUpdateEvent() { + @Override + public void updateListener(SqueezeBoxPlayerEventListener listener) { + listener.sourceChangeEvent(mac, source); + } + }); } private void handlePrefsetMessage(final String mac, String[] messageParts) { @@ -876,10 +963,20 @@ private void handlePrefsetMessage(final String mac, String[] messageParts) { String value = messageParts[4]; if (function.equals("power")) { final boolean power = value.equals("1"); - updatePlayer(listener -> listener.powerChangeEvent(mac, power)); + updatePlayer(new PlayerUpdateEvent() { + @Override + public void updateListener(SqueezeBoxPlayerEventListener listener) { + listener.powerChangeEvent(mac, power); + } + }); } else if (function.equals("volume")) { final int volume = (int) Double.parseDouble(value); - updatePlayer(listener -> listener.absoluteVolumeChangeEvent(mac, volume)); + updatePlayer(new PlayerUpdateEvent() { + @Override + public void updateListener(SqueezeBoxPlayerEventListener listener) { + listener.absoluteVolumeChangeEvent(mac, volume); + } + }); } } } @@ -899,22 +996,26 @@ private void handleFavorites(String message) { List favorites = new ArrayList<>(); Favorite f = null; boolean isTypePlaylist = false; - for (KeyValue entry : decodeKeyValueResponse(messageParts)) { + for (String part : messageParts) { // Favorite ID (in form xxxxxxxxx.n) - if ("id".equals(entry.key)) { - f = new Favorite(entry.value); + if (part.startsWith("id%3A")) { + String id = part.substring("id%3A".length()); + f = new Favorite(id); favorites.add(f); isTypePlaylist = false; } // Favorite name - else if ("name".equals(entry.key)) { - f.name = entry.value; - } else if ("type".equals(entry.key) && "playlist".equals(entry.value)) { + 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")) { isTypePlaylist = true; } // When "1", favorite is a submenu with additional favorites - else if ("hasitems".equals(entry.key)) { - boolean hasitems = "1".equals(entry.value); + else if (part.startsWith("hasitems%3A")) { + boolean hasitems = "1".matches(part.substring("hasitems%3A".length())); if (f != null) { // Except for some favorites (e.g. Spotify) use hasitems:1 and type:playlist if (hasitems && isTypePlaylist == false) { @@ -925,10 +1026,19 @@ else if ("hasitems".equals(entry.key)) { } } } - updatePlayer(listener -> listener.updateFavoritesListEvent(favorites)); + updatePlayersFavoritesList(favorites); updateChannelFavoritesList(favorites); } + private void updatePlayersFavoritesList(List favorites) { + updatePlayer(new PlayerUpdateEvent() { + @Override + public void updateListener(SqueezeBoxPlayerEventListener listener) { + listener.updateFavoritesListEvent(favorites); + } + }); + } + private void updateChannelFavoritesList(List favorites) { final Channel channel = getThing().getChannel(CHANNEL_FAVORITES_LIST); if (channel == null) { @@ -988,7 +1098,12 @@ private void updateCustomButtons(final String mac) { } final String like = likeCommand; final String unlike = unlikeCommand; - updatePlayer(listener -> listener.buttonsChangeEvent(mac, like, unlike)); + updatePlayer(new PlayerUpdateEvent() { + @Override + public void updateListener(SqueezeBoxPlayerEventListener listener) { + listener.buttonsChangeEvent(mac, like, unlike); + } + }); } }