forked from brahmkshatriya/echo-extension-template
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
## Clear App Data before use!! - Added more proxy options
- Loading branch information
1 parent
5f69246
commit 3325da5
Showing
14 changed files
with
824 additions
and
600 deletions.
There are no files selected for viewing
676 changes: 85 additions & 591 deletions
676
ext/src/main/java/dev/brahmkshatriya/echo/extension/DeezerApi.kt
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
ext/src/main/java/dev/brahmkshatriya/echo/extension/api/DeezerAlbum.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package dev.brahmkshatriya.echo.extension.api | ||
|
||
import dev.brahmkshatriya.echo.common.models.Album | ||
import dev.brahmkshatriya.echo.extension.DeezerApi | ||
import kotlinx.serialization.json.Json | ||
import kotlinx.serialization.json.JsonObject | ||
import kotlinx.serialization.json.buildJsonObject | ||
import kotlinx.serialization.json.put | ||
|
||
class DeezerAlbum(private val deezerApi: DeezerApi, private val json: Json) { | ||
|
||
suspend fun album(album: Album, language: String): JsonObject { | ||
val jsonData = deezerApi.callApi( | ||
method = "deezer.pageAlbum", | ||
params = buildJsonObject { | ||
put("alb_id", album.id) | ||
put("header", true) | ||
put("lang", language.substringBefore("-")) | ||
} | ||
) | ||
return json.decodeFromString<JsonObject>(jsonData) | ||
} | ||
|
||
suspend fun getAlbums(userId: String): JsonObject { | ||
val jsonData = deezerApi.callApi( | ||
method = "deezer.pageProfile", | ||
params = buildJsonObject { | ||
put("user_id", userId) | ||
put("tab", "albums") | ||
put("nb", 50) | ||
} | ||
) | ||
return json.decodeFromString<JsonObject>(jsonData) | ||
} | ||
|
||
suspend fun addFavoriteAlbum(id: String) { | ||
deezerApi.callApi( | ||
method = "album.addFavorite", | ||
params = buildJsonObject { | ||
put("ALB_ID", id) | ||
} | ||
) | ||
} | ||
|
||
suspend fun removeFavoriteAlbum(id: String) { | ||
deezerApi.callApi( | ||
method = "album.deleteFavorite", | ||
params = buildJsonObject { | ||
put("ALB_ID", id) | ||
} | ||
) | ||
} | ||
} |
60 changes: 60 additions & 0 deletions
60
ext/src/main/java/dev/brahmkshatriya/echo/extension/api/DeezerArtist.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package dev.brahmkshatriya.echo.extension.api | ||
|
||
import dev.brahmkshatriya.echo.extension.DeezerApi | ||
import kotlinx.serialization.json.Json | ||
import kotlinx.serialization.json.JsonObject | ||
import kotlinx.serialization.json.buildJsonObject | ||
import kotlinx.serialization.json.put | ||
import kotlinx.serialization.json.putJsonObject | ||
|
||
class DeezerArtist(private val deezerApi: DeezerApi, private val json: Json) { | ||
|
||
suspend fun artist(id: String, language: String): JsonObject { | ||
val jsonData = deezerApi.callApi( | ||
method = "deezer.pageArtist", | ||
params = buildJsonObject { | ||
put("art_id", id) | ||
put ("lang", language.substringBefore("-")) | ||
} | ||
) | ||
return json.decodeFromString<JsonObject>(jsonData) | ||
} | ||
|
||
suspend fun getArtists(userId: String): JsonObject { | ||
val jsonData = deezerApi.callApi( | ||
method = "deezer.pageProfile", | ||
params = buildJsonObject { | ||
put("nb", 40) | ||
put ("tab", "artists") | ||
put("user_id", userId) | ||
} | ||
) | ||
return json.decodeFromString<JsonObject>(jsonData) | ||
} | ||
|
||
suspend fun followArtist(id: String) { | ||
deezerApi.callApi( | ||
method = "artist.addFavorite", | ||
params = buildJsonObject { | ||
put("ART_ID", id) | ||
putJsonObject("CTXT") { | ||
put("id", id) | ||
put("t", "artist_smartradio") | ||
} | ||
} | ||
) | ||
} | ||
|
||
suspend fun unfollowArtist(id: String) { | ||
deezerApi.callApi( | ||
method = "artist.deleteFavorite", | ||
params = buildJsonObject { | ||
put("ART_ID", id) | ||
putJsonObject("CTXT") { | ||
put("id", id) | ||
put("t", "artist_smartradio") | ||
} | ||
} | ||
) | ||
} | ||
} |
123 changes: 123 additions & 0 deletions
123
ext/src/main/java/dev/brahmkshatriya/echo/extension/api/DeezerLogin.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package dev.brahmkshatriya.echo.extension.api | ||
|
||
import dev.brahmkshatriya.echo.common.models.ImageHolder.Companion.toImageHolder | ||
import dev.brahmkshatriya.echo.common.models.User | ||
import dev.brahmkshatriya.echo.extension.DeezerApi | ||
import dev.brahmkshatriya.echo.extension.DeezerSession | ||
import kotlinx.serialization.json.Json | ||
import kotlinx.serialization.json.JsonObject | ||
import kotlinx.serialization.json.jsonObject | ||
import kotlinx.serialization.json.jsonPrimitive | ||
import okhttp3.Headers | ||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull | ||
import okhttp3.OkHttpClient | ||
import okhttp3.Request | ||
import java.math.BigInteger | ||
import java.security.MessageDigest | ||
|
||
class DeezerLogin( | ||
private val deezerApi: DeezerApi, | ||
private val json: Json, | ||
private val session: DeezerSession, | ||
private val client: OkHttpClient | ||
) { | ||
|
||
suspend fun makeUser(email: String = "", pass: String = "", arl: String, sid: String): List<User> { | ||
val userList = mutableListOf<User>() | ||
val jsonData = deezerApi.callApi("deezer.getUserData") | ||
val jObject = json.decodeFromString<JsonObject>(jsonData) | ||
val userResults = jObject["results"]!! | ||
val userObject = userResults.jsonObject["USER"]!! | ||
val token = userResults.jsonObject["checkForm"]!!.jsonPrimitive.content | ||
val userId = userObject.jsonObject["USER_ID"]!!.jsonPrimitive.content | ||
val licenseToken = userObject.jsonObject["OPTIONS"]!!.jsonObject["license_token"]!!.jsonPrimitive.content | ||
val name = userObject.jsonObject["BLOG_NAME"]!!.jsonPrimitive.content | ||
val cover = userObject.jsonObject["USER_PICTURE"]!!.jsonPrimitive.content | ||
val user = User( | ||
id = userId, | ||
name = name, | ||
cover = "https://e-cdns-images.dzcdn.net/images/user/$cover/100x100-000000-80-0-0.jpg".toImageHolder(), | ||
extras = mapOf( | ||
"arl" to arl, | ||
"user_id" to userId, | ||
"sid" to sid, | ||
"token" to token, | ||
"license_token" to licenseToken, | ||
"email" to email, | ||
"pass" to pass | ||
) | ||
) | ||
userList.add(user) | ||
return userList | ||
} | ||
|
||
suspend fun getArlByEmail(mail: String, password: String, sid: String) { | ||
// Get SID | ||
getSid() | ||
|
||
val clientId = "447462" | ||
val clientSecret = "a83bf7f38ad2f137e444727cfc3775cf" | ||
val md5Password = md5(password) | ||
|
||
val params = mapOf( | ||
"app_id" to clientId, | ||
"login" to mail, | ||
"password" to md5Password, | ||
"hash" to md5(clientId + mail + md5Password + clientSecret) | ||
) | ||
|
||
// Get access token | ||
val responseJson = getToken(params, sid) | ||
val apiResponse = json.decodeFromString<JsonObject>(responseJson) | ||
session.updateCredentials(token = apiResponse.jsonObject["access_token"]!!.jsonPrimitive.content) | ||
|
||
// Get ARL | ||
val arlResponse = deezerApi.callApi("user.getArl") | ||
val arlObject = json.decodeFromString<JsonObject>(arlResponse) | ||
session.updateCredentials(arl = arlObject["results"]!!.jsonPrimitive.content) | ||
} | ||
|
||
private fun md5(input: String): String { | ||
val md = MessageDigest.getInstance("MD5") | ||
val digest = md.digest(input.toByteArray()) | ||
return BigInteger(1, digest).toString(16).padStart(32, '0') | ||
} | ||
|
||
private fun getToken(params: Map<String, String>, sid: String): String { | ||
val url = "https://connect.deezer.com/oauth/user_auth.php" | ||
val httpUrl = url.toHttpUrlOrNull()!!.newBuilder().apply { | ||
params.forEach { (key, value) -> addQueryParameter(key, value) } | ||
}.build() | ||
|
||
val request = Request.Builder() | ||
.url(httpUrl) | ||
.get() | ||
.headers( | ||
Headers.headersOf( | ||
"Cookie", "sid=$sid", | ||
"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36" | ||
) | ||
) | ||
.build() | ||
|
||
client.newCall(request).execute().use { response -> | ||
if (!response.isSuccessful) throw Exception("Unexpected code $response") | ||
return response.body.string() | ||
} | ||
} | ||
|
||
fun getSid() { | ||
val url = "https://www.deezer.com/" | ||
val request = Request.Builder() | ||
.url(url) | ||
.get() | ||
.build() | ||
|
||
val response = client.newCall(request).execute() | ||
response.headers.forEach { | ||
if (it.second.startsWith("sid=")) { | ||
session.updateCredentials(sid = it.second.substringAfter("sid=").substringBefore(";")) | ||
} | ||
} | ||
} | ||
} |
100 changes: 100 additions & 0 deletions
100
ext/src/main/java/dev/brahmkshatriya/echo/extension/api/DeezerMedia.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package dev.brahmkshatriya.echo.extension.api | ||
|
||
import dev.brahmkshatriya.echo.common.models.Track | ||
import kotlinx.serialization.encodeToString | ||
import kotlinx.serialization.json.Json | ||
import kotlinx.serialization.json.JsonObject | ||
import kotlinx.serialization.json.add | ||
import kotlinx.serialization.json.buildJsonArray | ||
import kotlinx.serialization.json.buildJsonObject | ||
import kotlinx.serialization.json.put | ||
import kotlinx.serialization.json.putJsonArray | ||
import okhttp3.Headers | ||
import okhttp3.HttpUrl | ||
import okhttp3.MediaType.Companion.toMediaType | ||
import okhttp3.OkHttpClient | ||
import okhttp3.Request | ||
import okhttp3.RequestBody.Companion.toRequestBody | ||
|
||
class DeezerMedia(private val json: Json, private val clientNP: OkHttpClient) { | ||
|
||
fun getMP3MediaUrl(track: Track, language: String, arl: String, sid: String, licenseToken: String): JsonObject { | ||
val headers = Headers.Builder().apply { | ||
add("Accept-Encoding", "gzip") | ||
add("Accept-Language", language.substringBefore("-")) | ||
add("Cache-Control", "max-age=0") | ||
add("Connection", "Keep-alive") | ||
add("Content-Type", "application/json; charset=utf-8") | ||
add("Cookie", "arl=$arl&sid=$sid") | ||
add("Host", "media.deezer.com") | ||
add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36") | ||
}.build() | ||
|
||
val url = HttpUrl.Builder() | ||
.scheme("https") | ||
.host("media.deezer.com") | ||
.addPathSegment("v1") | ||
.addPathSegment("get_url") | ||
.build() | ||
|
||
val requestBody = json.encodeToString( | ||
buildJsonObject { | ||
put("license_token", licenseToken) | ||
putJsonArray("media") { | ||
add(buildJsonObject { | ||
put("type", "FULL") | ||
putJsonArray("formats") { | ||
add(buildJsonObject { | ||
put("cipher", "BF_CBC_STRIPE") | ||
put("format", "MP3_MISC") | ||
}) | ||
} | ||
}) | ||
} | ||
putJsonArray("track_tokens") { add(track.extras["TRACK_TOKEN"]) } | ||
} | ||
).toRequestBody("application/json; charset=utf-8".toMediaType()) | ||
|
||
val request = Request.Builder() | ||
.url(url) | ||
.post(requestBody) | ||
.headers(headers) | ||
.build() | ||
|
||
val response = clientNP.newCall(request).execute() | ||
val responseBody = response.body.string() | ||
|
||
return json.decodeFromString<JsonObject>(responseBody) | ||
} | ||
|
||
fun getMediaUrl(track: Track, quality: String): JsonObject { | ||
val url = HttpUrl.Builder() | ||
.scheme("https") | ||
.host("dzmedia.fly.dev") | ||
.addPathSegment("get_url") | ||
.build() | ||
|
||
val formats = when (quality) { | ||
"128" -> arrayOf("MP3_128", "MP3_64", "MP3_MISC") | ||
"flac" -> arrayOf("FLAC", "MP3_320", "MP3_128", "MP3_64", "MP3_MISC") | ||
else -> arrayOf("MP3_320", "MP3_128", "MP3_64", "MP3_MISC") | ||
} | ||
|
||
val requestBody = json.encodeToString( | ||
buildJsonObject { | ||
put("formats", buildJsonArray { formats.forEach { add(it) } }) | ||
put ("ids", buildJsonArray{ add(track.id.toLong()) }) | ||
} | ||
).toRequestBody("application/json; charset=utf-8".toMediaType()) | ||
|
||
val request = Request.Builder() | ||
.url(url) | ||
.post(requestBody) | ||
.build() | ||
|
||
val response = clientNP.newCall(request).execute() | ||
val responseBody = response.body.string() | ||
|
||
return json.decodeFromString<JsonObject>(responseBody) | ||
} | ||
} |
Oops, something went wrong.