From 45363576428be2ad6bcb3306f3d3b6c22dd33c53 Mon Sep 17 00:00:00 2001 From: _Bastler Date: Thu, 10 Feb 2022 12:01:30 +0100 Subject: [PATCH] update jukebox to play if not running --- .../jitsi/businesslogic/JitsiRoomManager.java | 39 +++--- .../validation/JitsiRoomValidator.java | 8 +- .../jukebox/businesslogic/JukeboxManager.java | 119 +++++++++++++++++- .../businesslogic/model/JukeboxConfig.java | 8 +- .../jukebox/controller/JukeboxController.java | 17 +-- 5 files changed, 153 insertions(+), 38 deletions(-) diff --git a/jitsi/src/main/java/de/bstly/we/jitsi/businesslogic/JitsiRoomManager.java b/jitsi/src/main/java/de/bstly/we/jitsi/businesslogic/JitsiRoomManager.java index c89f5fb..496b65e 100644 --- a/jitsi/src/main/java/de/bstly/we/jitsi/businesslogic/JitsiRoomManager.java +++ b/jitsi/src/main/java/de/bstly/we/jitsi/businesslogic/JitsiRoomManager.java @@ -74,9 +74,9 @@ public class JitsiRoomManager implements SmartInitializingSingleton, UserDataPro @Value("${jitsi.urlFormat:%s/jwt?%s}") private String urlFormat; - /* - * @see org.springframework.beans.factory.SmartInitializingSingleton#afterSingletonsInstantiated() + * @see org.springframework.beans.factory.SmartInitializingSingleton# + * afterSingletonsInstantiated() */ @Override public void afterSingletonsInstantiated() { @@ -110,9 +110,9 @@ public class JitsiRoomManager implements SmartInitializingSingleton, UserDataPro /** * Gets the. * - * @param page the page - * @param size the size - * @param sortBy the sort by + * @param page the page + * @param size the size + * @param sortBy the sort by * @param descending the descending * @return the page */ @@ -124,10 +124,10 @@ public class JitsiRoomManager implements SmartInitializingSingleton, UserDataPro /** * Gets the for user id. * - * @param userId the user id - * @param page the page - * @param size the size - * @param sortBy the sort by + * @param userId the user id + * @param page the page + * @param size the size + * @param sortBy the sort by * @param descending the descending * @return the for user id */ @@ -144,11 +144,11 @@ public class JitsiRoomManager implements SmartInitializingSingleton, UserDataPro /** * Creates the. * - * @param owner the owner - * @param room the room - * @param starts the starts + * @param owner the owner + * @param room the room + * @param starts the starts * @param moderationStarts the moderation starts - * @param expires the expires + * @param expires the expires * @return the jitsi room * @throws JOSEException the JOSE exception */ @@ -213,7 +213,8 @@ public class JitsiRoomManager implements SmartInitializingSingleton, UserDataPro ShortenedUrl shortenedUrl = shortenedUrlManager.get(jitsiRoom.getCode()); if (shortenedUrl != null) { shortenedUrl.setUrl(jitsiRoom.getUrl()); - shortenedUrl.setNote("JitsiRoom: " + jitsiRoom.getRoom()); + shortenedUrl.setNote("JitsiRoom: " + + jitsiRoom.getRoom()); shortenedUrl.setExpires(jitsiRoom.getExpires()); shortenedUrlManager.save(shortenedUrl); jitsiRoom.setOrgUrl(jitsiRoom.getUrl()); @@ -234,8 +235,9 @@ public class JitsiRoomManager implements SmartInitializingSingleton, UserDataPro */ public JitsiRoom createShortenedUrl(JitsiRoom jitsiRoom) { ShortenedUrl shortenedUrl = shortenedUrlManager.create(jitsiRoom.getOwner(), - jitsiRoom.getUrl(), "JitsiRoom: " + jitsiRoom.getRoom(), null, - jitsiRoom.getExpires(), null, false, true); + jitsiRoom.getUrl(), "JitsiRoom: " + + jitsiRoom.getRoom(), + null, jitsiRoom.getExpires(), null, false, true); jitsiRoom.setOrgUrl(jitsiRoom.getUrl()); jitsiRoom.setCode(shortenedUrl.getCode()); jitsiRoom.setUrl(shortenedUrl.getLink()); @@ -246,7 +248,7 @@ public class JitsiRoomManager implements SmartInitializingSingleton, UserDataPro * Delete. * * @param jitsiRoom the jitsi room - * @param quota the quota + * @param quota the quota */ public void delete(JitsiRoom jitsiRoom, boolean quota) { if (quota) { @@ -299,7 +301,6 @@ public class JitsiRoomManager implements SmartInitializingSingleton, UserDataPro } } - /* * @see de.bstly.we.businesslogic.UserDataProvider#getId() */ @@ -308,7 +309,6 @@ public class JitsiRoomManager implements SmartInitializingSingleton, UserDataPro return "jitsiRooms"; } - /* * @see de.bstly.we.businesslogic.UserDataProvider#getUserData(java.lang.Long) */ @@ -321,7 +321,6 @@ public class JitsiRoomManager implements SmartInitializingSingleton, UserDataPro return result; } - /* * @see de.bstly.we.businesslogic.UserDataProvider#purgeUserData(java.lang.Long) */ diff --git a/jitsi/src/main/java/de/bstly/we/jitsi/controller/validation/JitsiRoomValidator.java b/jitsi/src/main/java/de/bstly/we/jitsi/controller/validation/JitsiRoomValidator.java index fd6a3d0..31e1e36 100644 --- a/jitsi/src/main/java/de/bstly/we/jitsi/controller/validation/JitsiRoomValidator.java +++ b/jitsi/src/main/java/de/bstly/we/jitsi/controller/validation/JitsiRoomValidator.java @@ -67,9 +67,9 @@ public class JitsiRoomValidator implements Validator { /** * Validate. * - * @param owner the owner + * @param owner the owner * @param roomName the room name - * @param errors the errors + * @param errors the errors */ public void validate(Long owner, String roomName, Errors errors) { if (owner == null) { @@ -97,7 +97,7 @@ public class JitsiRoomValidator implements Validator { * Validate room. * * @param roomName the room name - * @param errors the errors + * @param errors the errors */ public void validateRoom(String roomName, Errors errors) { for (String systemRoomName : systemPropertyManager.get(RESERVED_JITSI_ROOMS, "") @@ -115,7 +115,7 @@ public class JitsiRoomValidator implements Validator { * Validate expiry. * * @param jitsiRoom the jitsi room - * @param errors the errors + * @param errors the errors */ public void validateExpiry(JitsiRoom jitsiRoom, Errors errors) { diff --git a/jukebox/src/main/java/de/bstly/we/jukebox/businesslogic/JukeboxManager.java b/jukebox/src/main/java/de/bstly/we/jukebox/businesslogic/JukeboxManager.java index 42436ab..0476d90 100644 --- a/jukebox/src/main/java/de/bstly/we/jukebox/businesslogic/JukeboxManager.java +++ b/jukebox/src/main/java/de/bstly/we/jukebox/businesslogic/JukeboxManager.java @@ -3,6 +3,7 @@ */ package de.bstly.we.jukebox.businesslogic; +import java.io.IOException; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Base64; @@ -11,6 +12,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.scheduling.annotation.Scheduled; @@ -58,6 +60,13 @@ public class JukeboxManager implements SmartInitializingSingleton { private JukeboxConfig config; protected static Gson gson = new Gson(); + @Value("${we.bstly.jukebox.daemon.retries:5}") + private int daemonRetries; + + /* + * @see org.springframework.beans.factory.SmartInitializingSingleton# + * afterSingletonsInstantiated() + */ @Override public void afterSingletonsInstantiated() { getConfig(); @@ -239,10 +248,18 @@ public class JukeboxManager implements SmartInitializingSingleton { return JsonNull.INSTANCE; } + /** + * Try start playback. + */ protected void tryStartPlayback() { tryStartPlayback(null); } + /** + * Try start playback. + * + * @param context_uri the context uri + */ protected void tryStartPlayback(String context_uri) { if (!checkToken()) { config.setActive(false); @@ -371,6 +388,8 @@ public class JukeboxManager implements SmartInitializingSingleton { JsonElement status = getStatus(); + boolean queue = true; + // start playing if not running if (status == null || !status.isJsonObject()) { MultiValueMap queryParameters = new LinkedMultiValueMap(); @@ -382,13 +401,19 @@ public class JukeboxManager implements SmartInitializingSingleton { + config.getAccessToken()); JsonObject body = new JsonObject(); - JsonArray uris = new JsonArray(); - uris.add(uri); - body.add("uris", uris); + if (StringUtils.hasText(config.getFallbackContextId())) { + body.addProperty("context_uri", config.getFallbackContextId()); + } else { + JsonArray uris = new JsonArray(); + uris.add(uri); + body.add("uris", uris); + queue = false; + } request.bodyValue(body.toString()); - request.retrieve().bodyToMono(String.class).block(); - } else { + } + + if (queue) { MultiValueMap queryParameters = new LinkedMultiValueMap(); queryParameters.add("uri", uri); queryParameters.add("device_id", config.getDeviceId()); @@ -412,4 +437,88 @@ public class JukeboxManager implements SmartInitializingSingleton { } } + /** + * Check devices. + */ + public void checkDevices() { + checkDevices(0); + } + + /** + * Check devices. + * + * @param tries the tries + */ + public void checkDevices(int tries) { + if (tries > daemonRetries) { + logger.warn("Could not setup spotifyd device!"); + return; + } + + if (!checkToken()) { + logger.warn("Failed token check!"); + return; + } + + if (!StringUtils.hasText(config.getDeviceId())) { + logger.info("No device ID set."); + return; + } + + WebClient.RequestBodySpec request = webClient.method(HttpMethod.GET) + .uri(uriBuilder -> uriBuilder.path("/v1/me/player/devices").build()) + .header(HttpHeaders.AUTHORIZATION, "Bearer " + + config.getAccessToken()); + + boolean deviceFound = false; + + String jsonString = request.retrieve().bodyToMono(String.class).block(); + + if (StringUtils.hasText(jsonString)) { + JsonElement response = JsonParser.parseString(jsonString); + + if (response != null && !response.isJsonNull() && response.isJsonObject()) { + JsonArray devices = response.getAsJsonObject().getAsJsonArray("devices"); + for (JsonElement deviceElement : devices) { + JsonObject device = deviceElement.getAsJsonObject(); + if (device.has("id") + && device.get("id").getAsString().equals(config.getDeviceId())) { + deviceFound = true; + return; + } + } + } + } + + if (!deviceFound) { + String command = "sudo /bin/systemctl restart spotifyd.service"; + try { + Runtime.getRuntime().exec(command); + } catch (IOException e) { + logger.warn("Could execute command: " + + command, e); + return; + } + + try { + tries++; + Thread.sleep(5000 * tries); + checkDevices(tries); + } catch (InterruptedException e) { + logger.warn("Could not sleep!"); + return; + } + } + } + + /** + * Check spotify D. + */ + @Scheduled(cron = "${we.bstly.jukebox.daemon.cron:0 */15 * * * * }") + public void checkSpotifyD() { + if (config.isActive()) { + checkDevices(); + } + } + } diff --git a/jukebox/src/main/java/de/bstly/we/jukebox/businesslogic/model/JukeboxConfig.java b/jukebox/src/main/java/de/bstly/we/jukebox/businesslogic/model/JukeboxConfig.java index d8c3b13..fdb2c41 100644 --- a/jukebox/src/main/java/de/bstly/we/jukebox/businesslogic/model/JukeboxConfig.java +++ b/jukebox/src/main/java/de/bstly/we/jukebox/businesslogic/model/JukeboxConfig.java @@ -203,14 +203,18 @@ public class JukeboxConfig { } /** - * @return the fallbackContextId + * Gets the fallback context id. + * + * @return the fallback context id */ public String getFallbackContextId() { return fallbackContextId; } /** - * @param fallbackContextId the fallbackContextId to set + * Sets the fallback context id. + * + * @param fallbackContextId the new fallback context id */ public void setFallbackContextId(String fallbackContextId) { this.fallbackContextId = fallbackContextId; diff --git a/jukebox/src/main/java/de/bstly/we/jukebox/controller/JukeboxController.java b/jukebox/src/main/java/de/bstly/we/jukebox/controller/JukeboxController.java index e26a881..5afbaf9 100644 --- a/jukebox/src/main/java/de/bstly/we/jukebox/controller/JukeboxController.java +++ b/jukebox/src/main/java/de/bstly/we/jukebox/controller/JukeboxController.java @@ -52,6 +52,8 @@ public class JukeboxController extends BaseController { /** * Check queue permission. + * + * @return the json element */ protected JsonElement checkQueuePermission() { if (!permissionManager.hasPermission(getCurrentUserId(), ParteyPermissions.PARTEY)) { @@ -101,8 +103,9 @@ public class JukeboxController extends BaseController { /** * Check. * + * @param response the response * @throws JsonIOException the json IO exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException Signals that an I/O exception has occurred. */ @PreAuthorize("isAuthenticated()") @GetMapping @@ -126,11 +129,11 @@ public class JukeboxController extends BaseController { /** * Search. * - * @param query the query - * @param offset the offset + * @param query the query + * @param offset the offset * @param response the response * @throws JsonIOException the json IO exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException Signals that an I/O exception has occurred. */ @PreAuthorize("isAuthenticated()") @GetMapping("/search") @@ -162,7 +165,7 @@ public class JukeboxController extends BaseController { * * @param response the response * @throws JsonIOException the json IO exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException Signals that an I/O exception has occurred. */ @PreAuthorize("isAuthenticated()") @GetMapping("/current") @@ -194,10 +197,10 @@ public class JukeboxController extends BaseController { /** * Last. * - * @param limit the limit + * @param limit the limit * @param response the response * @throws JsonIOException the json IO exception - * @throws IOException Signals that an I/O exception has occurred. + * @throws IOException Signals that an I/O exception has occurred. */ @PreAuthorize("isAuthenticated()") @GetMapping("/last")