mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Add chinese track website "bangumi" (#2032)
* copy from shikimori and change parmater * add login activity * fix * login sucess * search * add... * auth fix * save status * revert shikimori * fix oauth error * add bangumi info * update read chapter index * refersh token * remove outdate file * drop comment * change icon * drop search result which type not comic * fix bind logic * set status * add ep status * format code * disable cache for `collection` api
This commit is contained in:
		| @@ -5,6 +5,7 @@ import eu.kanade.tachiyomi.data.track.anilist.Anilist | ||||
| import eu.kanade.tachiyomi.data.track.kitsu.Kitsu | ||||
| import eu.kanade.tachiyomi.data.track.myanimelist.Myanimelist | ||||
| import eu.kanade.tachiyomi.data.track.shikimori.Shikimori | ||||
| import eu.kanade.tachiyomi.data.track.bangumi.Bangumi | ||||
|  | ||||
| class TrackManager(private val context: Context) { | ||||
|  | ||||
| @@ -13,6 +14,7 @@ class TrackManager(private val context: Context) { | ||||
|         const val ANILIST = 2 | ||||
|         const val KITSU = 3 | ||||
|         const val SHIKIMORI = 4 | ||||
|         const val BANGUMI = 5 | ||||
|     } | ||||
|  | ||||
|     val myAnimeList = Myanimelist(context, MYANIMELIST) | ||||
| @@ -23,7 +25,9 @@ class TrackManager(private val context: Context) { | ||||
|  | ||||
|     val shikimori = Shikimori(context, SHIKIMORI) | ||||
|  | ||||
|     val services = listOf(myAnimeList, aniList, kitsu, shikimori) | ||||
|     val bangumi = Bangumi(context, BANGUMI) | ||||
|  | ||||
|     val services = listOf(myAnimeList, aniList, kitsu, shikimori, bangumi) | ||||
|  | ||||
|     fun getService(id: Int) = services.find { it.id == id } | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,7 @@ | ||||
| package eu.kanade.tachiyomi.data.track.bangumi | ||||
|  | ||||
| data class Avatar( | ||||
|   val large: String? = "", | ||||
|   val medium: String? = "", | ||||
|   val small: String? = "" | ||||
| ) | ||||
| @@ -0,0 +1,144 @@ | ||||
| package eu.kanade.tachiyomi.data.track.bangumi | ||||
|  | ||||
| import android.content.Context | ||||
| import android.graphics.Color | ||||
| import com.google.gson.Gson | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Track | ||||
| import eu.kanade.tachiyomi.data.track.TrackService | ||||
| import eu.kanade.tachiyomi.data.track.model.TrackSearch | ||||
| import rx.Completable | ||||
| import rx.Observable | ||||
| import uy.kohesive.injekt.injectLazy | ||||
|  | ||||
| class Bangumi(private val context: Context, id: Int) : TrackService(id) { | ||||
|  | ||||
|   override fun getScoreList(): List<String> { | ||||
|     return IntRange(0, 10).map(Int::toString) | ||||
|   } | ||||
|  | ||||
|   override fun displayScore(track: Track): String { | ||||
|     return track.score.toInt().toString() | ||||
|   } | ||||
|  | ||||
|   override fun add(track: Track): Observable<Track> { | ||||
|     return api.addLibManga(track) | ||||
|   } | ||||
|  | ||||
|   override fun update(track: Track): Observable<Track> { | ||||
|     if (track.total_chapters != 0 && track.last_chapter_read == track.total_chapters) { | ||||
|       track.status = COMPLETED | ||||
|     } | ||||
|     return api.updateLibManga(track) | ||||
|   } | ||||
|  | ||||
|   override fun bind(track: Track): Observable<Track> { | ||||
|     return api.statusLibManga(track) | ||||
|       .flatMap { | ||||
|         api.findLibManga(track).flatMap { remoteTrack -> | ||||
|           if (remoteTrack != null && it != null) { | ||||
|             track.copyPersonalFrom(remoteTrack) | ||||
|             track.library_id = remoteTrack.library_id | ||||
|             track.status = remoteTrack.status | ||||
|             track.last_chapter_read = remoteTrack.last_chapter_read | ||||
|             update(track) | ||||
|           } else { | ||||
|             // Set default fields if it's not found in the list | ||||
|             track.score = DEFAULT_SCORE.toFloat() | ||||
|             track.status = DEFAULT_STATUS | ||||
|             add(track) | ||||
|             update(track) | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|   } | ||||
|  | ||||
|   override fun search(query: String): Observable<List<TrackSearch>> { | ||||
|     return api.search(query) | ||||
|   } | ||||
|  | ||||
|   override fun refresh(track: Track): Observable<Track> { | ||||
|     return api.statusLibManga(track) | ||||
|       .flatMap { | ||||
|         track.copyPersonalFrom(it!!) | ||||
|         api.findLibManga(track) | ||||
|           .map { remoteTrack -> | ||||
|             if (remoteTrack != null) { | ||||
|               track.total_chapters = remoteTrack.total_chapters | ||||
|               track.status = remoteTrack.status | ||||
|             } | ||||
|             track | ||||
|           } | ||||
|       } | ||||
|   } | ||||
|  | ||||
|   companion object { | ||||
|     const val READING = 3 | ||||
|     const val COMPLETED = 2 | ||||
|     const val ON_HOLD = 4 | ||||
|     const val DROPPED = 5 | ||||
|     const val PLANNING = 1 | ||||
|  | ||||
|     const val DEFAULT_STATUS = READING | ||||
|     const val DEFAULT_SCORE = 0 | ||||
|   } | ||||
|  | ||||
|   override val name = "Bangumi" | ||||
|  | ||||
|   private val gson: Gson by injectLazy() | ||||
|  | ||||
|   private val interceptor by lazy { BangumiInterceptor(this, gson) } | ||||
|  | ||||
|   private val api by lazy { BangumiApi(client, interceptor) } | ||||
|  | ||||
|   override fun getLogo() = R.drawable.bangumi | ||||
|  | ||||
|   override fun getLogoColor() = Color.rgb(0xF0, 0x91, 0x99) | ||||
|  | ||||
|   override fun getStatusList(): List<Int> { | ||||
|     return listOf(READING, COMPLETED, ON_HOLD, DROPPED, PLANNING) | ||||
|   } | ||||
|  | ||||
|   override fun getStatus(status: Int): String = with(context) { | ||||
|     when (status) { | ||||
|       READING -> getString(R.string.reading) | ||||
|       COMPLETED -> getString(R.string.completed) | ||||
|       ON_HOLD -> getString(R.string.on_hold) | ||||
|       DROPPED -> getString(R.string.dropped) | ||||
|       PLANNING -> getString(R.string.plan_to_read) | ||||
|       else -> "" | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   override fun login(username: String, password: String) = login(password) | ||||
|  | ||||
|   fun login(code: String): Completable { | ||||
|     return api.accessToken(code).map { oauth: OAuth? -> | ||||
|       interceptor.newAuth(oauth) | ||||
|       if (oauth != null) { | ||||
|         saveCredentials(oauth.user_id.toString(), oauth.access_token) | ||||
|       } | ||||
|     }.doOnError { | ||||
|       logout() | ||||
|     }.toCompletable() | ||||
|   } | ||||
|  | ||||
|   fun saveToken(oauth: OAuth?) { | ||||
|     val json = gson.toJson(oauth) | ||||
|     preferences.trackToken(this).set(json) | ||||
|   } | ||||
|  | ||||
|   fun restoreToken(): OAuth? { | ||||
|     return try { | ||||
|       gson.fromJson(preferences.trackToken(this).get(), OAuth::class.java) | ||||
|     } catch (e: Exception) { | ||||
|       null | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   override fun logout() { | ||||
|     super.logout() | ||||
|     preferences.trackToken(this).set(null) | ||||
|     interceptor.newAuth(null) | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,208 @@ | ||||
| package eu.kanade.tachiyomi.data.track.bangumi | ||||
|  | ||||
| import android.net.Uri | ||||
| import com.github.salomonbrys.kotson.array | ||||
| import com.github.salomonbrys.kotson.obj | ||||
| import com.google.gson.Gson | ||||
| import com.google.gson.JsonObject | ||||
| import com.google.gson.JsonParser | ||||
| import eu.kanade.tachiyomi.data.database.models.Track | ||||
| import eu.kanade.tachiyomi.data.track.TrackManager | ||||
| import eu.kanade.tachiyomi.data.track.model.TrackSearch | ||||
| import eu.kanade.tachiyomi.network.POST | ||||
| import eu.kanade.tachiyomi.network.asObservableSuccess | ||||
| import okhttp3.CacheControl | ||||
| import okhttp3.FormBody | ||||
| import okhttp3.OkHttpClient | ||||
| import okhttp3.Request | ||||
| import rx.Observable | ||||
| import uy.kohesive.injekt.injectLazy | ||||
| import java.net.URLEncoder | ||||
|  | ||||
| class BangumiApi(private val client: OkHttpClient, interceptor: BangumiInterceptor) { | ||||
|  | ||||
|   private val gson: Gson by injectLazy() | ||||
|   private val parser = JsonParser() | ||||
|   private val authClient = client.newBuilder().addInterceptor(interceptor).build() | ||||
|  | ||||
|   fun addLibManga(track: Track): Observable<Track> { | ||||
|     val body = FormBody.Builder() | ||||
|       .add("rating", track.score.toInt().toString()) | ||||
|       .add("status", track.toBangumiStatus()) | ||||
|       .build() | ||||
|     val request = Request.Builder() | ||||
|       .url("$apiUrl/collection/${track.media_id}/update") | ||||
|       .post(body) | ||||
|       .build() | ||||
|     return authClient.newCall(request) | ||||
|       .asObservableSuccess() | ||||
|       .map { | ||||
|         track | ||||
|       } | ||||
|   } | ||||
|  | ||||
|   fun updateLibManga(track: Track): Observable<Track> { | ||||
|     // chapter update | ||||
|     val body = FormBody.Builder() | ||||
|       .add("watched_eps", track.last_chapter_read.toString()) | ||||
|       .build() | ||||
|     val request = Request.Builder() | ||||
|       .url("$apiUrl/subject/${track.media_id}/update/watched_eps") | ||||
|       .post(body) | ||||
|       .build() | ||||
|  | ||||
|     // read status update | ||||
|     val sbody = FormBody.Builder() | ||||
|       .add("status", track.toBangumiStatus()) | ||||
|       .build() | ||||
|     val srequest = Request.Builder() | ||||
|       .url("$apiUrl/collection/${track.media_id}/update") | ||||
|       .post(sbody) | ||||
|       .build() | ||||
|     return authClient.newCall(request) | ||||
|       .asObservableSuccess() | ||||
|       .map { | ||||
|         track | ||||
|       }.flatMap { | ||||
|         authClient.newCall(srequest) | ||||
|           .asObservableSuccess() | ||||
|           .map { | ||||
|             track | ||||
|           } | ||||
|       } | ||||
|   } | ||||
|  | ||||
|   fun search(search: String): Observable<List<TrackSearch>> { | ||||
|     val url = Uri.parse( | ||||
|       "$apiUrl/search/subject/${URLEncoder.encode(search, Charsets.UTF_8.name())}").buildUpon() | ||||
|       .appendQueryParameter("max_results", "20") | ||||
|       .build() | ||||
|     val request = Request.Builder() | ||||
|       .url(url.toString()) | ||||
|       .get() | ||||
|       .build() | ||||
|     return authClient.newCall(request) | ||||
|       .asObservableSuccess() | ||||
|       .map { netResponse -> | ||||
|         val responseBody = netResponse.body()?.string().orEmpty() | ||||
|         if (responseBody.isEmpty()) { | ||||
|           throw Exception("Null Response") | ||||
|         } | ||||
|         val response = parser.parse(responseBody).obj["list"]?.array | ||||
|         response?.filter { it.obj["type"].asInt == 1 }?.map { jsonToSearch(it.obj) } | ||||
|       } | ||||
|  | ||||
|   } | ||||
|  | ||||
|   private fun jsonToSearch(obj: JsonObject): TrackSearch { | ||||
|     return TrackSearch.create(TrackManager.BANGUMI).apply { | ||||
|       media_id = obj["id"].asInt | ||||
|       title = obj["name_cn"].asString | ||||
|       cover_url = obj["images"].obj["common"].asString | ||||
|       summary = obj["name"].asString | ||||
|       tracking_url = obj["url"].asString | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private fun jsonToTrack(mangas: JsonObject): Track { | ||||
|     return Track.create(TrackManager.BANGUMI).apply { | ||||
|       title = mangas["name"].asString | ||||
|       media_id = mangas["id"].asInt | ||||
|       score = if (mangas["rating"] != null) | ||||
|         (if (mangas["rating"].isJsonObject) mangas["rating"].obj["score"].asFloat else 0f) | ||||
|       else 0f | ||||
|       status = Bangumi.DEFAULT_STATUS | ||||
|       tracking_url = mangas["url"].asString | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   fun findLibManga(track: Track): Observable<Track?> { | ||||
|     val urlMangas = "$apiUrl/subject/${track.media_id}" | ||||
|     val requestMangas = Request.Builder() | ||||
|       .url(urlMangas) | ||||
|       .get() | ||||
|       .build() | ||||
|  | ||||
|     return authClient.newCall(requestMangas) | ||||
|       .asObservableSuccess() | ||||
|       .map { netResponse -> | ||||
|         // get comic info | ||||
|         val responseBody = netResponse.body()?.string().orEmpty() | ||||
|         jsonToTrack(parser.parse(responseBody).obj) | ||||
|       } | ||||
|   } | ||||
|  | ||||
|   fun statusLibManga(track: Track): Observable<Track?> { | ||||
|     val urlUserRead = "$apiUrl/collection/${track.media_id}" | ||||
|     val requestUserRead = Request.Builder() | ||||
|       .url(urlUserRead) | ||||
|       .cacheControl(CacheControl.FORCE_NETWORK) | ||||
|       .get() | ||||
|       .build() | ||||
|  | ||||
|     // todo get user readed chapter here | ||||
|     return authClient.newCall(requestUserRead) | ||||
|       .asObservableSuccess() | ||||
|       .map { netResponse -> | ||||
|         val resp = netResponse.body()?.string() | ||||
|         val coll = gson.fromJson(resp, Collection::class.java) | ||||
|         track.status = coll.status?.id!! | ||||
|         track.last_chapter_read = coll.ep_status!! | ||||
|         track | ||||
|       } | ||||
|   } | ||||
|  | ||||
|   fun accessToken(code: String): Observable<OAuth> { | ||||
|     return client.newCall(accessTokenRequest(code)).asObservableSuccess().map { netResponse -> | ||||
|       val responseBody = netResponse.body()?.string().orEmpty() | ||||
|       if (responseBody.isEmpty()) { | ||||
|         throw Exception("Null Response") | ||||
|       } | ||||
|       gson.fromJson(responseBody, OAuth::class.java) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   private fun accessTokenRequest(code: String) = POST(oauthUrl, | ||||
|     body = FormBody.Builder() | ||||
|       .add("grant_type", "authorization_code") | ||||
|       .add("client_id", clientId) | ||||
|       .add("client_secret", clientSecret) | ||||
|       .add("code", code) | ||||
|       .add("redirect_uri", redirectUrl) | ||||
|       .build() | ||||
|   ) | ||||
|  | ||||
|   companion object { | ||||
|     private const val clientId = "bgm10555cda0762e80ca" | ||||
|     private const val clientSecret = "8fff394a8627b4c388cbf349ec865775" | ||||
|  | ||||
|     private const val baseUrl = "https://bangumi.org" | ||||
|     private const val apiUrl = "https://api.bgm.tv" | ||||
|     private const val oauthUrl = "https://bgm.tv/oauth/access_token" | ||||
|     private const val loginUrl = "https://bgm.tv/oauth/authorize" | ||||
|  | ||||
|     private const val redirectUrl = "tachiyomi://bangumi-auth" | ||||
|     private const val baseMangaUrl = "$apiUrl/mangas" | ||||
|  | ||||
|     fun mangaUrl(remoteId: Int): String { | ||||
|       return "$baseMangaUrl/$remoteId" | ||||
|     } | ||||
|  | ||||
|     fun authUrl() = | ||||
|       Uri.parse(loginUrl).buildUpon() | ||||
|         .appendQueryParameter("client_id", clientId) | ||||
|         .appendQueryParameter("response_type", "code") | ||||
|         .appendQueryParameter("redirect_uri", redirectUrl) | ||||
|         .build() | ||||
|  | ||||
|     fun refreshTokenRequest(token: String) = POST(oauthUrl, | ||||
|       body = FormBody.Builder() | ||||
|         .add("grant_type", "refresh_token") | ||||
|         .add("client_id", clientId) | ||||
|         .add("client_secret", clientSecret) | ||||
|         .add("refresh_token", token) | ||||
|         .add("redirect_uri", redirectUrl) | ||||
|         .build()) | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,61 @@ | ||||
| package eu.kanade.tachiyomi.data.track.bangumi | ||||
|  | ||||
| import com.google.gson.Gson | ||||
| import okhttp3.FormBody | ||||
| import okhttp3.Interceptor | ||||
| import okhttp3.Response | ||||
|  | ||||
| class BangumiInterceptor(val bangumi: Bangumi, val gson: Gson) : Interceptor { | ||||
|  | ||||
|   /** | ||||
|    * OAuth object used for authenticated requests. | ||||
|    */ | ||||
|   private var oauth: OAuth? = bangumi.restoreToken() | ||||
|  | ||||
|   fun addTocken(tocken: String, oidFormBody: FormBody): FormBody { | ||||
|     val newFormBody = FormBody.Builder() | ||||
|     for (i in 0 until oidFormBody.size()) { | ||||
|       newFormBody.add(oidFormBody.name(i), oidFormBody.value(i)) | ||||
|     } | ||||
|     newFormBody.add("access_token", tocken) | ||||
|     return newFormBody.build() | ||||
|   } | ||||
|  | ||||
|   override fun intercept(chain: Interceptor.Chain): Response { | ||||
|     val originalRequest = chain.request() | ||||
|  | ||||
|     val currAuth = oauth ?: throw Exception("Not authenticated with Bangumi") | ||||
|  | ||||
|     if (currAuth.isExpired()) { | ||||
|       val response = chain.proceed(BangumiApi.refreshTokenRequest(currAuth.refresh_token!!)) | ||||
|       if (response.isSuccessful) { | ||||
|         newAuth(gson.fromJson(response.body()!!.string(), OAuth::class.java)) | ||||
|       } else { | ||||
|         response.close() | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     var authRequest = if (originalRequest.method() == "GET") originalRequest.newBuilder() | ||||
|       .header("User-Agent", "Tachiyomi") | ||||
|       .url(originalRequest.url().newBuilder() | ||||
|         .addQueryParameter("access_token", currAuth.access_token).build()) | ||||
|       .build() else originalRequest.newBuilder() | ||||
|       .post(addTocken(currAuth.access_token, originalRequest.body() as FormBody)) | ||||
|       .header("User-Agent", "Tachiyomi") | ||||
|       .build() | ||||
|  | ||||
|     return chain.proceed(authRequest) | ||||
|   } | ||||
|  | ||||
|   fun newAuth(oauth: OAuth?) { | ||||
|     this.oauth = if (oauth == null) null else OAuth( | ||||
|       oauth.access_token, | ||||
|       oauth.token_type, | ||||
|       System.currentTimeMillis() / 1000, | ||||
|       oauth.expires_in, | ||||
|       oauth.refresh_token, | ||||
|       this.oauth?.user_id) | ||||
|  | ||||
|     bangumi.saveToken(oauth) | ||||
|   } | ||||
| } | ||||
| @@ -0,0 +1,22 @@ | ||||
| package eu.kanade.tachiyomi.data.track.bangumi | ||||
|  | ||||
| import eu.kanade.tachiyomi.data.database.models.Track | ||||
|  | ||||
| fun Track.toBangumiStatus() = when (status) { | ||||
|   Bangumi.READING -> "do" | ||||
|   Bangumi.COMPLETED -> "collect" | ||||
|   Bangumi.ON_HOLD -> "on_hold" | ||||
|   Bangumi.DROPPED -> "dropped" | ||||
|   Bangumi.PLANNING -> "wish" | ||||
|   else -> throw NotImplementedError("Unknown status") | ||||
| } | ||||
|  | ||||
| fun toTrackStatus(status: String) = when (status) { | ||||
|   "do" -> Bangumi.READING | ||||
|   "collect" -> Bangumi.COMPLETED | ||||
|   "on_hold" -> Bangumi.ON_HOLD | ||||
|   "dropped" -> Bangumi.DROPPED | ||||
|   "wish" -> Bangumi.PLANNING | ||||
|  | ||||
|   else -> throw Exception("Unknown status") | ||||
| } | ||||
| @@ -0,0 +1,13 @@ | ||||
| package eu.kanade.tachiyomi.data.track.bangumi | ||||
|  | ||||
| data class Collection( | ||||
|   val `private`: Int? = 0, | ||||
|   val comment: String? = "", | ||||
|   val ep_status: Int? = 0, | ||||
|   val lasttouch: Int? = 0, | ||||
|   val rating: Int? = 0, | ||||
|   val status: Status? = Status(), | ||||
|   val tag: List<String?>? = listOf(), | ||||
|   val user: User? = User(), | ||||
|   val vol_status: Int? = 0 | ||||
| ) | ||||
| @@ -0,0 +1,16 @@ | ||||
| package eu.kanade.tachiyomi.data.track.bangumi | ||||
|  | ||||
| data class OAuth( | ||||
|   val access_token: String, | ||||
|   val token_type: String, | ||||
|   val created_at: Long, | ||||
|   val expires_in: Long, | ||||
|   val refresh_token: String?, | ||||
|   val user_id: Long? | ||||
| ) { | ||||
|  | ||||
|   // Access token refersh before expired | ||||
|   fun isExpired() = (System.currentTimeMillis() / 1000) > (created_at + expires_in - 3600) | ||||
|  | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,7 @@ | ||||
| package eu.kanade.tachiyomi.data.track.bangumi | ||||
|  | ||||
| data class Status( | ||||
|   val id: Int? = 0, | ||||
|   val name: String? = "", | ||||
|   val type: String? = "" | ||||
| ) | ||||
| @@ -0,0 +1,11 @@ | ||||
| package eu.kanade.tachiyomi.data.track.bangumi | ||||
|  | ||||
| data class User( | ||||
|   val avatar: Avatar? = Avatar(), | ||||
|   val id: Int? = 0, | ||||
|   val nickname: String? = "", | ||||
|   val sign: String? = "", | ||||
|   val url: String? = "", | ||||
|   val usergroup: Int? = 0, | ||||
|   val username: String? = "" | ||||
| ) | ||||
| @@ -0,0 +1,50 @@ | ||||
| package eu.kanade.tachiyomi.ui.setting | ||||
|  | ||||
| import android.content.Intent | ||||
| import android.os.Bundle | ||||
| import android.support.v7.app.AppCompatActivity | ||||
| import android.view.Gravity.CENTER | ||||
| import android.view.ViewGroup.LayoutParams.WRAP_CONTENT | ||||
| import android.widget.FrameLayout | ||||
| import android.widget.ProgressBar | ||||
| import eu.kanade.tachiyomi.data.track.TrackManager | ||||
| import eu.kanade.tachiyomi.ui.main.MainActivity | ||||
| import rx.android.schedulers.AndroidSchedulers | ||||
| import rx.schedulers.Schedulers | ||||
| import uy.kohesive.injekt.injectLazy | ||||
|  | ||||
| class BangumiLoginActivity : AppCompatActivity() { | ||||
|  | ||||
|     private val trackManager: TrackManager by injectLazy() | ||||
|  | ||||
|     override fun onCreate(savedState: Bundle?) { | ||||
|         super.onCreate(savedState) | ||||
|  | ||||
|         val view = ProgressBar(this) | ||||
|         setContentView(view, FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT, CENTER)) | ||||
|  | ||||
|         val code = intent.data?.getQueryParameter("code") | ||||
|         if (code != null) { | ||||
|             trackManager.bangumi.login(code) | ||||
|                     .subscribeOn(Schedulers.io()) | ||||
|                     .observeOn(AndroidSchedulers.mainThread()) | ||||
|                     .subscribe({ | ||||
|                         returnToSettings() | ||||
|                     }, { | ||||
|                         returnToSettings() | ||||
|                     }) | ||||
|         } else { | ||||
|             trackManager.bangumi.logout() | ||||
|             returnToSettings() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun returnToSettings() { | ||||
|         finish() | ||||
|  | ||||
|         val intent = Intent(this, MainActivity::class.java) | ||||
|         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP) | ||||
|         startActivity(intent) | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager | ||||
| import eu.kanade.tachiyomi.data.track.TrackService | ||||
| import eu.kanade.tachiyomi.data.track.anilist.AnilistApi | ||||
| import eu.kanade.tachiyomi.data.track.shikimori.ShikimoriApi | ||||
| import eu.kanade.tachiyomi.data.track.bangumi.BangumiApi | ||||
| import eu.kanade.tachiyomi.util.getResourceColor | ||||
| import eu.kanade.tachiyomi.widget.preference.LoginPreference | ||||
| import eu.kanade.tachiyomi.widget.preference.TrackLoginDialog | ||||
| @@ -63,6 +64,15 @@ class SettingsTrackingController : SettingsController(), | ||||
|                     tabsIntent.launchUrl(activity, ShikimoriApi.authUrl()) | ||||
|                 } | ||||
|             } | ||||
|             trackPreference(trackManager.bangumi) { | ||||
|                 onClick { | ||||
|                     val tabsIntent = CustomTabsIntent.Builder() | ||||
|                             .setToolbarColor(context.getResourceColor(R.attr.colorPrimary)) | ||||
|                             .build() | ||||
|                     tabsIntent.intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY) | ||||
|                     tabsIntent.launchUrl(activity, BangumiApi.authUrl()) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user