Changed login method of Bangumi tracker

Created a login dialog to enter access token instead of browser redirect.
This commit is contained in:
KayZhang52 2023-09-17 22:34:53 +08:00
parent f9754f4f58
commit 0d105c04cf
5 changed files with 146 additions and 7 deletions

View file

@ -95,6 +95,13 @@ object SettingsTrackingScreen : SearchableSettings {
onDismissRequest = { dialog = null },
)
}
is BangumiLoginDialog ->{
TrackingLoginDialogForBangumi(
service = service,
uNameStringRes = uNameStringRes,
onDismissRequest = { dialog = null }
)
}
is LogoutDialog -> {
TrackingLogoutDialog(
service = service,
@ -160,7 +167,7 @@ object SettingsTrackingScreen : SearchableSettings {
Preference.PreferenceItem.TrackingPreference(
title = trackManager.bangumi.name,
service = trackManager.bangumi,
login = { context.openInBrowser(BangumiApi.authUrl(), forceDefaultBrowser = true) },
login = { dialog = BangumiLoginDialog(trackManager.bangumi, R.string.username); },
logout = { dialog = LogoutDialog(trackManager.bangumi) },
),
Preference.PreferenceItem.InfoPreference(stringResource(R.string.tracking_info)),
@ -281,6 +288,96 @@ object SettingsTrackingScreen : SearchableSettings {
)
}
/**
* Dialog for Bangumi Tracking, user need to directly enter access token.
*/
@Composable
private fun TrackingLoginDialogForBangumi(
service: TrackService,
@StringRes uNameStringRes: Int,
onDismissRequest: () -> Unit,
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
var accessToken by remember { mutableStateOf(TextFieldValue("")) }
var expiresIn by remember { mutableStateOf(TextFieldValue("")) }
var expanded by remember { mutableStateOf(false) }
var processing by remember { mutableStateOf(false) }
var inputError by remember { mutableStateOf(false) }
AlertDialog(
onDismissRequest = onDismissRequest,
title = {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(
text = "Enter access token for Bangumi",
modifier = Modifier.weight(1f),
)
IconButton(onClick = onDismissRequest) {
Icon(
imageVector = Icons.Outlined.Close,
contentDescription = stringResource(R.string.action_close),
)
}
}
},
text = {
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = accessToken,
onValueChange = { accessToken = it },
label = { Text(text = "access token") },
visualTransformation = VisualTransformation.None,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Text,
imeAction = ImeAction.Done,
),
singleLine = true,
isError = inputError && !processing,
)
OutlinedTextField(
modifier = Modifier.fillMaxWidth(),
value = expiresIn,
onValueChange = { expiresIn = it },
label = { Text(text = "days to expiry") },
visualTransformation = VisualTransformation.None,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
imeAction = ImeAction.Done,
),
singleLine = true,
isError = inputError && !processing,
)
}
},
confirmButton = {
Button(
modifier = Modifier.fillMaxWidth(),
enabled = !processing && accessToken.text.isNotBlank(),
onClick = {
scope.launchIO {
processing = true
val result = checkLogin(
context = context,
service = service,
username = accessToken.text,
password = expiresIn.text,
)
inputError = !result
if (result) onDismissRequest()
processing = false
}
},
) {
val id = if (processing) R.string.loading else R.string.login
Text(text = stringResource(id))
}
},
)
}
private suspend fun checkLogin(
context: Context,
service: TrackService,
@ -346,6 +443,11 @@ private data class LoginDialog(
@StringRes val uNameStringRes: Int,
)
private data class BangumiLoginDialog(
val service: TrackService,
@StringRes val uNameStringRes: Int,
)
private data class LogoutDialog(
val service: TrackService,
)

View file

@ -105,13 +105,21 @@ class Bangumi(id: Long) : TrackService(id, "Bangumi") {
override fun getCompletionStatus(): Int = COMPLETED
override suspend fun login(username: String, password: String) = login(password)
override suspend fun login(username: String, password: String) = login(username, password.toLong())
suspend fun login(code: String) {
try {
val oauth = api.accessToken(code)
suspend fun login(code:String, expiresIn:Long){
try{
val oauth = OAuth(
access_token = code,
token_type = "",
expires_in = expiresIn * 86400000,
refresh_token = null,
user_id = id
)
interceptor.newAuth(oauth)
val id = api.checkPersonalToken(code).toLong()
saveCredentials(oauth.user_id.toString(), oauth.access_token)
saveToken(oauth)
} catch (e: Throwable) {
logout()
}

View file

@ -175,6 +175,34 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
.build(),
)
/**
* Check that access token user gave is valid
*/
suspend fun checkPersonalToken(code:String): Int {
return withIOContext {
val response = authClient.newCall(
GET(
"$apiUrl/v0/me",
),
).awaitSuccess()
val responseBody = response.body.string()
if (responseBody.isEmpty()) {
throw Exception("Null Response")
}
if (response.code != 200) {
throw Exception("Failed Response")
} else {
var id:Int = -1
json.decodeFromString<User>(responseBody).let {
id = it.id!!
}
if(id == -1) throw Exception("Failed Response")
id
}
}
}
companion object {
private const val clientId = "bgm10555cda0762e80ca"
private const val clientSecret = "8fff394a8627b4c388cbf349ec865775"

View file

@ -32,12 +32,14 @@ class BangumiInterceptor(val bangumi: Bangumi) : Interceptor {
val authRequest = if (originalRequest.method == "GET") {
originalRequest.newBuilder()
.header("User-Agent", "Tachiyomi")
.header("Authorization","Bearer ${oauth!!.access_token}")
.url(
originalRequest.url.newBuilder()
.addQueryParameter("access_token", currAuth.access_token).build(),
)
.build()
} else {
originalRequest.newBuilder()
.post(addToken(currAuth.access_token, originalRequest.body as FormBody))
.header("User-Agent", "Tachiyomi")

View file

@ -9,7 +9,6 @@ class TrackLoginActivity : BaseOAuthLoginActivity() {
override fun handleResult(data: Uri?) {
when (data?.host) {
"anilist-auth" -> handleAnilist(data)
"bangumi-auth" -> handleBangumi(data)
"myanimelist-auth" -> handleMyAnimeList(data)
"shikimori-auth" -> handleShikimori(data)
}
@ -33,7 +32,7 @@ class TrackLoginActivity : BaseOAuthLoginActivity() {
val code = data.getQueryParameter("code")
if (code != null) {
lifecycleScope.launchIO {
trackManager.bangumi.login(code)
trackManager.bangumi.login(code,"0")
returnToSettings()
}
} else {