add jukebox feature
This commit is contained in:
@@ -42,6 +42,11 @@
|
|||||||
<artifactId>webstly-jitsi</artifactId>
|
<artifactId>webstly-jitsi</artifactId>
|
||||||
<version>${revision}</version>
|
<version>${revision}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>de.bstly.we</groupId>
|
||||||
|
<artifactId>webstly-jukebox</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>de.bstly.we</groupId>
|
<groupId>de.bstly.we</groupId>
|
||||||
<artifactId>webstly-membership</artifactId>
|
<artifactId>webstly-membership</artifactId>
|
||||||
|
|||||||
@@ -42,12 +42,13 @@ public class SystemPropertyManager {
|
|||||||
/**
|
/**
|
||||||
* Gets the.
|
* Gets the.
|
||||||
*
|
*
|
||||||
* @param key the key
|
* @param key the key
|
||||||
* @param defaultValue the default value
|
* @param defaultValue the default value
|
||||||
* @return the string
|
* @return the string
|
||||||
*/
|
*/
|
||||||
public String get(String key, String defaultValue) {
|
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.
|
* Gets the boolean.
|
||||||
*
|
*
|
||||||
* @param key the key
|
* @param key the key
|
||||||
* @param defaultValue the default value
|
* @param defaultValue the default value
|
||||||
* @return the boolean
|
* @return the boolean
|
||||||
*/
|
*/
|
||||||
@@ -84,7 +85,7 @@ public class SystemPropertyManager {
|
|||||||
/**
|
/**
|
||||||
* Gets the integer.
|
* Gets the integer.
|
||||||
*
|
*
|
||||||
* @param key the key
|
* @param key the key
|
||||||
* @param defaultValue the default value
|
* @param defaultValue the default value
|
||||||
* @return the integer
|
* @return the integer
|
||||||
*/
|
*/
|
||||||
@@ -105,7 +106,7 @@ public class SystemPropertyManager {
|
|||||||
/**
|
/**
|
||||||
* Gets the long.
|
* Gets the long.
|
||||||
*
|
*
|
||||||
* @param key the key
|
* @param key the key
|
||||||
* @param defaultValue the default value
|
* @param defaultValue the default value
|
||||||
* @return the long
|
* @return the long
|
||||||
*/
|
*/
|
||||||
@@ -116,7 +117,7 @@ public class SystemPropertyManager {
|
|||||||
/**
|
/**
|
||||||
* Adds the.
|
* Adds the.
|
||||||
*
|
*
|
||||||
* @param key the key
|
* @param key the key
|
||||||
* @param value the value
|
* @param value the value
|
||||||
*/
|
*/
|
||||||
public void add(String key, String value) {
|
public void add(String key, String value) {
|
||||||
@@ -128,7 +129,7 @@ public class SystemPropertyManager {
|
|||||||
/**
|
/**
|
||||||
* Update.
|
* Update.
|
||||||
*
|
*
|
||||||
* @param key the key
|
* @param key the key
|
||||||
* @param value the value
|
* @param value the value
|
||||||
*/
|
*/
|
||||||
public void update(String key, String value) {
|
public void update(String key, String value) {
|
||||||
@@ -139,4 +140,12 @@ public class SystemPropertyManager {
|
|||||||
systemPropertyRepository.save(systemProperty);
|
systemPropertyRepository.save(systemProperty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void set(String key, String value) {
|
||||||
|
if (systemPropertyRepository.existsById(key)) {
|
||||||
|
update(key, value);
|
||||||
|
} else {
|
||||||
|
add(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>de.bstly.we</groupId>
|
||||||
|
<artifactId>webstly-main</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<name>jukebox</name>
|
||||||
|
<artifactId>webstly-jukebox</artifactId>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>de.bstly.we</groupId>
|
||||||
|
<artifactId>webstly-partey</artifactId>
|
||||||
|
<version>${revision}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
</project>
|
||||||
@@ -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<String, String> queryParameters = new LinkedMultiValueMap<String, String>();
|
||||||
|
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<String, String> queryParameters = new LinkedMultiValueMap<String, String>();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<Long, Instant> queueList = Maps.newHashMap();
|
||||||
|
private Map<Long, Instant> 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<Long> 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+138
@@ -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<Long> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<java.version>11</java.version>
|
<java.version>11</java.version>
|
||||||
<revision>1.4.2-SNAPSHOT</revision>
|
<revision>1.4.3-SNAPSHOT</revision>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
<module>i18n</module>
|
<module>i18n</module>
|
||||||
<module>invite</module>
|
<module>invite</module>
|
||||||
<module>jitsi</module>
|
<module>jitsi</module>
|
||||||
|
<module>jukebox</module>
|
||||||
<module>jwt</module>
|
<module>jwt</module>
|
||||||
<module>membership</module>
|
<module>membership</module>
|
||||||
<module>minetest</module>
|
<module>minetest</module>
|
||||||
|
|||||||
Reference in New Issue
Block a user