Skip to content

Commit

Permalink
cache deezer api token & license token
Browse files Browse the repository at this point in the history
  • Loading branch information
topi314 committed Dec 20, 2023
1 parent f05b1fe commit 5a24554
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.sedmelluq.discord.lavaplayer.track.*;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.HttpClientBuilder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand All @@ -25,13 +26,16 @@
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class DeezerAudioSourceManager extends ExtendedAudioSourceManager implements HttpConfigurable, AudioSearchManager {

Expand All @@ -49,6 +53,7 @@ public class DeezerAudioSourceManager extends ExtendedAudioSourceManager impleme

private final String masterDecryptionKey;
private final HttpInterfaceManager httpInterfaceManager;
private Tokens tokens;

public DeezerAudioSourceManager(String masterDecryptionKey) {
if (masterDecryptionKey == null || masterDecryptionKey.isEmpty()) {
Expand All @@ -58,6 +63,43 @@ public DeezerAudioSourceManager(String masterDecryptionKey) {
this.httpInterfaceManager = HttpClientTools.createDefaultThreadLocalManager();
}

private void refreshSession() throws IOException{
var getSessionID = new HttpPost(DeezerAudioSourceManager.PRIVATE_API_BASE + "?method=deezer.ping&input=3&api_version=1.0&api_token=");
var json = LavaSrcTools.fetchResponseAsJson(this.getHttpInterface(), getSessionID);

checkResponse(json, "Failed to get session ID: ");
var sessionID = json.get("results").get("SESSION").text();

var getUserToken = new HttpPost(DeezerAudioSourceManager.PRIVATE_API_BASE + "?method=deezer.getUserData&input=3&api_version=1.0&api_token=");
getUserToken.setHeader("Cookie", "sid=" + sessionID);
json = LavaSrcTools.fetchResponseAsJson(this.getHttpInterface(), getUserToken);

checkResponse(json, "Failed to get user token: ");
this.tokens = new Tokens(
json.get("results").get("checkForm").text(),
json.get("results").get("USER").get("OPTIONS").get("license_token").text(),
Instant.now().plus(3600, ChronoUnit.SECONDS)
);
}

public Tokens getTokens() throws IOException{
if (this.tokens == null || Instant.now().isAfter(this.tokens.expireAt)) {
this.refreshSession();
}
return this.tokens;
}

static void checkResponse(JsonBrowser json, String message) throws IllegalStateException {
if (json == null) {
throw new IllegalStateException(message + "No response");
}
var errors = json.get("data").index(0).get("errors").values();
if (!errors.isEmpty()) {
var errorsStr = errors.stream().map(error -> error.get("code").text() + ": " + error.get("message").text()).collect(Collectors.joining(", "));
throw new IllegalStateException(message + errorsStr);
}
}

@NotNull
@Override
public String getSourceName() {
Expand Down Expand Up @@ -361,4 +403,16 @@ public HttpInterface getHttpInterface() {
return this.httpInterfaceManager.getInterface();
}

public static class Tokens {
public String api;
public String license;
public Instant expireAt;

public Tokens(String api,String license, Instant expireAt) {
this.api = api;
this.license = license;
this.expireAt = expireAt;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,46 +36,22 @@ public DeezerAudioTrack(AudioTrackInfo trackInfo, String albumName, String album
}

private URI getTrackMediaURI() throws IOException, URISyntaxException {
var getSessionID = new HttpPost(DeezerAudioSourceManager.PRIVATE_API_BASE + "?method=deezer.ping&input=3&api_version=1.0&api_token=");
var json = LavaSrcTools.fetchResponseAsJson(this.sourceManager.getHttpInterface(), getSessionID);

this.checkResponse(json, "Failed to get session ID: ");
var sessionID = json.get("results").get("SESSION").text();

var getUserToken = new HttpPost(DeezerAudioSourceManager.PRIVATE_API_BASE + "?method=deezer.getUserData&input=3&api_version=1.0&api_token=");
getUserToken.setHeader("Cookie", "sid=" + sessionID);
json = LavaSrcTools.fetchResponseAsJson(this.sourceManager.getHttpInterface(), getUserToken);

this.checkResponse(json, "Failed to get user token: ");
var userLicenseToken = json.get("results").get("USER").get("OPTIONS").get("license_token").text();
var apiToken = json.get("results").get("checkForm").text();

var getTrackToken = new HttpPost(DeezerAudioSourceManager.PRIVATE_API_BASE + "?method=song.getData&input=3&api_version=1.0&api_token=" + apiToken);
var tokens = this.sourceManager.getTokens();
var getTrackToken = new HttpPost(DeezerAudioSourceManager.PRIVATE_API_BASE + "?method=song.getData&input=3&api_version=1.0&api_token=" + tokens.api);
getTrackToken.setEntity(new StringEntity("{\"sng_id\":\"" + this.trackInfo.identifier + "\"}", ContentType.APPLICATION_JSON));
json = LavaSrcTools.fetchResponseAsJson(this.sourceManager.getHttpInterface(), getTrackToken);
var json = LavaSrcTools.fetchResponseAsJson(this.sourceManager.getHttpInterface(), getTrackToken);

this.checkResponse(json, "Failed to get track token: ");
DeezerAudioSourceManager.checkResponse(json, "Failed to get track token: ");
var trackToken = json.get("results").get("TRACK_TOKEN").text();

var getMediaURL = new HttpPost(DeezerAudioSourceManager.MEDIA_BASE + "/get_url");
getMediaURL.setEntity(new StringEntity("{\"license_token\":\"" + userLicenseToken + "\",\"media\": [{\"type\": \"FULL\",\"formats\": [{\"cipher\": \"BF_CBC_STRIPE\", \"format\": \"MP3_128\"}]}],\"track_tokens\": [\"" + trackToken + "\"]}", ContentType.APPLICATION_JSON));
getMediaURL.setEntity(new StringEntity("{\"license_token\":\"" + tokens.license + "\",\"media\": [{\"type\": \"FULL\",\"formats\": [{\"cipher\": \"BF_CBC_STRIPE\", \"format\": \"MP3_128\"}]}],\"track_tokens\": [\"" + trackToken + "\"]}", ContentType.APPLICATION_JSON));
json = LavaSrcTools.fetchResponseAsJson(this.sourceManager.getHttpInterface(), getMediaURL);

this.checkResponse(json, "Failed to get media URL: ");
DeezerAudioSourceManager.checkResponse(json, "Failed to get media URL: ");
return new URI(json.get("data").index(0).get("media").index(0).get("sources").index(0).get("url").text());
}

private void checkResponse(JsonBrowser json, String message) throws IllegalStateException {
if (json == null) {
throw new IllegalStateException(message + "No response");
}
var errors = json.get("data").index(0).get("errors").values();
if (!errors.isEmpty()) {
var errorsStr = errors.stream().map(error -> error.get("code").text() + ": " + error.get("message").text()).collect(Collectors.joining(", "));
throw new IllegalStateException(message + errorsStr);
}
}

private byte[] getTrackDecryptionKey() throws NoSuchAlgorithmException {
var md5 = Hex.encodeHex(MessageDigest.getInstance("MD5").digest(this.trackInfo.identifier.getBytes()), true);
var master_key = this.sourceManager.getMasterDecryptionKey().getBytes();
Expand Down

0 comments on commit 5a24554

Please sign in to comment.