From e7d057bfb80b10d9417c5fd572920e8d3bffdb3c Mon Sep 17 00:00:00 2001 From: Jannik Date: Sat, 4 Dec 2021 19:55:26 +0100 Subject: [PATCH] add crunchyroll login and browse (no parsing for now) --- app/build.gradle | 14 ++- .../teapod/parser/crunchyroll/Cruncyroll.kt | 105 ++++++++++++++++++ .../teapod/ui/activity/main/MainActivity.kt | 41 ++++--- 3 files changed, 143 insertions(+), 17 deletions(-) create mode 100644 app/src/main/java/org/mosad/teapod/parser/crunchyroll/Cruncyroll.kt diff --git a/app/build.gradle b/app/build.gradle index 06a5261..fc83ede 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,9 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-android-extensions' +plugins { + id 'com.android.application' + id 'kotlin-android' + id 'kotlin-android-extensions' + id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlin_version" +} android { compileSdkVersion 30 @@ -43,6 +46,7 @@ dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2' + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.1") implementation 'androidx.core:core-ktx:1.6.0' implementation 'androidx.appcompat:appcompat:1.3.1' @@ -68,6 +72,10 @@ dependencies { implementation 'com.afollestad.material-dialogs:core:3.3.0' implementation 'com.afollestad.material-dialogs:bottomsheets:3.3.0' + implementation 'com.github.kittinunf.fuel:fuel:2.3.1' + implementation 'com.github.kittinunf.fuel:fuel-android:2.3.1' + implementation 'com.github.kittinunf.fuel:fuel-json:2.3.1' + testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' diff --git a/app/src/main/java/org/mosad/teapod/parser/crunchyroll/Cruncyroll.kt b/app/src/main/java/org/mosad/teapod/parser/crunchyroll/Cruncyroll.kt new file mode 100644 index 0000000..cddec0d --- /dev/null +++ b/app/src/main/java/org/mosad/teapod/parser/crunchyroll/Cruncyroll.kt @@ -0,0 +1,105 @@ +package org.mosad.teapod.parser.crunchyroll + +import com.github.kittinunf.fuel.Fuel +import com.github.kittinunf.fuel.core.FuelError +import com.github.kittinunf.fuel.json.FuelJson +import com.github.kittinunf.fuel.json.responseJson +import com.github.kittinunf.result.Result +import kotlinx.coroutines.* +import kotlinx.serialization.Serializable +import kotlinx.serialization.decodeFromString +import kotlinx.serialization.json.Json + +private val json = Json { ignoreUnknownKeys = true } + +class Cruncyroll { + + private val baseUrl = "https://beta-api.crunchyroll.com" + + private var accessToken = "" + private var tokenType = "" + + fun login(username: String, password: String): Boolean = runBlocking { + val tokenEndpoint = "/auth/v1/token" + + val formData = listOf( + "username" to username, + "password" to password, + "grant_type" to "password", + "scope" to "offline_access" + ) + + withContext(Dispatchers.IO) { + val (request, response, result) = Fuel.post("$baseUrl$tokenEndpoint", parameters = formData) + .header("Content-Type", "application/x-www-form-urlencoded") + .appendHeader( + "Authorization", + "Basic " + ) + .responseJson() + + result.component1()?.obj()?.let { + accessToken = it.get("access_token").toString() + tokenType = it.get("token_type").toString() + } + +// println("request: $request") +// println("response: $response") +// println("response: $result") + + println("login complete with code ${response.statusCode}") + + return@withContext response.statusCode == 200 + } + + return@runBlocking false + } + + // TODO get/post difference + private suspend fun requestA(endpoint: String): Result = coroutineScope { + return@coroutineScope (Dispatchers.IO) { + val (request, response, result) = Fuel.get("$baseUrl$endpoint") + .header("Authorization", "$tokenType $accessToken") + .responseJson() + +// println("request request: $request") +// println("request response: $response") +// println("request result: $result") + + result + } + } + + // TESTING + @Serializable + data class Test(val total: Int, val items: List) + + @Serializable + data class Item(val channel_id: String, val description: String) + + // TODO sort_by, default alphabetical, n, locale de-DE + suspend fun browse() { + val browseEndpoint = "/content/v1/browse" + + val result = requestA(browseEndpoint) + + println("${result.component1()?.obj()?.get("total")}") + + val test = json.decodeFromString(result.component1()?.obj()?.toString()!!) + println(test) + + } + + suspend fun search() { + val searchEndpoint = "/content/v1/search" + + val result = requestA(searchEndpoint) + + println("${result.component1()?.obj()?.get("total")}") + + val test = json.decodeFromString(result.component1()?.obj()?.toString()!!) + println(test) + + } + +} \ No newline at end of file diff --git a/app/src/main/java/org/mosad/teapod/ui/activity/main/MainActivity.kt b/app/src/main/java/org/mosad/teapod/ui/activity/main/MainActivity.kt index 69905a5..39104b4 100644 --- a/app/src/main/java/org/mosad/teapod/ui/activity/main/MainActivity.kt +++ b/app/src/main/java/org/mosad/teapod/ui/activity/main/MainActivity.kt @@ -36,6 +36,7 @@ import kotlinx.coroutines.* import org.mosad.teapod.R import org.mosad.teapod.databinding.ActivityMainBinding import org.mosad.teapod.parser.AoDParser +import org.mosad.teapod.parser.crunchyroll.Cruncyroll import org.mosad.teapod.preferences.EncryptedPreferences import org.mosad.teapod.preferences.Preferences import org.mosad.teapod.ui.activity.main.fragments.AccountFragment @@ -150,26 +151,38 @@ class MainActivity : AppCompatActivity(), NavigationBarView.OnItemSelectedListen EncryptedPreferences.readCredentials(this) StorageController.load(this) - // show onboarding + // show onboarding TODO rework if (EncryptedPreferences.password.isEmpty()) { showOnboarding() } else { - try { - if (!AoDParser.login()) { - showLoginDialog() - } - } catch (ex: SocketTimeoutException) { - Log.w(javaClass.name, "Timeout during login!") + val crunchy = Cruncyroll() + crunchy.login(EncryptedPreferences.login, EncryptedPreferences.password) + println("after login") - // show waring dialog before finishing - MaterialDialog(this).show { - title(R.string.dialog_timeout_head) - message(R.string.dialog_timeout_desc) - onDismiss { exitAndRemoveTask() } - } - } + runBlocking { crunchy.browse() } } + + +// if (EncryptedPreferences.password.isEmpty()) { +// showOnboarding() +// } else { +// try { +// if (!AoDParser.login()) { +// showLoginDialog() +// } +// } catch (ex: SocketTimeoutException) { +// Log.w(javaClass.name, "Timeout during login!") +// +// // show waring dialog before finishing +// MaterialDialog(this).show { +// title(R.string.dialog_timeout_head) +// message(R.string.dialog_timeout_desc) +// onDismiss { exitAndRemoveTask() } +// } +// } +// } + runBlocking { loadingJob.await() } // wait for initial loading to finish } Log.i(javaClass.name, "loading and login in $time ms")