diff --git a/application/pom.xml b/application/pom.xml
index c9b51c4..ed72c85 100755
--- a/application/pom.xml
+++ b/application/pom.xml
@@ -42,6 +42,11 @@
webstly-jitsi
${revision}
+
+ de.bstly.we
+ webstly-jukebox
+ ${revision}
+
de.bstly.we
webstly-membership
diff --git a/core/src/main/java/de/bstly/we/businesslogic/SystemPropertyManager.java b/core/src/main/java/de/bstly/we/businesslogic/SystemPropertyManager.java
index 0efb4ff..ab6b93c 100755
--- a/core/src/main/java/de/bstly/we/businesslogic/SystemPropertyManager.java
+++ b/core/src/main/java/de/bstly/we/businesslogic/SystemPropertyManager.java
@@ -42,12 +42,13 @@ public class SystemPropertyManager {
/**
* Gets the.
*
- * @param key the key
+ * @param key the key
* @param defaultValue the default value
* @return the string
*/
public String get(String key, String defaultValue) {
- return systemPropertyRepository.findById(key).orElse(new SystemProperty(key, defaultValue)).getValue();
+ return systemPropertyRepository.findById(key).orElse(new SystemProperty(key, defaultValue))
+ .getValue();
}
/**
@@ -63,7 +64,7 @@ public class SystemPropertyManager {
/**
* Gets the boolean.
*
- * @param key the key
+ * @param key the key
* @param defaultValue the default value
* @return the boolean
*/
@@ -84,7 +85,7 @@ public class SystemPropertyManager {
/**
* Gets the integer.
*
- * @param key the key
+ * @param key the key
* @param defaultValue the default value
* @return the integer
*/
@@ -105,7 +106,7 @@ public class SystemPropertyManager {
/**
* Gets the long.
*
- * @param key the key
+ * @param key the key
* @param defaultValue the default value
* @return the long
*/
@@ -116,7 +117,7 @@ public class SystemPropertyManager {
/**
* Adds the.
*
- * @param key the key
+ * @param key the key
* @param value the value
*/
public void add(String key, String value) {
@@ -128,7 +129,7 @@ public class SystemPropertyManager {
/**
* Update.
*
- * @param key the key
+ * @param key the key
* @param value the value
*/
public void update(String key, String value) {
@@ -139,4 +140,12 @@ public class SystemPropertyManager {
systemPropertyRepository.save(systemProperty);
}
+ public void set(String key, String value) {
+ if (systemPropertyRepository.existsById(key)) {
+ update(key, value);
+ } else {
+ add(key, value);
+ }
+ }
+
}
diff --git a/jukebox/pom.xml b/jukebox/pom.xml
new file mode 100644
index 0000000..3626cf8
--- /dev/null
+++ b/jukebox/pom.xml
@@ -0,0 +1,21 @@
+
+ 4.0.0
+
+ de.bstly.we
+ webstly-main
+ ${revision}
+
+
+ jukebox
+ webstly-jukebox
+
+
+
+ de.bstly.we
+ webstly-partey
+ ${revision}
+
+
+
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
new file mode 100644
index 0000000..8fc8687
--- /dev/null
+++ b/jukebox/src/main/java/de/bstly/we/jukebox/businesslogic/JukeboxManager.java
@@ -0,0 +1,280 @@
+/**
+ *
+ */
+package de.bstly.we.jukebox.businesslogic;
+
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Base64;
+
+import org.springframework.beans.factory.SmartInitializingSingleton;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.util.StringUtils;
+import org.springframework.web.reactive.function.client.WebClient;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonNull;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+
+import de.bstly.we.businesslogic.SystemPropertyManager;
+import de.bstly.we.jukebox.businesslogic.model.JukeboxConfig;
+import reactor.core.publisher.Mono;
+
+/**
+ * The Class JukeboxManager.
+ */
+@Component
+public class JukeboxManager implements SmartInitializingSingleton {
+ public static final String CLIENT_ID = "jukebox.client_id";
+ public static final String CLIENT_SECRET = "jukebox.client_secret";
+ public static final String REDIRECT_URL = "jukebox.redirect_url";
+ public static final String ACCOUNT_URL = "jukebox.account_url";
+ public static final String API_URL = "jukebox.api_url";
+ public static final String ACTIVE = "jukebox.active";
+ public static final String ACCESS_TOKEN = "jukebox.access_token";
+ public static final String REFRESH_TOKEN = "jukebox.refresh_token";
+ public static final String EXPIRES = "jukebox.expires";
+
+ @Autowired
+ private SystemPropertyManager systemPropertyManager;
+
+ protected WebClient webClient;
+ private JukeboxConfig config;
+
+ /*
+ * @see org.springframework.beans.factory.SmartInitializingSingleton#
+ * afterSingletonsInstantiated()
+ */
+ /*
+ * @see org.springframework.beans.factory.SmartInitializingSingleton#
+ * afterSingletonsInstantiated()
+ */
+ /*
+ * @see org.springframework.beans.factory.SmartInitializingSingleton#
+ * afterSingletonsInstantiated()
+ */
+ @Override
+ public void afterSingletonsInstantiated() {
+ getConfig();
+
+ if (StringUtils.hasText(config.getApiUrl())) {
+ webClient = WebClient.builder().baseUrl(config.getApiUrl())
+ .defaultHeader(HttpHeaders.CONTENT_TYPE, "application/json").build();
+ }
+ }
+
+ /**
+ * Gets the config.
+ *
+ * @return the config
+ */
+ public JukeboxConfig getConfig() {
+ if (config == null) {
+ config = new JukeboxConfig();
+ config.setClientId(systemPropertyManager.get(CLIENT_ID));
+ config.setClientSecret(systemPropertyManager.get(CLIENT_SECRET));
+ config.setRedirectUrl(systemPropertyManager.get(REDIRECT_URL));
+ config.setApiUrl(systemPropertyManager.get(API_URL));
+ config.setAccountUrl(systemPropertyManager.get(ACCOUNT_URL));
+ config.setActive(systemPropertyManager.getBoolean(ACTIVE, false));
+ config.setAccessToken(systemPropertyManager.get(ACCESS_TOKEN));
+ config.setRefreshToken(systemPropertyManager.get(REFRESH_TOKEN));
+ if (StringUtils.hasText(systemPropertyManager.get(EXPIRES))) {
+ config.setExpires(Instant.parse(systemPropertyManager.get(EXPIRES)));
+ }
+ }
+
+ return config;
+ }
+
+ /**
+ * Sets the config.
+ *
+ * @param config the config
+ * @return the jukebox config
+ */
+ public JukeboxConfig setConfig(JukeboxConfig config) {
+ this.config = config;
+
+ systemPropertyManager.set(CLIENT_ID, config.getClientId());
+ systemPropertyManager.set(CLIENT_SECRET, config.getClientSecret());
+ systemPropertyManager.set(REDIRECT_URL, config.getRedirectUrl());
+ systemPropertyManager.set(API_URL, config.getApiUrl());
+ systemPropertyManager.set(ACCOUNT_URL, config.getAccountUrl());
+ systemPropertyManager.set(ACTIVE, String.valueOf(config.isActive()));
+ systemPropertyManager.set(ACCESS_TOKEN, config.getAccessToken());
+ systemPropertyManager.set(REFRESH_TOKEN, config.getRefreshToken());
+
+ if (config.getExpires() != null) {
+ systemPropertyManager.set(EXPIRES, config.getExpires().toString());
+ }
+
+ if (StringUtils.hasText(config.getApiUrl())) {
+ webClient = WebClient.builder().baseUrl(config.getApiUrl())
+ .defaultHeader(HttpHeaders.CONTENT_TYPE, "application/json").build();
+ }
+
+ return config;
+ }
+
+ /**
+ * Check token.
+ *
+ * @return true, if successful
+ */
+ protected boolean checkToken() {
+ if (webClient == null || !StringUtils.hasText(config.getRefreshToken())) {
+ return false;
+ }
+
+ if (!StringUtils.hasText(config.getAccessToken()) || config.getExpires() == null
+ || config.getExpires().isBefore(Instant.now())) {
+
+ String authHeader = "Basic "
+ + new String(Base64.getEncoder()
+ .encode(String
+ .format("%s:%s", config.getClientId(), config.getClientSecret())
+ .getBytes()));
+ WebClient.RequestBodySpec request = WebClient.builder().baseUrl(config.getAccountUrl())
+ .build().method(HttpMethod.POST)
+ .uri(uriBuilder -> uriBuilder.path("/api/token").build())
+ .header(HttpHeaders.AUTHORIZATION, authHeader)
+ .header(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
+
+ request.bodyValue("grant_type=refresh_token&refresh_token="
+ + config.getRefreshToken());
+
+ String jsonString = request.retrieve().bodyToMono(String.class).block();
+
+ if (StringUtils.hasText(jsonString)) {
+ JsonObject response = JsonParser.parseString(jsonString).getAsJsonObject();
+ config.setAccessToken(response.get("access_token").getAsString());
+ config.setExpires(Instant.now().plus(response.get("expires_in").getAsLong(),
+ ChronoUnit.SECONDS));
+
+ if (response.has("refresh_token")) {
+ config.setRefreshToken(response.get("refresh_token").getAsString());
+ }
+
+ return true;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Gets the status.
+ *
+ * @return the status
+ */
+ public JsonElement getStatus() {
+ if (!checkToken()) {
+ return null;
+ }
+
+ WebClient.RequestBodySpec request = webClient.method(HttpMethod.GET)
+ .uri(uriBuilder -> uriBuilder.path("/v1/me/player").build())
+ .header(HttpHeaders.AUTHORIZATION, "Bearer "
+ + config.getAccessToken());
+
+ String jsonString = request.retrieve().bodyToMono(String.class).block();
+
+ if (StringUtils.hasText(jsonString)) {
+ JsonElement status = JsonParser.parseString(jsonString);
+ if (config.isActive()) {
+ boolean disable = false;
+ if (status == null || status.isJsonNull() || !status.isJsonObject()) {
+ disable = true;
+ } else {
+ JsonObject statusObject = status.getAsJsonObject();
+ if (!statusObject.has("device")) {
+ disable = true;
+ }
+ JsonObject device = statusObject.getAsJsonObject("device");
+ if (!device.has("is_private_session")
+ || !device.get("is_private_session").getAsBoolean()) {
+ disable = true;
+ }
+ }
+ if (disable) {
+ config.setActive(false);
+ systemPropertyManager.set(ACTIVE, String.valueOf(config.isActive()));
+ }
+ }
+ return status;
+ }
+
+ return JsonNull.INSTANCE;
+ }
+
+ /**
+ * Search track.
+ *
+ * @param query the query
+ * @param offset the offset
+ * @return the json element
+ */
+ public JsonElement searchTrack(String query, Long offset) {
+ if (!checkToken()) {
+ return null;
+ }
+
+ MultiValueMap queryParameters = new LinkedMultiValueMap();
+ queryParameters.add("q", query);
+ queryParameters.add("type", "track");
+ if (offset != null) {
+ queryParameters.add("offset", String.valueOf(offset));
+ }
+ WebClient.RequestBodySpec request = webClient.method(HttpMethod.GET).uri(
+ uriBuilder -> uriBuilder.path("/v1/search").queryParams(queryParameters).build())
+ .header(HttpHeaders.AUTHORIZATION, "Bearer "
+ + config.getAccessToken());
+
+ String jsonString = request.retrieve().bodyToMono(String.class)
+ .onErrorResume(e -> Mono.just(e.getMessage())).block();
+
+ if (StringUtils.hasText(jsonString)) {
+ return JsonParser.parseString(jsonString);
+ }
+
+ return null;
+ }
+
+ /**
+ * Adds the to queue.
+ *
+ * @param uri the uri
+ */
+ public void addToQueue(String uri) {
+ if (!checkToken()) {
+ return;
+ }
+
+ MultiValueMap queryParameters = new LinkedMultiValueMap();
+ queryParameters.add("uri", uri);
+ WebClient.RequestBodySpec request = webClient.method(HttpMethod.POST)
+ .uri(uriBuilder -> uriBuilder.path("/v1/me/player/queue")
+ .queryParams(queryParameters).build())
+ .header(HttpHeaders.AUTHORIZATION, "Bearer "
+ + config.getAccessToken());
+
+ request.retrieve().bodyToMono(String.class).block();
+ }
+
+ /**
+ * Check active.
+ */
+ @Scheduled(cron = "${we.bstly.jukebox.cron:0 */5 0 * * * }")
+ public void checkActive() {
+ getStatus();
+ }
+
+}
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
new file mode 100644
index 0000000..04084a1
--- /dev/null
+++ b/jukebox/src/main/java/de/bstly/we/jukebox/businesslogic/model/JukeboxConfig.java
@@ -0,0 +1,181 @@
+/**
+ *
+ */
+package de.bstly.we.jukebox.businesslogic.model;
+
+import java.time.Instant;
+
+/**
+ * The Class JukeboxConfig.
+ */
+public class JukeboxConfig {
+
+ private String clientId;
+ private String clientSecret;
+ private String redirectUrl;
+ private String apiUrl;
+ private String accountUrl;
+ private boolean active;
+ private String accessToken;
+ private String refreshToken;
+ private Instant expires;
+
+ /**
+ * Gets the client id.
+ *
+ * @return the client id
+ */
+ public String getClientId() {
+ return clientId;
+ }
+
+ /**
+ * Sets the client id.
+ *
+ * @param clientId the new client id
+ */
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ /**
+ * Gets the client secret.
+ *
+ * @return the client secret
+ */
+ public String getClientSecret() {
+ return clientSecret;
+ }
+
+ /**
+ * Sets the client secret.
+ *
+ * @param clientSecret the new client secret
+ */
+ public void setClientSecret(String clientSecret) {
+ this.clientSecret = clientSecret;
+ }
+
+ /**
+ * Gets the redirect url.
+ *
+ * @return the redirect url
+ */
+ public String getRedirectUrl() {
+ return redirectUrl;
+ }
+
+ /**
+ * Sets the redirect url.
+ *
+ * @param redirectUrl the new redirect url
+ */
+ public void setRedirectUrl(String redirectUrl) {
+ this.redirectUrl = redirectUrl;
+ }
+
+ /**
+ * Gets the api url.
+ *
+ * @return the api url
+ */
+ public String getApiUrl() {
+ return apiUrl;
+ }
+
+ /**
+ * Sets the api url.
+ *
+ * @param apiUrl the new api url
+ */
+ public void setApiUrl(String apiUrl) {
+ this.apiUrl = apiUrl;
+ }
+
+ /**
+ * @return the accountUrl
+ */
+ public String getAccountUrl() {
+ return accountUrl;
+ }
+
+ /**
+ * @param accountUrl the accountUrl to set
+ */
+ public void setAccountUrl(String accountUrl) {
+ this.accountUrl = accountUrl;
+ }
+
+ /**
+ * Checks if is active.
+ *
+ * @return true, if is active
+ */
+ public boolean isActive() {
+ return active;
+ }
+
+ /**
+ * Sets the active.
+ *
+ * @param active the new active
+ */
+ public void setActive(boolean active) {
+ this.active = active;
+ }
+
+ /**
+ * Gets the access token.
+ *
+ * @return the access token
+ */
+ public String getAccessToken() {
+ return accessToken;
+ }
+
+ /**
+ * Sets the access token.
+ *
+ * @param accessToken the new access token
+ */
+ public void setAccessToken(String accessToken) {
+ this.accessToken = accessToken;
+ }
+
+ /**
+ * Gets the refresh token.
+ *
+ * @return the refresh token
+ */
+ public String getRefreshToken() {
+ return refreshToken;
+ }
+
+ /**
+ * Sets the refresh token.
+ *
+ * @param refreshToken the new refresh token
+ */
+ public void setRefreshToken(String refreshToken) {
+ this.refreshToken = refreshToken;
+ }
+
+ /**
+ * Gets the expires.
+ *
+ * @return the expires
+ */
+ public Instant getExpires() {
+ return expires;
+ }
+
+ /**
+ * Sets the expires.
+ *
+ * @param expires the new expires
+ */
+ public void setExpires(Instant expires) {
+ this.expires = expires;
+ }
+
+}
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
new file mode 100644
index 0000000..0a6408f
--- /dev/null
+++ b/jukebox/src/main/java/de/bstly/we/jukebox/controller/JukeboxController.java
@@ -0,0 +1,143 @@
+/**
+ *
+ */
+package de.bstly.we.jukebox.controller;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Map;
+import java.util.Optional;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.beust.jcommander.internal.Maps;
+import com.google.gson.Gson;
+import com.google.gson.JsonIOException;
+
+import de.bstly.we.businesslogic.PermissionManager;
+import de.bstly.we.controller.BaseController;
+import de.bstly.we.controller.support.EntityResponseStatusException;
+import de.bstly.we.jukebox.businesslogic.JukeboxManager;
+import de.bstly.we.partey.businesslogic.ParteyPermissions;
+
+/**
+ * The Class JukeboxController.
+ */
+
+@RestController
+@RequestMapping("/jukebox")
+public class JukeboxController extends BaseController {
+
+ @Autowired
+ private PermissionManager permissionManager;
+ @Autowired
+ private JukeboxManager jukeboxManager;
+ private Gson gson = new Gson();
+
+ private Map queueList = Maps.newHashMap();
+ private Map searchList = Maps.newHashMap();
+
+ /**
+ * Check queue permission.
+ */
+ protected void checkQueuePermission() {
+ if (!permissionManager.hasPermission(getCurrentUserId(), ParteyPermissions.PARTEY)) {
+ throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
+ }
+
+ if (!jukeboxManager.getConfig().isActive()) {
+ throw new EntityResponseStatusException(HttpStatus.GONE);
+ }
+
+ jukeboxManager.getStatus();
+
+ if (!jukeboxManager.getConfig().isActive()) {
+ throw new EntityResponseStatusException(HttpStatus.GONE);
+ }
+
+ if (queueList.containsKey(getCurrentUserId()) && queueList.get(getCurrentUserId())
+ .isAfter(Instant.now().minus(1, ChronoUnit.MINUTES))) {
+ throw new EntityResponseStatusException(
+ Duration.between(queueList.get(getCurrentUserId()), Instant.now()).getSeconds(),
+ HttpStatus.PAYMENT_REQUIRED);
+ }
+ }
+
+ /**
+ * Check search permission.
+ */
+ protected void checkSearchPermission() {
+ if (!permissionManager.hasPermission(getCurrentUserId(), ParteyPermissions.PARTEY)) {
+ throw new EntityResponseStatusException(HttpStatus.FORBIDDEN);
+ }
+
+ if (!jukeboxManager.getConfig().isActive()) {
+ throw new EntityResponseStatusException(HttpStatus.GONE);
+ }
+
+ if (searchList.containsKey(getCurrentUserId()) && searchList.get(getCurrentUserId())
+ .isAfter(Instant.now().minus(3, ChronoUnit.SECONDS))) {
+ throw new EntityResponseStatusException(Duration
+ .between(searchList.get(getCurrentUserId()), Instant.now()).getSeconds(),
+ HttpStatus.PAYMENT_REQUIRED);
+ }
+ }
+
+ /**
+ * Check.
+ *
+ * @throws JsonIOException the json IO exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ @PreAuthorize("isAuthenticated()")
+ @GetMapping
+ public void check() throws JsonIOException, IOException {
+ checkQueuePermission();
+ }
+
+ /**
+ * Search.
+ *
+ * @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.
+ */
+ @PreAuthorize("isAuthenticated()")
+ @GetMapping("/search")
+ public void search(@RequestParam("q") String query,
+ @RequestParam("offset") Optional offset, HttpServletResponse response)
+ throws JsonIOException, IOException {
+ checkSearchPermission();
+ response.setContentType("application/json");
+ response.setCharacterEncoding("UTF-8");
+ gson.toJson(jukeboxManager.searchTrack(query, offset.orElse(null)), response.getWriter());
+ searchList.put(getCurrentUserId(), Instant.now());
+ }
+
+ /**
+ * Queue.
+ *
+ * @param uri the uri
+ */
+ @PreAuthorize("isAuthenticated()")
+ @PostMapping("/queue")
+ public void queue(@RequestParam("uri") String uri) {
+ checkQueuePermission();
+ jukeboxManager.addToQueue(uri);
+ queueList.put(getCurrentUserId(), Instant.now());
+ }
+
+}
diff --git a/jukebox/src/main/java/de/bstly/we/jukebox/controller/JukeboxManagementController.java b/jukebox/src/main/java/de/bstly/we/jukebox/controller/JukeboxManagementController.java
new file mode 100644
index 0000000..2613da4
--- /dev/null
+++ b/jukebox/src/main/java/de/bstly/we/jukebox/controller/JukeboxManagementController.java
@@ -0,0 +1,138 @@
+/**
+ *
+ */
+package de.bstly.we.jukebox.controller;
+
+import java.io.IOException;
+import java.util.Optional;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonIOException;
+
+import de.bstly.we.controller.BaseController;
+import de.bstly.we.jukebox.businesslogic.JukeboxManager;
+import de.bstly.we.jukebox.businesslogic.model.JukeboxConfig;
+
+/**
+ * The Class JukeboxManagementController.
+ */
+
+@RestController
+@RequestMapping("/jukebox/manage")
+public class JukeboxManagementController extends BaseController {
+
+ @Autowired
+ private JukeboxManager jukeboxManager;
+ private Gson gson = new Gson();
+
+ /**
+ * Gets the config.
+ *
+ * @return the config
+ */
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
+ @GetMapping("/config")
+ public JukeboxConfig getConfig() {
+ return jukeboxManager.getConfig();
+ }
+
+ /**
+ * Sets the config.
+ *
+ * @param config the config
+ * @return the jukebox config
+ */
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
+ @PostMapping("/config")
+ public JukeboxConfig setConfig(@RequestBody JukeboxConfig config) {
+ return jukeboxManager.setConfig(config);
+ }
+
+ /**
+ * Sets the config.
+ *
+ * @param config the config
+ * @return the jukebox config
+ */
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
+ @PutMapping
+ public void setActive() {
+ JukeboxConfig config = getConfig();
+ config.setActive(true);
+ jukeboxManager.setConfig(config);
+ }
+
+ /**
+ * Sets the config.
+ *
+ * @param config the config
+ * @return the jukebox config
+ */
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
+ @DeleteMapping
+ public void disable() {
+ JukeboxConfig config = getConfig();
+ config.setActive(false);
+ jukeboxManager.setConfig(config);
+ }
+
+ /**
+ * Gets the status.
+ *
+ * @param response the response
+ * @return the status
+ * @throws JsonIOException the json IO exception
+ * @throws IOException Signals that an I/O exception has occurred.
+ */
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
+ @GetMapping()
+ public void getStatus(HttpServletResponse response) throws JsonIOException, IOException {
+ response.setContentType("application/json");
+ response.setCharacterEncoding("UTF-8");
+ gson.toJson(jukeboxManager.getStatus(), response.getWriter());
+ }
+
+ /**
+ * Search.
+ *
+ * @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.
+ */
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
+ @GetMapping("/search")
+ public void search(@RequestParam("q") String query,
+ @RequestParam("offset") Optional offset, HttpServletResponse response)
+ throws JsonIOException, IOException {
+ response.setContentType("application/json");
+ response.setCharacterEncoding("UTF-8");
+ gson.toJson(jukeboxManager.searchTrack(query, offset.orElse(null)), response.getWriter());
+ }
+
+ /**
+ * Queue.
+ *
+ * @param uri the uri
+ */
+ @PreAuthorize("hasRole('ROLE_ADMIN')")
+ @PostMapping("/queue")
+ public void queue(@RequestParam("uri") String uri) {
+ jukeboxManager.addToQueue(uri);
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index a42d21a..b199dd7 100755
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,7 @@
UTF-8
11
- 1.4.2-SNAPSHOT
+ 1.4.3-SNAPSHOT
@@ -30,6 +30,7 @@
i18n
invite
jitsi
+ jukebox
jwt
membership
minetest