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 015f392
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
import com.sedmelluq.discord.lavaplayer.tools.io.HttpInterface;
import com.sedmelluq.discord.lavaplayer.tools.io.HttpInterfaceManager;
import com.sedmelluq.discord.lavaplayer.track.*;
import kotlin.Pair;
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 +27,17 @@
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.concurrent.TimeUnit;
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,13 +55,52 @@ public class DeezerAudioSourceManager extends ExtendedAudioSourceManager impleme

private final String masterDecryptionKey;
private final HttpInterfaceManager httpInterfaceManager;
private String apiToken;
private String licenseToken;
private Instant expires;

public DeezerAudioSourceManager(String masterDecryptionKey) {
if (masterDecryptionKey == null || masterDecryptionKey.isEmpty()) {
throw new IllegalArgumentException("Deezer master key must be set");
}
this.masterDecryptionKey = masterDecryptionKey;
this.httpInterfaceManager = HttpClientTools.createDefaultThreadLocalManager();
this.expires = Instant.ofEpochMilli(0);
}

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.licenseToken = json.get("results").get("USER").get("OPTIONS").get("license_token").text();
this.apiToken = json.get("results").get("checkForm").text();
this.expires = Instant.now().plus(3600, ChronoUnit.SECONDS);
}

public Pair<String, String> getTokens() throws IOException{
if (Instant.now().isAfter(this.expires)) {
this.refreshSession();
}
return new Pair<>(this.apiToken, this.licenseToken);
}

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
Expand Down
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.getFirst());
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.getSecond() + "\",\"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 015f392

Please sign in to comment.