|
|
|
@ -4,6 +4,7 @@ import okhttp3.FormBody
|
|
|
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
|
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
|
|
import okhttp3.OkHttpClient
|
|
|
|
import okhttp3.OkHttpClient
|
|
|
|
import okhttp3.Request
|
|
|
|
import okhttp3.Request
|
|
|
|
|
|
|
|
import org.json.JSONObject
|
|
|
|
import org.koitharu.kotatsu.parsers.model.Manga
|
|
|
|
import org.koitharu.kotatsu.parsers.model.Manga
|
|
|
|
import org.koitharu.kotatsu.parsers.util.await
|
|
|
|
import org.koitharu.kotatsu.parsers.util.await
|
|
|
|
import org.koitharu.kotatsu.parsers.util.json.mapJSON
|
|
|
|
import org.koitharu.kotatsu.parsers.util.json.mapJSON
|
|
|
|
@ -13,11 +14,12 @@ import org.koitharu.kotatsu.parsers.util.urlEncoded
|
|
|
|
import org.koitharu.kotatsu.shikimori.data.model.ShikimoriManga
|
|
|
|
import org.koitharu.kotatsu.shikimori.data.model.ShikimoriManga
|
|
|
|
import org.koitharu.kotatsu.shikimori.data.model.ShikimoriMangaInfo
|
|
|
|
import org.koitharu.kotatsu.shikimori.data.model.ShikimoriMangaInfo
|
|
|
|
import org.koitharu.kotatsu.shikimori.data.model.ShikimoriUser
|
|
|
|
import org.koitharu.kotatsu.shikimori.data.model.ShikimoriUser
|
|
|
|
|
|
|
|
import org.koitharu.kotatsu.utils.ext.toRequestBody
|
|
|
|
|
|
|
|
|
|
|
|
private const val CLIENT_ID = "Mw6F0tPEOgyV7F9U9Twg50Q8SndMY7hzIOfXg0AX_XU"
|
|
|
|
private const val CLIENT_ID = "Mw6F0tPEOgyV7F9U9Twg50Q8SndMY7hzIOfXg0AX_XU"
|
|
|
|
private const val CLIENT_SECRET = "euBMt1GGRSDpVIFQVPxZrO7Kh6X4gWyv0dABuj4B-M8"
|
|
|
|
private const val CLIENT_SECRET = "euBMt1GGRSDpVIFQVPxZrO7Kh6X4gWyv0dABuj4B-M8"
|
|
|
|
private const val REDIRECT_URI = "kotatsu://shikimori-auth"
|
|
|
|
private const val REDIRECT_URI = "kotatsu://shikimori-auth"
|
|
|
|
private const val BASE_URL = "https://shikimori.one/api/"
|
|
|
|
private const val BASE_URL = "https://shikimori.one/"
|
|
|
|
private const val MANGA_PAGE_SIZE = 10
|
|
|
|
private const val MANGA_PAGE_SIZE = 10
|
|
|
|
|
|
|
|
|
|
|
|
class ShikimoriRepository(
|
|
|
|
class ShikimoriRepository(
|
|
|
|
@ -26,7 +28,7 @@ class ShikimoriRepository(
|
|
|
|
) {
|
|
|
|
) {
|
|
|
|
|
|
|
|
|
|
|
|
val oauthUrl: String
|
|
|
|
val oauthUrl: String
|
|
|
|
get() = "https://shikimori.one/oauth/authorize?client_id=$CLIENT_ID&" +
|
|
|
|
get() = "${BASE_URL}oauth/authorize?client_id=$CLIENT_ID&" +
|
|
|
|
"redirect_uri=$REDIRECT_URI&response_type=code&scope="
|
|
|
|
"redirect_uri=$REDIRECT_URI&response_type=code&scope="
|
|
|
|
|
|
|
|
|
|
|
|
val isAuthorized: Boolean
|
|
|
|
val isAuthorized: Boolean
|
|
|
|
@ -45,7 +47,7 @@ class ShikimoriRepository(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
val request = Request.Builder()
|
|
|
|
val request = Request.Builder()
|
|
|
|
.post(body.build())
|
|
|
|
.post(body.build())
|
|
|
|
.url("https://shikimori.one/oauth/token")
|
|
|
|
.url("${BASE_URL}oauth/token")
|
|
|
|
val response = okHttp.newCall(request.build()).await().parseJson()
|
|
|
|
val response = okHttp.newCall(request.build()).await().parseJson()
|
|
|
|
storage.accessToken = response.getString("access_token")
|
|
|
|
storage.accessToken = response.getString("access_token")
|
|
|
|
storage.refreshToken = response.getString("refresh_token")
|
|
|
|
storage.refreshToken = response.getString("refresh_token")
|
|
|
|
@ -54,15 +56,24 @@ class ShikimoriRepository(
|
|
|
|
suspend fun getUser(): ShikimoriUser {
|
|
|
|
suspend fun getUser(): ShikimoriUser {
|
|
|
|
val request = Request.Builder()
|
|
|
|
val request = Request.Builder()
|
|
|
|
.get()
|
|
|
|
.get()
|
|
|
|
.url("https://shikimori.one/api/users/whoami")
|
|
|
|
.url("${BASE_URL}api/users/whoami")
|
|
|
|
val response = okHttp.newCall(request.build()).await().parseJson()
|
|
|
|
val response = okHttp.newCall(request.build()).await().parseJson()
|
|
|
|
return ShikimoriUser(response)
|
|
|
|
return ShikimoriUser(response).also { storage.user = it }
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fun getCachedUser(): ShikimoriUser? {
|
|
|
|
|
|
|
|
return storage.user
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fun logout() {
|
|
|
|
|
|
|
|
storage.clear()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
suspend fun findManga(query: String, offset: Int): List<ShikimoriManga> {
|
|
|
|
suspend fun findManga(query: String, offset: Int): List<ShikimoriManga> {
|
|
|
|
val page = offset / MANGA_PAGE_SIZE
|
|
|
|
val page = offset / MANGA_PAGE_SIZE
|
|
|
|
val pageOffset = offset % MANGA_PAGE_SIZE
|
|
|
|
val pageOffset = offset % MANGA_PAGE_SIZE
|
|
|
|
val url = BASE_URL.toHttpUrl().newBuilder()
|
|
|
|
val url = BASE_URL.toHttpUrl().newBuilder()
|
|
|
|
|
|
|
|
.addPathSegment("api")
|
|
|
|
.addPathSegment("mangas")
|
|
|
|
.addPathSegment("mangas")
|
|
|
|
.addEncodedQueryParameter("page", (page + 1).toString())
|
|
|
|
.addEncodedQueryParameter("page", (page + 1).toString())
|
|
|
|
.addEncodedQueryParameter("limit", MANGA_PAGE_SIZE.toString())
|
|
|
|
.addEncodedQueryParameter("limit", MANGA_PAGE_SIZE.toString())
|
|
|
|
@ -75,11 +86,31 @@ class ShikimoriRepository(
|
|
|
|
return if (pageOffset != 0) list.drop(pageOffset) else list
|
|
|
|
return if (pageOffset != 0) list.drop(pageOffset) else list
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
suspend fun trackManga(manga: Manga, shikiMangaId: Long) {
|
|
|
|
|
|
|
|
val user = getCachedUser() ?: getUser()
|
|
|
|
|
|
|
|
val payload = JSONObject()
|
|
|
|
|
|
|
|
payload.put(
|
|
|
|
|
|
|
|
"user_rate",
|
|
|
|
|
|
|
|
JSONObject().apply {
|
|
|
|
|
|
|
|
put("target_id", shikiMangaId)
|
|
|
|
|
|
|
|
put("target_type", "Manga")
|
|
|
|
|
|
|
|
put("user_id", user.id)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
val url = BASE_URL.toHttpUrl().newBuilder()
|
|
|
|
|
|
|
|
.addPathSegment("api")
|
|
|
|
|
|
|
|
.addPathSegment("v2")
|
|
|
|
|
|
|
|
.addPathSegment("user_rates")
|
|
|
|
|
|
|
|
.build()
|
|
|
|
|
|
|
|
val request = Request.Builder().url(url).post(payload.toRequestBody()).build()
|
|
|
|
|
|
|
|
val response = okHttp.newCall(request).await().parseJson()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
suspend fun findMangaInfo(manga: Manga): ShikimoriMangaInfo? {
|
|
|
|
suspend fun findMangaInfo(manga: Manga): ShikimoriMangaInfo? {
|
|
|
|
val q = manga.title.urlEncoded()
|
|
|
|
val q = manga.title.urlEncoded()
|
|
|
|
val request = Request.Builder()
|
|
|
|
val request = Request.Builder()
|
|
|
|
.get()
|
|
|
|
.get()
|
|
|
|
.url("https://shikimori.one/api/mangas?limit=5&search=$q&censored=false")
|
|
|
|
.url("${BASE_URL}api/mangas?limit=5&search=$q&censored=false")
|
|
|
|
val response = okHttp.newCall(request.build()).await().parseJsonArray()
|
|
|
|
val response = okHttp.newCall(request.build()).await().parseJsonArray()
|
|
|
|
val candidates = response.mapJSON { ShikimoriManga(it) }
|
|
|
|
val candidates = response.mapJSON { ShikimoriManga(it) }
|
|
|
|
val bestCandidate = candidates.filter {
|
|
|
|
val bestCandidate = candidates.filter {
|
|
|
|
@ -91,7 +122,7 @@ class ShikimoriRepository(
|
|
|
|
suspend fun getRelatedManga(id: Long): List<ShikimoriManga> {
|
|
|
|
suspend fun getRelatedManga(id: Long): List<ShikimoriManga> {
|
|
|
|
val request = Request.Builder()
|
|
|
|
val request = Request.Builder()
|
|
|
|
.get()
|
|
|
|
.get()
|
|
|
|
.url("https://shikimori.one/api/mangas/$id/related")
|
|
|
|
.url("${BASE_URL}api/mangas/$id/related")
|
|
|
|
val response = okHttp.newCall(request.build()).await().parseJsonArray()
|
|
|
|
val response = okHttp.newCall(request.build()).await().parseJsonArray()
|
|
|
|
return response.mapJSON { jo -> ShikimoriManga(jo) }
|
|
|
|
return response.mapJSON { jo -> ShikimoriManga(jo) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -99,7 +130,7 @@ class ShikimoriRepository(
|
|
|
|
suspend fun getSimilarManga(id: Long): List<ShikimoriManga> {
|
|
|
|
suspend fun getSimilarManga(id: Long): List<ShikimoriManga> {
|
|
|
|
val request = Request.Builder()
|
|
|
|
val request = Request.Builder()
|
|
|
|
.get()
|
|
|
|
.get()
|
|
|
|
.url("https://shikimori.one/api/mangas/$id/similar")
|
|
|
|
.url("${BASE_URL}api/mangas/$id/similar")
|
|
|
|
val response = okHttp.newCall(request.build()).await().parseJsonArray()
|
|
|
|
val response = okHttp.newCall(request.build()).await().parseJsonArray()
|
|
|
|
return response.mapJSON { jo -> ShikimoriManga(jo) }
|
|
|
|
return response.mapJSON { jo -> ShikimoriManga(jo) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -107,7 +138,7 @@ class ShikimoriRepository(
|
|
|
|
suspend fun getMangaInfo(id: Long): ShikimoriMangaInfo {
|
|
|
|
suspend fun getMangaInfo(id: Long): ShikimoriMangaInfo {
|
|
|
|
val request = Request.Builder()
|
|
|
|
val request = Request.Builder()
|
|
|
|
.get()
|
|
|
|
.get()
|
|
|
|
.url("https://shikimori.one/api/mangas/$id")
|
|
|
|
.url("${BASE_URL}api/mangas/$id")
|
|
|
|
val response = okHttp.newCall(request.build()).await().parseJson()
|
|
|
|
val response = okHttp.newCall(request.build()).await().parseJson()
|
|
|
|
return ShikimoriMangaInfo(response)
|
|
|
|
return ShikimoriMangaInfo(response)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|