2 * Copyright (c) 2010-2022 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.sonos.internal.handler;
15 import java.io.IOException;
16 import java.util.ArrayList;
17 import java.util.List;
19 import org.eclipse.jdt.annotation.NonNullByDefault;
20 import org.eclipse.jdt.annotation.Nullable;
21 import org.openhab.binding.sonos.internal.SonosMetaData;
22 import org.openhab.binding.sonos.internal.SonosXMLParser;
23 import org.openhab.core.io.net.http.HttpUtil;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
28 * The {@link SonosMediaInformation} is responsible for extracting media information from XML metadata
30 * @author Laurent Garnier - Initial contribution
33 public class SonosMediaInformation {
35 private static final int HTTP_TIMEOUT = 5000;
37 private static final Logger LOGGER = LoggerFactory.getLogger(SonosMediaInformation.class);
39 private @Nullable String artist;
40 private @Nullable String album;
41 private @Nullable String title;
42 private @Nullable String combinedInfo;
43 private boolean needsUpdate;
45 public SonosMediaInformation() {
49 public SonosMediaInformation(boolean needsUpdate) {
50 this(null, null, null, null, needsUpdate);
53 public SonosMediaInformation(@Nullable String artist, @Nullable String album, @Nullable String title,
54 @Nullable String combinedInfo, boolean needsUpdate) {
58 this.combinedInfo = combinedInfo;
59 this.needsUpdate = needsUpdate;
62 public @Nullable String getArtist() {
66 public @Nullable String getAlbum() {
70 public @Nullable String getTitle() {
74 public @Nullable String getCombinedInfo() {
78 public boolean needsUpdate() {
82 public static SonosMediaInformation parseTuneInMediaInfo(@Nullable String opmlUrl, @Nullable String radioTitle,
83 @Nullable SonosMetaData trackMetaData) {
85 String combinedInfo = null;
86 if (opmlUrl != null) {
87 String response = null;
89 response = HttpUtil.executeUrl("GET", opmlUrl, HTTP_TIMEOUT);
90 } catch (IOException e) {
91 LOGGER.debug("Request to device failed", e);
94 if (response != null) {
95 List<String> fields = SonosXMLParser.getRadioTimeFromXML(response);
97 if (!fields.isEmpty()) {
99 for (String field : fields) {
100 if (combinedInfo.isEmpty()) {
101 // radio name should be first field
104 combinedInfo += " - ";
106 combinedInfo += field;
108 return new SonosMediaInformation(null, null, title, combinedInfo, true);
112 if (radioTitle != null && !radioTitle.isEmpty()) {
114 combinedInfo = title;
115 if (trackMetaData != null && !trackMetaData.getStreamContent().isEmpty()) {
116 combinedInfo += " - " + trackMetaData.getStreamContent();
118 return new SonosMediaInformation(null, null, title, combinedInfo, true);
120 return new SonosMediaInformation(false);
123 public static SonosMediaInformation parseRadioAppMediaInfo(@Nullable String radioTitle,
124 @Nullable SonosMetaData trackMetaData) {
125 if (radioTitle != null && !radioTitle.isEmpty()) {
126 String artist = null;
128 String title = radioTitle;
129 String combinedInfo = title;
130 if (trackMetaData != null) {
131 String[] contents = trackMetaData.getStreamContent().split("\\|");
132 String contentTitle = null;
133 for (int i = 0; i < contents.length; i++) {
134 if (contents[i].startsWith("TITLE ")) {
135 contentTitle = contents[i].substring(6).trim();
137 if (contents[i].startsWith("ARTIST ")) {
138 artist = contents[i].substring(7).trim();
140 if (contents[i].startsWith("ALBUM ")) {
141 album = contents[i].substring(6).trim();
144 if ((artist == null || artist.isEmpty()) && contentTitle != null && !contentTitle.isEmpty()
145 && !contentTitle.startsWith("Advertisement_")) {
146 // Try to extract artist and song title from contentTitle
147 int idx = contentTitle.indexOf(" - ");
149 artist = contentTitle.substring(0, idx);
150 title = contentTitle.substring(idx + 3);
152 } else if (artist != null && !artist.isEmpty() && album != null && !album.isEmpty()
153 && contentTitle != null && !contentTitle.isEmpty()) {
154 title = contentTitle;
156 if (artist != null && !artist.isEmpty()) {
157 combinedInfo += " - " + artist;
159 if (album != null && !album.isEmpty()) {
160 combinedInfo += " - " + album;
162 if (!radioTitle.equals(title)) {
163 combinedInfo += " - " + title;
164 } else if (contentTitle != null && !contentTitle.isEmpty()
165 && !contentTitle.startsWith("Advertisement_")) {
166 combinedInfo += " - " + contentTitle;
169 return new SonosMediaInformation(artist, album, title, combinedInfo, true);
171 return new SonosMediaInformation(false);
174 public static SonosMediaInformation parseTrack(@Nullable SonosMetaData trackMetaData) {
175 if (trackMetaData != null) {
176 List<String> infos = new ArrayList<>();
177 String artist = !trackMetaData.getAlbumArtist().isEmpty() ? trackMetaData.getAlbumArtist()
178 : trackMetaData.getCreator();
179 if (!artist.isEmpty()) {
182 String album = trackMetaData.getAlbum();
183 if (!album.isEmpty()) {
186 String title = trackMetaData.getTitle();
187 if (!title.isEmpty()) {
190 return new SonosMediaInformation(artist, album, title, String.join(" - ", infos), true);
192 return new SonosMediaInformation(false);
195 public static SonosMediaInformation parseTrackTitle(@Nullable SonosMetaData trackMetaData) {
196 if (trackMetaData != null) {
197 String title = trackMetaData.getTitle();
198 return new SonosMediaInformation(null, null, title, title, true);
200 return new SonosMediaInformation(false);