Linting fixes
This commit is contained in:
@@ -63,7 +63,7 @@ abstract class TrackService(val id: Int) {
|
||||
|
||||
open val isLogged: Boolean
|
||||
get() = getUsername().isNotEmpty() &&
|
||||
getPassword().isNotEmpty()
|
||||
getPassword().isNotEmpty()
|
||||
|
||||
fun getUsername() = preferences.trackUsername(this)!!
|
||||
|
||||
|
||||
@@ -150,18 +150,18 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
|
||||
|
||||
override fun bind(track: Track): Observable<Track> {
|
||||
return api.findLibManga(track, getUsername().toInt())
|
||||
.flatMap { remoteTrack ->
|
||||
if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.library_id = remoteTrack.library_id
|
||||
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)
|
||||
}
|
||||
.flatMap { remoteTrack ->
|
||||
if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.library_id = remoteTrack.library_id
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun search(query: String): Observable<List<TrackSearch>> {
|
||||
@@ -170,11 +170,11 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
|
||||
|
||||
override fun refresh(track: Track): Observable<Track> {
|
||||
return api.getLibManga(track, getUsername().toInt())
|
||||
.map { remoteTrack ->
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.total_chapters = remoteTrack.total_chapters
|
||||
track
|
||||
}
|
||||
.map { remoteTrack ->
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.total_chapters = remoteTrack.total_chapters
|
||||
track
|
||||
}
|
||||
}
|
||||
|
||||
override fun login(username: String, password: String) = login(password)
|
||||
|
||||
@@ -25,7 +25,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
private val authClient = client.newBuilder().addInterceptor(interceptor).build()
|
||||
|
||||
fun addLibManga(track: Track): Observable<Track> {
|
||||
val query = """
|
||||
val query =
|
||||
"""
|
||||
|mutation AddManga(${'$'}mangaId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus) {
|
||||
|SaveMediaListEntry (mediaId: ${'$'}mangaId, progress: ${'$'}progress, status: ${'$'}status) {
|
||||
| id
|
||||
@@ -34,35 +35,36 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
|}
|
||||
|""".trimMargin()
|
||||
val variables = jsonObject(
|
||||
"mangaId" to track.media_id,
|
||||
"progress" to track.last_chapter_read,
|
||||
"status" to track.toAnilistStatus()
|
||||
"mangaId" to track.media_id,
|
||||
"progress" to track.last_chapter_read,
|
||||
"status" to track.toAnilistStatus()
|
||||
)
|
||||
val payload = jsonObject(
|
||||
"query" to query,
|
||||
"variables" to variables
|
||||
"query" to query,
|
||||
"variables" to variables
|
||||
)
|
||||
val body = payload.toString().toRequestBody(jsonMime)
|
||||
val request = Request.Builder()
|
||||
.url(apiUrl)
|
||||
.post(body)
|
||||
.build()
|
||||
.url(apiUrl)
|
||||
.post(body)
|
||||
.build()
|
||||
return authClient.newCall(request)
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
netResponse.close()
|
||||
if (responseBody.isEmpty()) {
|
||||
throw Exception("Null Response")
|
||||
}
|
||||
val response = JsonParser.parseString(responseBody).obj
|
||||
track.library_id = response["data"]["SaveMediaListEntry"]["id"].asLong
|
||||
track
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
netResponse.close()
|
||||
if (responseBody.isEmpty()) {
|
||||
throw Exception("Null Response")
|
||||
}
|
||||
val response = JsonParser.parseString(responseBody).obj
|
||||
track.library_id = response["data"]["SaveMediaListEntry"]["id"].asLong
|
||||
track
|
||||
}
|
||||
}
|
||||
|
||||
fun updateLibManga(track: Track): Observable<Track> {
|
||||
val query = """
|
||||
val query =
|
||||
"""
|
||||
|mutation UpdateManga(${'$'}listId: Int, ${'$'}progress: Int, ${'$'}status: MediaListStatus, ${'$'}score: Int) {
|
||||
|SaveMediaListEntry (id: ${'$'}listId, progress: ${'$'}progress, status: ${'$'}status, scoreRaw: ${'$'}score) {
|
||||
|id
|
||||
@@ -72,29 +74,30 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
|}
|
||||
|""".trimMargin()
|
||||
val variables = jsonObject(
|
||||
"listId" to track.library_id,
|
||||
"progress" to track.last_chapter_read,
|
||||
"status" to track.toAnilistStatus(),
|
||||
"score" to track.score.toInt()
|
||||
"listId" to track.library_id,
|
||||
"progress" to track.last_chapter_read,
|
||||
"status" to track.toAnilistStatus(),
|
||||
"score" to track.score.toInt()
|
||||
)
|
||||
val payload = jsonObject(
|
||||
"query" to query,
|
||||
"variables" to variables
|
||||
"query" to query,
|
||||
"variables" to variables
|
||||
)
|
||||
val body = payload.toString().toRequestBody(jsonMime)
|
||||
val request = Request.Builder()
|
||||
.url(apiUrl)
|
||||
.post(body)
|
||||
.build()
|
||||
.url(apiUrl)
|
||||
.post(body)
|
||||
.build()
|
||||
return authClient.newCall(request)
|
||||
.asObservableSuccess()
|
||||
.map {
|
||||
track
|
||||
}
|
||||
.asObservableSuccess()
|
||||
.map {
|
||||
track
|
||||
}
|
||||
}
|
||||
|
||||
fun search(search: String): Observable<List<TrackSearch>> {
|
||||
val query = """
|
||||
val query =
|
||||
"""
|
||||
|query Search(${'$'}query: String) {
|
||||
|Page (perPage: 50) {
|
||||
|media(search: ${'$'}query, type: MANGA, format_not_in: [NOVEL]) {
|
||||
@@ -119,35 +122,36 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
|}
|
||||
|""".trimMargin()
|
||||
val variables = jsonObject(
|
||||
"query" to search
|
||||
"query" to search
|
||||
)
|
||||
val payload = jsonObject(
|
||||
"query" to query,
|
||||
"variables" to variables
|
||||
"query" to query,
|
||||
"variables" to variables
|
||||
)
|
||||
val body = payload.toString().toRequestBody(jsonMime)
|
||||
val request = Request.Builder()
|
||||
.url(apiUrl)
|
||||
.post(body)
|
||||
.build()
|
||||
.url(apiUrl)
|
||||
.post(body)
|
||||
.build()
|
||||
return authClient.newCall(request)
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
if (responseBody.isEmpty()) {
|
||||
throw Exception("Null Response")
|
||||
}
|
||||
val response = JsonParser.parseString(responseBody).obj
|
||||
val data = response["data"]!!.obj
|
||||
val page = data["Page"].obj
|
||||
val media = page["media"].array
|
||||
val entries = media.map { jsonToALManga(it.obj) }
|
||||
entries.map { it.toTrack() }
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
if (responseBody.isEmpty()) {
|
||||
throw Exception("Null Response")
|
||||
}
|
||||
val response = JsonParser.parseString(responseBody).obj
|
||||
val data = response["data"]!!.obj
|
||||
val page = data["Page"].obj
|
||||
val media = page["media"].array
|
||||
val entries = media.map { jsonToALManga(it.obj) }
|
||||
entries.map { it.toTrack() }
|
||||
}
|
||||
}
|
||||
|
||||
fun findLibManga(track: Track, userid: Int): Observable<Track?> {
|
||||
val query = """
|
||||
val query =
|
||||
"""
|
||||
|query (${'$'}id: Int!, ${'$'}manga_id: Int!) {
|
||||
|Page {
|
||||
|mediaList(userId: ${'$'}id, type: MANGA, mediaId: ${'$'}manga_id) {
|
||||
@@ -178,37 +182,37 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
|}
|
||||
|""".trimMargin()
|
||||
val variables = jsonObject(
|
||||
"id" to userid,
|
||||
"manga_id" to track.media_id
|
||||
"id" to userid,
|
||||
"manga_id" to track.media_id
|
||||
)
|
||||
val payload = jsonObject(
|
||||
"query" to query,
|
||||
"variables" to variables
|
||||
"query" to query,
|
||||
"variables" to variables
|
||||
)
|
||||
val body = payload.toString().toRequestBody(jsonMime)
|
||||
val request = Request.Builder()
|
||||
.url(apiUrl)
|
||||
.post(body)
|
||||
.build()
|
||||
.url(apiUrl)
|
||||
.post(body)
|
||||
.build()
|
||||
return authClient.newCall(request)
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
if (responseBody.isEmpty()) {
|
||||
throw Exception("Null Response")
|
||||
}
|
||||
val response = JsonParser.parseString(responseBody).obj
|
||||
val data = response["data"]!!.obj
|
||||
val page = data["Page"].obj
|
||||
val media = page["mediaList"].array
|
||||
val entries = media.map { jsonToALUserManga(it.obj) }
|
||||
entries.firstOrNull()?.toTrack()
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
if (responseBody.isEmpty()) {
|
||||
throw Exception("Null Response")
|
||||
}
|
||||
val response = JsonParser.parseString(responseBody).obj
|
||||
val data = response["data"]!!.obj
|
||||
val page = data["Page"].obj
|
||||
val media = page["mediaList"].array
|
||||
val entries = media.map { jsonToALUserManga(it.obj) }
|
||||
entries.firstOrNull()?.toTrack()
|
||||
}
|
||||
}
|
||||
|
||||
fun getLibManga(track: Track, userid: Int): Observable<Track> {
|
||||
return findLibManga(track, userid)
|
||||
.map { it ?: throw Exception("Could not find manga") }
|
||||
.map { it ?: throw Exception("Could not find manga") }
|
||||
}
|
||||
|
||||
fun createOAuth(token: String): OAuth {
|
||||
@@ -216,7 +220,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
}
|
||||
|
||||
fun getCurrentUser(): Observable<Pair<Int, String>> {
|
||||
val query = """
|
||||
val query =
|
||||
"""
|
||||
|query User {
|
||||
|Viewer {
|
||||
|id
|
||||
@@ -227,41 +232,48 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
|}
|
||||
|""".trimMargin()
|
||||
val payload = jsonObject(
|
||||
"query" to query
|
||||
"query" to query
|
||||
)
|
||||
val body = payload.toString().toRequestBody(jsonMime)
|
||||
val request = Request.Builder()
|
||||
.url(apiUrl)
|
||||
.post(body)
|
||||
.build()
|
||||
.url(apiUrl)
|
||||
.post(body)
|
||||
.build()
|
||||
return authClient.newCall(request)
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
if (responseBody.isEmpty()) {
|
||||
throw Exception("Null Response")
|
||||
}
|
||||
val response = JsonParser.parseString(responseBody).obj
|
||||
val data = response["data"]!!.obj
|
||||
val viewer = data["Viewer"].obj
|
||||
Pair(viewer["id"].asInt, viewer["mediaListOptions"]["scoreFormat"].asString)
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
if (responseBody.isEmpty()) {
|
||||
throw Exception("Null Response")
|
||||
}
|
||||
val response = JsonParser.parseString(responseBody).obj
|
||||
val data = response["data"]!!.obj
|
||||
val viewer = data["Viewer"].obj
|
||||
Pair(viewer["id"].asInt, viewer["mediaListOptions"]["scoreFormat"].asString)
|
||||
}
|
||||
}
|
||||
|
||||
private fun jsonToALManga(struct: JsonObject): ALManga {
|
||||
val date = try {
|
||||
val date = Calendar.getInstance()
|
||||
date.set(struct["startDate"]["year"].nullInt ?: 0, (struct["startDate"]["month"].nullInt
|
||||
?: 0) - 1,
|
||||
struct["startDate"]["day"].nullInt ?: 0)
|
||||
date.set(
|
||||
struct["startDate"]["year"].nullInt ?: 0,
|
||||
(
|
||||
struct["startDate"]["month"].nullInt
|
||||
?: 0
|
||||
) - 1,
|
||||
struct["startDate"]["day"].nullInt ?: 0
|
||||
)
|
||||
date.timeInMillis
|
||||
} catch (_: Exception) {
|
||||
0L
|
||||
}
|
||||
|
||||
return ALManga(struct["id"].asInt, struct["title"]["romaji"].asString, struct["coverImage"]["large"].asString,
|
||||
struct["description"].nullString.orEmpty(), struct["type"].asString, struct["status"].asString,
|
||||
date, struct["chapters"].nullInt ?: 0)
|
||||
return ALManga(
|
||||
struct["id"].asInt, struct["title"]["romaji"].asString, struct["coverImage"]["large"].asString,
|
||||
struct["description"].nullString.orEmpty(), struct["type"].asString, struct["status"].asString,
|
||||
date, struct["chapters"].nullInt ?: 0
|
||||
)
|
||||
}
|
||||
|
||||
private fun jsonToALUserManga(struct: JsonObject): ALUserManga {
|
||||
@@ -280,8 +292,8 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
}
|
||||
|
||||
fun authUrl() = Uri.parse("${baseUrl}oauth/authorize").buildUpon()
|
||||
.appendQueryParameter("client_id", clientId)
|
||||
.appendQueryParameter("response_type", "token")
|
||||
.build()
|
||||
.appendQueryParameter("client_id", clientId)
|
||||
.appendQueryParameter("response_type", "token")
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,8 +38,8 @@ class AnilistInterceptor(val anilist: Anilist, private var token: String?) : Int
|
||||
|
||||
// Add the authorization header to the original request.
|
||||
val authRequest = originalRequest.newBuilder()
|
||||
.addHeader("Authorization", "Bearer ${oauth!!.access_token}")
|
||||
.build()
|
||||
.addHeader("Authorization", "Bearer ${oauth!!.access_token}")
|
||||
.build()
|
||||
|
||||
return chain.proceed(authRequest)
|
||||
}
|
||||
|
||||
@@ -39,23 +39,23 @@ class Bangumi(private val context: Context, id: Int) : TrackService(id) {
|
||||
|
||||
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
|
||||
refresh(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)
|
||||
}
|
||||
.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
|
||||
refresh(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>> {
|
||||
@@ -64,17 +64,17 @@ class Bangumi(private val context: Context, id: Int) : TrackService(id) {
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
.flatMap {
|
||||
track.copyPersonalFrom(it!!)
|
||||
api.findLibManga(track)
|
||||
.map { remoteTrack ->
|
||||
if (remoteTrack != null) {
|
||||
track.total_chapters = remoteTrack.total_chapters
|
||||
track.status = remoteTrack.status
|
||||
}
|
||||
track
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLogo() = R.drawable.ic_tracker_bangumi
|
||||
|
||||
@@ -26,73 +26,74 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
||||
|
||||
fun addLibManga(track: Track): Observable<Track> {
|
||||
val body = FormBody.Builder()
|
||||
.add("rating", track.score.toInt().toString())
|
||||
.add("status", track.toBangumiStatus())
|
||||
.build()
|
||||
.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()
|
||||
.url("$apiUrl/collection/${track.media_id}/update")
|
||||
.post(body)
|
||||
.build()
|
||||
return authClient.newCall(request)
|
||||
.asObservableSuccess()
|
||||
.map {
|
||||
track
|
||||
}
|
||||
.asObservableSuccess()
|
||||
.map {
|
||||
track
|
||||
}
|
||||
}
|
||||
|
||||
fun updateLibManga(track: Track): Observable<Track> {
|
||||
// chapter update
|
||||
val body = FormBody.Builder()
|
||||
.add("watched_eps", track.last_chapter_read.toString())
|
||||
.build()
|
||||
.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()
|
||||
.url("$apiUrl/subject/${track.media_id}/update/watched_eps")
|
||||
.post(body)
|
||||
.build()
|
||||
|
||||
// read status update
|
||||
val sbody = FormBody.Builder()
|
||||
.add("status", track.toBangumiStatus())
|
||||
.build()
|
||||
.add("status", track.toBangumiStatus())
|
||||
.build()
|
||||
val srequest = Request.Builder()
|
||||
.url("$apiUrl/collection/${track.media_id}/update")
|
||||
.post(sbody)
|
||||
.build()
|
||||
.url("$apiUrl/collection/${track.media_id}/update")
|
||||
.post(sbody)
|
||||
.build()
|
||||
return authClient.newCall(srequest)
|
||||
.asObservableSuccess()
|
||||
.map {
|
||||
track
|
||||
}.flatMap {
|
||||
authClient.newCall(request)
|
||||
.asObservableSuccess()
|
||||
.map {
|
||||
track
|
||||
}
|
||||
}
|
||||
.asObservableSuccess()
|
||||
.map {
|
||||
track
|
||||
}.flatMap {
|
||||
authClient.newCall(request)
|
||||
.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()
|
||||
"$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()
|
||||
.url(url.toString())
|
||||
.get()
|
||||
.build()
|
||||
return authClient.newCall(request)
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
var responseBody = netResponse.body?.string().orEmpty()
|
||||
if (responseBody.isEmpty()) {
|
||||
throw Exception("Null Response")
|
||||
}
|
||||
if (responseBody.contains("\"code\":404")) {
|
||||
responseBody = "{\"results\":0,\"list\":[]}"
|
||||
}
|
||||
val response = JsonParser.parseString(responseBody).obj["list"]?.array
|
||||
response?.filter { it.obj["type"].asInt == 1 }?.map { jsonToSearch(it.obj) }
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
var responseBody = netResponse.body?.string().orEmpty()
|
||||
if (responseBody.isEmpty()) {
|
||||
throw Exception("Null Response")
|
||||
}
|
||||
if (responseBody.contains("\"code\":404")) {
|
||||
responseBody = "{\"results\":0,\"list\":[]}"
|
||||
}
|
||||
val response = JsonParser.parseString(responseBody).obj["list"]?.array
|
||||
response?.filter { it.obj["type"].asInt == 1 }?.map { jsonToSearch(it.obj) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun jsonToSearch(obj: JsonObject): TrackSearch {
|
||||
@@ -109,9 +110,15 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
||||
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
|
||||
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
|
||||
}
|
||||
@@ -120,37 +127,37 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
||||
fun findLibManga(track: Track): Observable<Track?> {
|
||||
val urlMangas = "$apiUrl/subject/${track.media_id}"
|
||||
val requestMangas = Request.Builder()
|
||||
.url(urlMangas)
|
||||
.get()
|
||||
.build()
|
||||
.url(urlMangas)
|
||||
.get()
|
||||
.build()
|
||||
|
||||
return authClient.newCall(requestMangas)
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
// get comic info
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
jsonToTrack(JsonParser.parseString(responseBody).obj)
|
||||
}
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
// get comic info
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
jsonToTrack(JsonParser.parseString(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()
|
||||
.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
|
||||
}
|
||||
.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> {
|
||||
@@ -163,14 +170,15 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
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 {
|
||||
@@ -190,19 +198,21 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
|
||||
}
|
||||
|
||||
fun authUrl() =
|
||||
Uri.parse(loginUrl).buildUpon()
|
||||
.appendQueryParameter("client_id", clientId)
|
||||
.appendQueryParameter("response_type", "code")
|
||||
.appendQueryParameter("redirect_uri", redirectUrl)
|
||||
.build()
|
||||
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())
|
||||
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()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,25 +36,28 @@ class BangumiInterceptor(val bangumi: Bangumi, val gson: Gson) : Interceptor {
|
||||
}
|
||||
|
||||
val 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()
|
||||
.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)
|
||||
oauth.access_token,
|
||||
oauth.token_type,
|
||||
System.currentTimeMillis() / 1000,
|
||||
oauth.expires_in,
|
||||
oauth.refresh_token,
|
||||
this.oauth?.user_id
|
||||
)
|
||||
|
||||
bangumi.saveToken(oauth)
|
||||
}
|
||||
|
||||
@@ -78,17 +78,17 @@ class Kitsu(private val context: Context, id: Int) : TrackService(id) {
|
||||
|
||||
override fun bind(track: Track): Observable<Track> {
|
||||
return api.findLibManga(track, getUserId())
|
||||
.flatMap { remoteTrack ->
|
||||
if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.media_id = remoteTrack.media_id
|
||||
update(track)
|
||||
} else {
|
||||
track.score = DEFAULT_SCORE
|
||||
track.status = DEFAULT_STATUS
|
||||
add(track)
|
||||
}
|
||||
.flatMap { remoteTrack ->
|
||||
if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.media_id = remoteTrack.media_id
|
||||
update(track)
|
||||
} else {
|
||||
track.score = DEFAULT_SCORE
|
||||
track.status = DEFAULT_STATUS
|
||||
add(track)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun search(query: String): Observable<List<TrackSearch>> {
|
||||
@@ -97,20 +97,20 @@ class Kitsu(private val context: Context, id: Int) : TrackService(id) {
|
||||
|
||||
override fun refresh(track: Track): Observable<Track> {
|
||||
return api.getLibManga(track)
|
||||
.map { remoteTrack ->
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.total_chapters = remoteTrack.total_chapters
|
||||
track
|
||||
}
|
||||
.map { remoteTrack ->
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.total_chapters = remoteTrack.total_chapters
|
||||
track
|
||||
}
|
||||
}
|
||||
|
||||
override fun login(username: String, password: String): Completable {
|
||||
return api.login(username, password)
|
||||
.doOnNext { interceptor.newAuth(it) }
|
||||
.flatMap { api.getCurrentUser() }
|
||||
.doOnNext { userId -> saveCredentials(username, userId) }
|
||||
.doOnError { logout() }
|
||||
.toCompletable()
|
||||
.doOnNext { interceptor.newAuth(it) }
|
||||
.flatMap { api.getCurrentUser() }
|
||||
.doOnNext { userId -> saveCredentials(username, userId) }
|
||||
.doOnError { logout() }
|
||||
.toCompletable()
|
||||
}
|
||||
|
||||
override fun logout() {
|
||||
|
||||
@@ -33,59 +33,59 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
||||
private val authClient = client.newBuilder().addInterceptor(interceptor).build()
|
||||
|
||||
private val rest = Retrofit.Builder()
|
||||
.baseUrl(baseUrl)
|
||||
.client(authClient)
|
||||
.addConverterFactory(GsonConverterFactory.create(GsonBuilder().serializeNulls().create()))
|
||||
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
|
||||
.build()
|
||||
.create(Rest::class.java)
|
||||
.baseUrl(baseUrl)
|
||||
.client(authClient)
|
||||
.addConverterFactory(GsonConverterFactory.create(GsonBuilder().serializeNulls().create()))
|
||||
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
|
||||
.build()
|
||||
.create(Rest::class.java)
|
||||
|
||||
private val searchRest = Retrofit.Builder()
|
||||
.baseUrl(algoliaKeyUrl)
|
||||
.client(authClient)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
|
||||
.build()
|
||||
.create(SearchKeyRest::class.java)
|
||||
.baseUrl(algoliaKeyUrl)
|
||||
.client(authClient)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
|
||||
.build()
|
||||
.create(SearchKeyRest::class.java)
|
||||
|
||||
private val algoliaRest = Retrofit.Builder()
|
||||
.baseUrl(algoliaUrl)
|
||||
.client(client)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
|
||||
.build()
|
||||
.create(AgoliaSearchRest::class.java)
|
||||
.baseUrl(algoliaUrl)
|
||||
.client(client)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
|
||||
.build()
|
||||
.create(AgoliaSearchRest::class.java)
|
||||
|
||||
fun addLibManga(track: Track, userId: String): Observable<Track> {
|
||||
return Observable.defer {
|
||||
// @formatter:off
|
||||
val data = jsonObject(
|
||||
"type" to "libraryEntries",
|
||||
"attributes" to jsonObject(
|
||||
"status" to track.toKitsuStatus(),
|
||||
"progress" to track.last_chapter_read
|
||||
"type" to "libraryEntries",
|
||||
"attributes" to jsonObject(
|
||||
"status" to track.toKitsuStatus(),
|
||||
"progress" to track.last_chapter_read
|
||||
),
|
||||
"relationships" to jsonObject(
|
||||
"user" to jsonObject(
|
||||
"data" to jsonObject(
|
||||
"id" to userId,
|
||||
"type" to "users"
|
||||
)
|
||||
),
|
||||
"relationships" to jsonObject(
|
||||
"user" to jsonObject(
|
||||
"data" to jsonObject(
|
||||
"id" to userId,
|
||||
"type" to "users"
|
||||
)
|
||||
),
|
||||
"media" to jsonObject(
|
||||
"data" to jsonObject(
|
||||
"id" to track.media_id,
|
||||
"type" to "manga"
|
||||
)
|
||||
)
|
||||
"media" to jsonObject(
|
||||
"data" to jsonObject(
|
||||
"id" to track.media_id,
|
||||
"type" to "manga"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
rest.addLibManga(jsonObject("data" to data))
|
||||
.map { json ->
|
||||
track.media_id = json["data"]["id"].int
|
||||
track
|
||||
}
|
||||
.map { json ->
|
||||
track.media_id = json["data"]["id"].int
|
||||
track
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,77 +93,77 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
||||
return Observable.defer {
|
||||
// @formatter:off
|
||||
val data = jsonObject(
|
||||
"type" to "libraryEntries",
|
||||
"id" to track.media_id,
|
||||
"attributes" to jsonObject(
|
||||
"status" to track.toKitsuStatus(),
|
||||
"progress" to track.last_chapter_read,
|
||||
"ratingTwenty" to track.toKitsuScore()
|
||||
)
|
||||
"type" to "libraryEntries",
|
||||
"id" to track.media_id,
|
||||
"attributes" to jsonObject(
|
||||
"status" to track.toKitsuStatus(),
|
||||
"progress" to track.last_chapter_read,
|
||||
"ratingTwenty" to track.toKitsuScore()
|
||||
)
|
||||
)
|
||||
// @formatter:on
|
||||
|
||||
rest.updateLibManga(track.media_id, jsonObject("data" to data))
|
||||
.map { track }
|
||||
.map { track }
|
||||
}
|
||||
}
|
||||
|
||||
fun search(query: String): Observable<List<TrackSearch>> {
|
||||
return searchRest
|
||||
.getKey().map { json ->
|
||||
json["media"].asJsonObject["key"].string
|
||||
}.flatMap { key ->
|
||||
algoliaSearch(key, query)
|
||||
}
|
||||
.getKey().map { json ->
|
||||
json["media"].asJsonObject["key"].string
|
||||
}.flatMap { key ->
|
||||
algoliaSearch(key, query)
|
||||
}
|
||||
}
|
||||
|
||||
private fun algoliaSearch(key: String, query: String): Observable<List<TrackSearch>> {
|
||||
val jsonObject = jsonObject("params" to "query=$query$algoliaFilter")
|
||||
return algoliaRest
|
||||
.getSearchQuery(algoliaAppId, key, jsonObject)
|
||||
.map { json ->
|
||||
val data = json["hits"].array
|
||||
data.map { KitsuSearchManga(it.obj) }
|
||||
.filter { it.subType != "novel" }
|
||||
.map { it.toTrack() }
|
||||
}
|
||||
.getSearchQuery(algoliaAppId, key, jsonObject)
|
||||
.map { json ->
|
||||
val data = json["hits"].array
|
||||
data.map { KitsuSearchManga(it.obj) }
|
||||
.filter { it.subType != "novel" }
|
||||
.map { it.toTrack() }
|
||||
}
|
||||
}
|
||||
|
||||
fun findLibManga(track: Track, userId: String): Observable<Track?> {
|
||||
return rest.findLibManga(track.media_id, userId)
|
||||
.map { json ->
|
||||
val data = json["data"].array
|
||||
if (data.size() > 0) {
|
||||
val manga = json["included"].array[0].obj
|
||||
KitsuLibManga(data[0].obj, manga).toTrack()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
.map { json ->
|
||||
val data = json["data"].array
|
||||
if (data.size() > 0) {
|
||||
val manga = json["included"].array[0].obj
|
||||
KitsuLibManga(data[0].obj, manga).toTrack()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getLibManga(track: Track): Observable<Track> {
|
||||
return rest.getLibManga(track.media_id)
|
||||
.map { json ->
|
||||
val data = json["data"].array
|
||||
if (data.size() > 0) {
|
||||
val manga = json["included"].array[0].obj
|
||||
KitsuLibManga(data[0].obj, manga).toTrack()
|
||||
} else {
|
||||
throw Exception("Could not find manga")
|
||||
}
|
||||
.map { json ->
|
||||
val data = json["data"].array
|
||||
if (data.size() > 0) {
|
||||
val manga = json["included"].array[0].obj
|
||||
KitsuLibManga(data[0].obj, manga).toTrack()
|
||||
} else {
|
||||
throw Exception("Could not find manga")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun login(username: String, password: String): Observable<OAuth> {
|
||||
return Retrofit.Builder()
|
||||
.baseUrl(loginUrl)
|
||||
.client(client)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
|
||||
.build()
|
||||
.create(LoginRest::class.java)
|
||||
.requestAccessToken(username, password)
|
||||
.baseUrl(loginUrl)
|
||||
.client(client)
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
|
||||
.build()
|
||||
.create(LoginRest::class.java)
|
||||
.requestAccessToken(username, password)
|
||||
}
|
||||
|
||||
fun getCurrentUser(): Observable<String> {
|
||||
@@ -242,12 +242,14 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
||||
return baseMangaUrl + remoteId
|
||||
}
|
||||
|
||||
fun refreshTokenRequest(token: String) = POST("${loginUrl}oauth/token",
|
||||
body = FormBody.Builder()
|
||||
.add("grant_type", "refresh_token")
|
||||
.add("client_id", clientId)
|
||||
.add("client_secret", clientSecret)
|
||||
.add("refresh_token", token)
|
||||
.build())
|
||||
fun refreshTokenRequest(token: String) = POST(
|
||||
"${loginUrl}oauth/token",
|
||||
body = FormBody.Builder()
|
||||
.add("grant_type", "refresh_token")
|
||||
.add("client_id", clientId)
|
||||
.add("client_secret", clientSecret)
|
||||
.add("refresh_token", token)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,10 +30,10 @@ class KitsuInterceptor(val kitsu: Kitsu, val gson: Gson) : Interceptor {
|
||||
|
||||
// Add the authorization header to the original request.
|
||||
val authRequest = originalRequest.newBuilder()
|
||||
.addHeader("Authorization", "Bearer ${oauth!!.access_token}")
|
||||
.header("Accept", "application/vnd.api+json")
|
||||
.header("Content-Type", "application/vnd.api+json")
|
||||
.build()
|
||||
.addHeader("Authorization", "Bearer ${oauth!!.access_token}")
|
||||
.header("Accept", "application/vnd.api+json")
|
||||
.header("Content-Type", "application/vnd.api+json")
|
||||
.build()
|
||||
|
||||
return chain.proceed(authRequest)
|
||||
}
|
||||
|
||||
@@ -74,17 +74,17 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) {
|
||||
|
||||
override fun bind(track: Track): Observable<Track> {
|
||||
return api.findLibManga(track)
|
||||
.flatMap { remoteTrack ->
|
||||
if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
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)
|
||||
}
|
||||
.flatMap { remoteTrack ->
|
||||
if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun search(query: String): Observable<List<TrackSearch>> {
|
||||
@@ -93,21 +93,21 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) {
|
||||
|
||||
override fun refresh(track: Track): Observable<Track> {
|
||||
return api.getLibManga(track)
|
||||
.map { remoteTrack ->
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.total_chapters = remoteTrack.total_chapters
|
||||
track
|
||||
}
|
||||
.map { remoteTrack ->
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.total_chapters = remoteTrack.total_chapters
|
||||
track
|
||||
}
|
||||
}
|
||||
|
||||
override fun login(username: String, password: String): Completable {
|
||||
logout()
|
||||
|
||||
return Observable.fromCallable { api.login(username, password) }
|
||||
.doOnNext { csrf -> saveCSRF(csrf) }
|
||||
.doOnNext { saveCredentials(username, password) }
|
||||
.doOnError { logout() }
|
||||
.toCompletable()
|
||||
.doOnNext { csrf -> saveCSRF(csrf) }
|
||||
.doOnNext { saveCredentials(username, password) }
|
||||
.doOnError { logout() }
|
||||
.toCompletable()
|
||||
}
|
||||
|
||||
fun refreshLogin() {
|
||||
@@ -141,8 +141,8 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) {
|
||||
|
||||
val isAuthorized: Boolean
|
||||
get() = super.isLogged &&
|
||||
getCSRF().isNotEmpty() &&
|
||||
checkCookies()
|
||||
getCSRF().isNotEmpty() &&
|
||||
checkCookies()
|
||||
|
||||
fun getCSRF(): String = preferences.trackToken(this).get()
|
||||
|
||||
@@ -152,8 +152,9 @@ class MyAnimeList(private val context: Context, id: Int) : TrackService(id) {
|
||||
var ckCount = 0
|
||||
val url = BASE_URL.toHttpUrlOrNull()!!
|
||||
for (ck in networkService.cookieManager.get(url)) {
|
||||
if (ck.name == USER_SESSION_COOKIE || ck.name == LOGGED_IN_COOKIE)
|
||||
if (ck.name == USER_SESSION_COOKIE || ck.name == LOGGED_IN_COOKIE) {
|
||||
ckCount++
|
||||
}
|
||||
}
|
||||
|
||||
return ckCount == 2
|
||||
|
||||
@@ -39,43 +39,45 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
||||
return if (query.startsWith(PREFIX_MY)) {
|
||||
val realQuery = query.removePrefix(PREFIX_MY)
|
||||
getList()
|
||||
.flatMap { Observable.from(it) }
|
||||
.filter { it.title.contains(realQuery, true) }
|
||||
.toList()
|
||||
.flatMap { Observable.from(it) }
|
||||
.filter { it.title.contains(realQuery, true) }
|
||||
.toList()
|
||||
} else {
|
||||
client.newCall(GET(searchUrl(query)))
|
||||
.asObservable()
|
||||
.flatMap { response ->
|
||||
Observable.from(Jsoup.parse(response.consumeBody())
|
||||
.select("div.js-categories-seasonal.js-block-list.list")
|
||||
.select("table").select("tbody")
|
||||
.select("tr").drop(1))
|
||||
.asObservable()
|
||||
.flatMap { response ->
|
||||
Observable.from(
|
||||
Jsoup.parse(response.consumeBody())
|
||||
.select("div.js-categories-seasonal.js-block-list.list")
|
||||
.select("table").select("tbody")
|
||||
.select("tr").drop(1)
|
||||
)
|
||||
}
|
||||
.filter { row ->
|
||||
row.select(TD)[2].text() != "Novel"
|
||||
}
|
||||
.map { row ->
|
||||
TrackSearch.create(TrackManager.MYANIMELIST).apply {
|
||||
title = row.searchTitle()
|
||||
media_id = row.searchMediaId()
|
||||
total_chapters = row.searchTotalChapters()
|
||||
summary = row.searchSummary()
|
||||
cover_url = row.searchCoverUrl()
|
||||
tracking_url = mangaUrl(media_id)
|
||||
publishing_status = row.searchPublishingStatus()
|
||||
publishing_type = row.searchPublishingType()
|
||||
start_date = row.searchStartDate()
|
||||
}
|
||||
.filter { row ->
|
||||
row.select(TD)[2].text() != "Novel"
|
||||
}
|
||||
.map { row ->
|
||||
TrackSearch.create(TrackManager.MYANIMELIST).apply {
|
||||
title = row.searchTitle()
|
||||
media_id = row.searchMediaId()
|
||||
total_chapters = row.searchTotalChapters()
|
||||
summary = row.searchSummary()
|
||||
cover_url = row.searchCoverUrl()
|
||||
tracking_url = mangaUrl(media_id)
|
||||
publishing_status = row.searchPublishingStatus()
|
||||
publishing_type = row.searchPublishingType()
|
||||
start_date = row.searchStartDate()
|
||||
}
|
||||
}
|
||||
.toList()
|
||||
}
|
||||
.toList()
|
||||
}
|
||||
}
|
||||
|
||||
fun addLibManga(track: Track): Observable<Track> {
|
||||
return Observable.defer {
|
||||
authClient.newCall(POST(url = addUrl(), body = mangaPostPayload(track)))
|
||||
.asObservableSuccess()
|
||||
.map { track }
|
||||
.asObservableSuccess()
|
||||
.map { track }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,40 +97,40 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
||||
|
||||
// Update remote
|
||||
authClient.newCall(POST(url = editPageUrl(track.media_id), body = mangaEditPostBody(editData)))
|
||||
.asObservableSuccess()
|
||||
.map {
|
||||
track
|
||||
}
|
||||
.asObservableSuccess()
|
||||
.map {
|
||||
track
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun findLibManga(track: Track): Observable<Track?> {
|
||||
return authClient.newCall(GET(url = editPageUrl(track.media_id)))
|
||||
.asObservable()
|
||||
.map { response ->
|
||||
var libTrack: Track? = null
|
||||
response.use {
|
||||
if (it.priorResponse?.isRedirect != true) {
|
||||
val trackForm = Jsoup.parse(it.consumeBody())
|
||||
.asObservable()
|
||||
.map { response ->
|
||||
var libTrack: Track? = null
|
||||
response.use {
|
||||
if (it.priorResponse?.isRedirect != true) {
|
||||
val trackForm = Jsoup.parse(it.consumeBody())
|
||||
|
||||
libTrack = Track.create(TrackManager.MYANIMELIST).apply {
|
||||
last_chapter_read = trackForm.select("#add_manga_num_read_chapters").`val`().toInt()
|
||||
total_chapters = trackForm.select("#totalChap").text().toInt()
|
||||
status = trackForm.select("#add_manga_status > option[selected]").`val`().toInt()
|
||||
score = trackForm.select("#add_manga_score > option[selected]").`val`().toFloatOrNull()
|
||||
?: 0f
|
||||
started_reading_date = trackForm.searchDatePicker("#add_manga_start_date")
|
||||
finished_reading_date = trackForm.searchDatePicker("#add_manga_finish_date")
|
||||
}
|
||||
libTrack = Track.create(TrackManager.MYANIMELIST).apply {
|
||||
last_chapter_read = trackForm.select("#add_manga_num_read_chapters").`val`().toInt()
|
||||
total_chapters = trackForm.select("#totalChap").text().toInt()
|
||||
status = trackForm.select("#add_manga_status > option[selected]").`val`().toInt()
|
||||
score = trackForm.select("#add_manga_score > option[selected]").`val`().toFloatOrNull()
|
||||
?: 0f
|
||||
started_reading_date = trackForm.searchDatePicker("#add_manga_start_date")
|
||||
finished_reading_date = trackForm.searchDatePicker("#add_manga_finish_date")
|
||||
}
|
||||
}
|
||||
libTrack
|
||||
}
|
||||
libTrack
|
||||
}
|
||||
}
|
||||
|
||||
fun getLibManga(track: Track): Observable<Track> {
|
||||
return findLibManga(track)
|
||||
.map { it ?: throw Exception("Could not find manga") }
|
||||
.map { it ?: throw Exception("Could not find manga") }
|
||||
}
|
||||
|
||||
fun login(username: String, password: String): String {
|
||||
@@ -143,8 +145,8 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
||||
val response = client.newCall(GET(loginUrl())).execute()
|
||||
|
||||
return Jsoup.parse(response.consumeBody())
|
||||
.select("meta[name=csrf_token]")
|
||||
.attr("content")
|
||||
.select("meta[name=csrf_token]")
|
||||
.attr("content")
|
||||
}
|
||||
|
||||
private fun login(username: String, password: String, csrf: String) {
|
||||
@@ -157,45 +159,45 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
||||
|
||||
private fun getList(): Observable<List<TrackSearch>> {
|
||||
return getListUrl()
|
||||
.flatMap { url ->
|
||||
getListXml(url)
|
||||
.flatMap { url ->
|
||||
getListXml(url)
|
||||
}
|
||||
.flatMap { doc ->
|
||||
Observable.from(doc.select("manga"))
|
||||
}
|
||||
.map {
|
||||
TrackSearch.create(TrackManager.MYANIMELIST).apply {
|
||||
title = it.selectText("manga_title")!!
|
||||
media_id = it.selectInt("manga_mangadb_id")
|
||||
last_chapter_read = it.selectInt("my_read_chapters")
|
||||
status = getStatus(it.selectText("my_status")!!)
|
||||
score = it.selectInt("my_score").toFloat()
|
||||
total_chapters = it.selectInt("manga_chapters")
|
||||
tracking_url = mangaUrl(media_id)
|
||||
started_reading_date = it.searchDateXml("my_start_date")
|
||||
finished_reading_date = it.searchDateXml("my_finish_date")
|
||||
}
|
||||
.flatMap { doc ->
|
||||
Observable.from(doc.select("manga"))
|
||||
}
|
||||
.map {
|
||||
TrackSearch.create(TrackManager.MYANIMELIST).apply {
|
||||
title = it.selectText("manga_title")!!
|
||||
media_id = it.selectInt("manga_mangadb_id")
|
||||
last_chapter_read = it.selectInt("my_read_chapters")
|
||||
status = getStatus(it.selectText("my_status")!!)
|
||||
score = it.selectInt("my_score").toFloat()
|
||||
total_chapters = it.selectInt("manga_chapters")
|
||||
tracking_url = mangaUrl(media_id)
|
||||
started_reading_date = it.searchDateXml("my_start_date")
|
||||
finished_reading_date = it.searchDateXml("my_finish_date")
|
||||
}
|
||||
}
|
||||
.toList()
|
||||
}
|
||||
.toList()
|
||||
}
|
||||
|
||||
private fun getListUrl(): Observable<String> {
|
||||
return authClient.newCall(POST(url = exportListUrl(), body = exportPostBody()))
|
||||
.asObservable()
|
||||
.map { response ->
|
||||
baseUrl + Jsoup.parse(response.consumeBody())
|
||||
.select("div.goodresult")
|
||||
.select("a")
|
||||
.attr("href")
|
||||
}
|
||||
.asObservable()
|
||||
.map { response ->
|
||||
baseUrl + Jsoup.parse(response.consumeBody())
|
||||
.select("div.goodresult")
|
||||
.select("a")
|
||||
.attr("href")
|
||||
}
|
||||
}
|
||||
|
||||
private fun getListXml(url: String): Observable<Document> {
|
||||
return authClient.newCall(GET(url))
|
||||
.asObservable()
|
||||
.map { response ->
|
||||
Jsoup.parse(response.consumeXmlBody(), "", Parser.xmlParser())
|
||||
}
|
||||
.asObservable()
|
||||
.map { response ->
|
||||
Jsoup.parse(response.consumeXmlBody(), "", Parser.xmlParser())
|
||||
}
|
||||
}
|
||||
|
||||
private fun Response.consumeBody(): String? {
|
||||
@@ -222,28 +224,28 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
||||
val tables = page.select("form#main-form table")
|
||||
|
||||
return MyAnimeListEditData(
|
||||
entry_id = tables[0].select("input[name=entry_id]").`val`(), // Always 0
|
||||
manga_id = tables[0].select("#manga_id").`val`(),
|
||||
status = tables[0].select("#add_manga_status > option[selected]").`val`(),
|
||||
num_read_volumes = tables[0].select("#add_manga_num_read_volumes").`val`(),
|
||||
last_completed_vol = tables[0].select("input[name=last_completed_vol]").`val`(), // Always empty
|
||||
num_read_chapters = tables[0].select("#add_manga_num_read_chapters").`val`(),
|
||||
score = tables[0].select("#add_manga_score > option[selected]").`val`(),
|
||||
start_date_month = tables[0].select("#add_manga_start_date_month > option[selected]").`val`(),
|
||||
start_date_day = tables[0].select("#add_manga_start_date_day > option[selected]").`val`(),
|
||||
start_date_year = tables[0].select("#add_manga_start_date_year > option[selected]").`val`(),
|
||||
finish_date_month = tables[0].select("#add_manga_finish_date_month > option[selected]").`val`(),
|
||||
finish_date_day = tables[0].select("#add_manga_finish_date_day > option[selected]").`val`(),
|
||||
finish_date_year = tables[0].select("#add_manga_finish_date_year > option[selected]").`val`(),
|
||||
tags = tables[1].select("#add_manga_tags").`val`(),
|
||||
priority = tables[1].select("#add_manga_priority > option[selected]").`val`(),
|
||||
storage_type = tables[1].select("#add_manga_storage_type > option[selected]").`val`(),
|
||||
num_retail_volumes = tables[1].select("#add_manga_num_retail_volumes").`val`(),
|
||||
num_read_times = tables[1].select("#add_manga_num_read_times").`val`(),
|
||||
reread_value = tables[1].select("#add_manga_reread_value > option[selected]").`val`(),
|
||||
comments = tables[1].select("#add_manga_comments").`val`(),
|
||||
is_asked_to_discuss = tables[1].select("#add_manga_is_asked_to_discuss > option[selected]").`val`(),
|
||||
sns_post_type = tables[1].select("#add_manga_sns_post_type > option[selected]").`val`()
|
||||
entry_id = tables[0].select("input[name=entry_id]").`val`(), // Always 0
|
||||
manga_id = tables[0].select("#manga_id").`val`(),
|
||||
status = tables[0].select("#add_manga_status > option[selected]").`val`(),
|
||||
num_read_volumes = tables[0].select("#add_manga_num_read_volumes").`val`(),
|
||||
last_completed_vol = tables[0].select("input[name=last_completed_vol]").`val`(), // Always empty
|
||||
num_read_chapters = tables[0].select("#add_manga_num_read_chapters").`val`(),
|
||||
score = tables[0].select("#add_manga_score > option[selected]").`val`(),
|
||||
start_date_month = tables[0].select("#add_manga_start_date_month > option[selected]").`val`(),
|
||||
start_date_day = tables[0].select("#add_manga_start_date_day > option[selected]").`val`(),
|
||||
start_date_year = tables[0].select("#add_manga_start_date_year > option[selected]").`val`(),
|
||||
finish_date_month = tables[0].select("#add_manga_finish_date_month > option[selected]").`val`(),
|
||||
finish_date_day = tables[0].select("#add_manga_finish_date_day > option[selected]").`val`(),
|
||||
finish_date_year = tables[0].select("#add_manga_finish_date_year > option[selected]").`val`(),
|
||||
tags = tables[1].select("#add_manga_tags").`val`(),
|
||||
priority = tables[1].select("#add_manga_priority > option[selected]").`val`(),
|
||||
storage_type = tables[1].select("#add_manga_storage_type > option[selected]").`val`(),
|
||||
num_retail_volumes = tables[1].select("#add_manga_num_retail_volumes").`val`(),
|
||||
num_read_times = tables[1].select("#add_manga_num_read_times").`val`(),
|
||||
reread_value = tables[1].select("#add_manga_reread_value > option[selected]").`val`(),
|
||||
comments = tables[1].select("#add_manga_comments").`val`(),
|
||||
is_asked_to_discuss = tables[1].select("#add_manga_is_asked_to_discuss > option[selected]").`val`(),
|
||||
sns_post_type = tables[1].select("#add_manga_sns_post_type > option[selected]").`val`()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -259,98 +261,99 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
||||
private fun mangaUrl(remoteId: Int) = baseMangaUrl + remoteId
|
||||
|
||||
private fun loginUrl() = Uri.parse(baseUrl).buildUpon()
|
||||
.appendPath("login.php")
|
||||
.toString()
|
||||
.appendPath("login.php")
|
||||
.toString()
|
||||
|
||||
private fun searchUrl(query: String): String {
|
||||
val col = "c[]"
|
||||
return Uri.parse(baseUrl).buildUpon()
|
||||
.appendPath("manga.php")
|
||||
.appendQueryParameter("q", query)
|
||||
.appendQueryParameter(col, "a")
|
||||
.appendQueryParameter(col, "b")
|
||||
.appendQueryParameter(col, "c")
|
||||
.appendQueryParameter(col, "d")
|
||||
.appendQueryParameter(col, "e")
|
||||
.appendQueryParameter(col, "g")
|
||||
.toString()
|
||||
.appendPath("manga.php")
|
||||
.appendQueryParameter("q", query)
|
||||
.appendQueryParameter(col, "a")
|
||||
.appendQueryParameter(col, "b")
|
||||
.appendQueryParameter(col, "c")
|
||||
.appendQueryParameter(col, "d")
|
||||
.appendQueryParameter(col, "e")
|
||||
.appendQueryParameter(col, "g")
|
||||
.toString()
|
||||
}
|
||||
|
||||
private fun exportListUrl() = Uri.parse(baseUrl).buildUpon()
|
||||
.appendPath("panel.php")
|
||||
.appendQueryParameter("go", "export")
|
||||
.toString()
|
||||
.appendPath("panel.php")
|
||||
.appendQueryParameter("go", "export")
|
||||
.toString()
|
||||
|
||||
private fun editPageUrl(mediaId: Int) = Uri.parse(baseModifyListUrl).buildUpon()
|
||||
.appendPath(mediaId.toString())
|
||||
.appendPath("edit")
|
||||
.toString()
|
||||
.appendPath(mediaId.toString())
|
||||
.appendPath("edit")
|
||||
.toString()
|
||||
|
||||
private fun addUrl() = Uri.parse(baseModifyListUrl).buildUpon()
|
||||
.appendPath("add.json")
|
||||
.toString()
|
||||
.appendPath("add.json")
|
||||
.toString()
|
||||
|
||||
private fun loginPostBody(username: String, password: String, csrf: String): RequestBody {
|
||||
return FormBody.Builder()
|
||||
.add("user_name", username)
|
||||
.add("password", password)
|
||||
.add("cookie", "1")
|
||||
.add("sublogin", "Login")
|
||||
.add("submit", "1")
|
||||
.add(CSRF, csrf)
|
||||
.build()
|
||||
.add("user_name", username)
|
||||
.add("password", password)
|
||||
.add("cookie", "1")
|
||||
.add("sublogin", "Login")
|
||||
.add("submit", "1")
|
||||
.add(CSRF, csrf)
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun exportPostBody(): RequestBody {
|
||||
return FormBody.Builder()
|
||||
.add("type", "2")
|
||||
.add("subexport", "Export My List")
|
||||
.build()
|
||||
.add("type", "2")
|
||||
.add("subexport", "Export My List")
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun mangaPostPayload(track: Track): RequestBody {
|
||||
val body = JSONObject()
|
||||
.put("manga_id", track.media_id)
|
||||
.put("status", track.status)
|
||||
.put("score", track.score)
|
||||
.put("num_read_chapters", track.last_chapter_read)
|
||||
.put("manga_id", track.media_id)
|
||||
.put("status", track.status)
|
||||
.put("score", track.score)
|
||||
.put("num_read_chapters", track.last_chapter_read)
|
||||
|
||||
return body.toString().toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
|
||||
}
|
||||
|
||||
private fun mangaEditPostBody(track: MyAnimeListEditData): RequestBody {
|
||||
return FormBody.Builder()
|
||||
.add("entry_id", track.entry_id)
|
||||
.add("manga_id", track.manga_id)
|
||||
.add("add_manga[status]", track.status)
|
||||
.add("add_manga[num_read_volumes]", track.num_read_volumes)
|
||||
.add("last_completed_vol", track.last_completed_vol)
|
||||
.add("add_manga[num_read_chapters]", track.num_read_chapters)
|
||||
.add("add_manga[score]", track.score)
|
||||
.add("add_manga[start_date][month]", track.start_date_month)
|
||||
.add("add_manga[start_date][day]", track.start_date_day)
|
||||
.add("add_manga[start_date][year]", track.start_date_year)
|
||||
.add("add_manga[finish_date][month]", track.finish_date_month)
|
||||
.add("add_manga[finish_date][day]", track.finish_date_day)
|
||||
.add("add_manga[finish_date][year]", track.finish_date_year)
|
||||
.add("add_manga[tags]", track.tags)
|
||||
.add("add_manga[priority]", track.priority)
|
||||
.add("add_manga[storage_type]", track.storage_type)
|
||||
.add("add_manga[num_retail_volumes]", track.num_retail_volumes)
|
||||
.add("add_manga[num_read_times]", track.num_read_chapters)
|
||||
.add("add_manga[reread_value]", track.reread_value)
|
||||
.add("add_manga[comments]", track.comments)
|
||||
.add("add_manga[is_asked_to_discuss]", track.is_asked_to_discuss)
|
||||
.add("add_manga[sns_post_type]", track.sns_post_type)
|
||||
.add("submitIt", track.submitIt)
|
||||
.build()
|
||||
.add("entry_id", track.entry_id)
|
||||
.add("manga_id", track.manga_id)
|
||||
.add("add_manga[status]", track.status)
|
||||
.add("add_manga[num_read_volumes]", track.num_read_volumes)
|
||||
.add("last_completed_vol", track.last_completed_vol)
|
||||
.add("add_manga[num_read_chapters]", track.num_read_chapters)
|
||||
.add("add_manga[score]", track.score)
|
||||
.add("add_manga[start_date][month]", track.start_date_month)
|
||||
.add("add_manga[start_date][day]", track.start_date_day)
|
||||
.add("add_manga[start_date][year]", track.start_date_year)
|
||||
.add("add_manga[finish_date][month]", track.finish_date_month)
|
||||
.add("add_manga[finish_date][day]", track.finish_date_day)
|
||||
.add("add_manga[finish_date][year]", track.finish_date_year)
|
||||
.add("add_manga[tags]", track.tags)
|
||||
.add("add_manga[priority]", track.priority)
|
||||
.add("add_manga[storage_type]", track.storage_type)
|
||||
.add("add_manga[num_retail_volumes]", track.num_retail_volumes)
|
||||
.add("add_manga[num_read_times]", track.num_read_chapters)
|
||||
.add("add_manga[reread_value]", track.reread_value)
|
||||
.add("add_manga[comments]", track.comments)
|
||||
.add("add_manga[is_asked_to_discuss]", track.is_asked_to_discuss)
|
||||
.add("add_manga[sns_post_type]", track.sns_post_type)
|
||||
.add("submitIt", track.submitIt)
|
||||
.build()
|
||||
}
|
||||
|
||||
private fun Element.searchDateXml(field: String): Long {
|
||||
val text = selectText(field, "0000-00-00")!!
|
||||
// MAL sets the data to 0000-00-00 when date is invalid or missing
|
||||
if (text == "0000-00-00")
|
||||
if (text == "0000-00-00") {
|
||||
return 0L
|
||||
}
|
||||
|
||||
return SimpleDateFormat("yyyy-MM-dd", Locale.US).parse(text)?.time ?: 0L
|
||||
}
|
||||
@@ -359,8 +362,9 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
||||
val month = select(id + "_month > option[selected]").`val`().toIntOrNull()
|
||||
val day = select(id + "_day > option[selected]").`val`().toIntOrNull()
|
||||
val year = select(id + "_year > option[selected]").`val`().toIntOrNull()
|
||||
if (year == null || month == null || day == null)
|
||||
if (year == null || month == null || day == null) {
|
||||
return 0L
|
||||
}
|
||||
|
||||
return GregorianCalendar(year, month - 1, day).timeInMillis
|
||||
}
|
||||
@@ -370,18 +374,18 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
||||
private fun Element.searchTotalChapters() = if (select(TD)[4].text() == "-") 0 else select(TD)[4].text().toInt()
|
||||
|
||||
private fun Element.searchCoverUrl() = select("img")
|
||||
.attr("data-src")
|
||||
.split("\\?")[0]
|
||||
.replace("/r/50x70/", "/")
|
||||
.attr("data-src")
|
||||
.split("\\?")[0]
|
||||
.replace("/r/50x70/", "/")
|
||||
|
||||
private fun Element.searchMediaId() = select("div.picSurround")
|
||||
.select("a").attr("id")
|
||||
.replace("sarea", "")
|
||||
.toInt()
|
||||
.select("a").attr("id")
|
||||
.replace("sarea", "")
|
||||
.toInt()
|
||||
|
||||
private fun Element.searchSummary() = select("div.pt4")
|
||||
.first()
|
||||
.ownText()!!
|
||||
.first()
|
||||
.ownText()!!
|
||||
|
||||
private fun Element.searchPublishingStatus() = if (select(TD).last().text() == "-") "Publishing" else "Finished"
|
||||
|
||||
@@ -472,8 +476,9 @@ class MyAnimeListApi(private val client: OkHttpClient, interceptor: MyAnimeListI
|
||||
fun copyPersonalFrom(track: Track) {
|
||||
num_read_chapters = track.last_chapter_read.toString()
|
||||
val numScore = track.score.toInt()
|
||||
if (numScore in 1..9)
|
||||
if (numScore in 1..9) {
|
||||
score = numScore.toString()
|
||||
}
|
||||
status = track.status.toString()
|
||||
if (track.started_reading_date == 0L) {
|
||||
start_date_month = ""
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ class MyAnimeListInterceptor(private val myanimelist: MyAnimeList) : Interceptor
|
||||
private fun updateJsonBody(requestBody: RequestBody): RequestBody {
|
||||
val jsonString = bodyToString(requestBody)
|
||||
val newBody = JSONObject(jsonString)
|
||||
.put(MyAnimeListApi.CSRF, myanimelist.getCSRF())
|
||||
.put(MyAnimeListApi.CSRF, myanimelist.getCSRF())
|
||||
|
||||
return newBody.toString().toRequestBody(requestBody.contentType())
|
||||
}
|
||||
|
||||
@@ -51,18 +51,18 @@ class Shikimori(private val context: Context, id: Int) : TrackService(id) {
|
||||
|
||||
override fun bind(track: Track): Observable<Track> {
|
||||
return api.findLibManga(track, getUsername())
|
||||
.flatMap { remoteTrack ->
|
||||
if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.library_id = remoteTrack.library_id
|
||||
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)
|
||||
}
|
||||
.flatMap { remoteTrack ->
|
||||
if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.library_id = remoteTrack.library_id
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun search(query: String): Observable<List<TrackSearch>> {
|
||||
@@ -71,13 +71,13 @@ class Shikimori(private val context: Context, id: Int) : TrackService(id) {
|
||||
|
||||
override fun refresh(track: Track): Observable<Track> {
|
||||
return api.findLibManga(track, getUsername())
|
||||
.map { remoteTrack ->
|
||||
if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.total_chapters = remoteTrack.total_chapters
|
||||
}
|
||||
track
|
||||
.map { remoteTrack ->
|
||||
if (remoteTrack != null) {
|
||||
track.copyPersonalFrom(remoteTrack)
|
||||
track.total_chapters = remoteTrack.total_chapters
|
||||
}
|
||||
track
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLogo() = R.drawable.ic_tracker_shikimori
|
||||
|
||||
@@ -30,49 +30,49 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
||||
|
||||
fun addLibManga(track: Track, user_id: String): Observable<Track> {
|
||||
val payload = jsonObject(
|
||||
"user_rate" to jsonObject(
|
||||
"user_id" to user_id,
|
||||
"target_id" to track.media_id,
|
||||
"target_type" to "Manga",
|
||||
"chapters" to track.last_chapter_read,
|
||||
"score" to track.score.toInt(),
|
||||
"status" to track.toShikimoriStatus()
|
||||
)
|
||||
"user_rate" to jsonObject(
|
||||
"user_id" to user_id,
|
||||
"target_id" to track.media_id,
|
||||
"target_type" to "Manga",
|
||||
"chapters" to track.last_chapter_read,
|
||||
"score" to track.score.toInt(),
|
||||
"status" to track.toShikimoriStatus()
|
||||
)
|
||||
)
|
||||
val body = payload.toString().toRequestBody(jsonime)
|
||||
val request = Request.Builder()
|
||||
.url("$apiUrl/v2/user_rates")
|
||||
.post(body)
|
||||
.build()
|
||||
.url("$apiUrl/v2/user_rates")
|
||||
.post(body)
|
||||
.build()
|
||||
return authClient.newCall(request)
|
||||
.asObservableSuccess()
|
||||
.map {
|
||||
track
|
||||
}
|
||||
.asObservableSuccess()
|
||||
.map {
|
||||
track
|
||||
}
|
||||
}
|
||||
|
||||
fun updateLibManga(track: Track, user_id: String): Observable<Track> = addLibManga(track, user_id)
|
||||
|
||||
fun search(search: String): Observable<List<TrackSearch>> {
|
||||
val url = Uri.parse("$apiUrl/mangas").buildUpon()
|
||||
.appendQueryParameter("order", "popularity")
|
||||
.appendQueryParameter("search", search)
|
||||
.appendQueryParameter("limit", "20")
|
||||
.build()
|
||||
.appendQueryParameter("order", "popularity")
|
||||
.appendQueryParameter("search", search)
|
||||
.appendQueryParameter("limit", "20")
|
||||
.build()
|
||||
val request = Request.Builder()
|
||||
.url(url.toString())
|
||||
.get()
|
||||
.build()
|
||||
.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 = JsonParser.parseString(responseBody).array
|
||||
response.map { jsonToSearch(it.obj) }
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
if (responseBody.isEmpty()) {
|
||||
throw Exception("Null Response")
|
||||
}
|
||||
val response = JsonParser.parseString(responseBody).array
|
||||
response.map { jsonToSearch(it.obj) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun jsonToSearch(obj: JsonObject): TrackSearch {
|
||||
@@ -103,45 +103,45 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
||||
|
||||
fun findLibManga(track: Track, user_id: String): Observable<Track?> {
|
||||
val url = Uri.parse("$apiUrl/v2/user_rates").buildUpon()
|
||||
.appendQueryParameter("user_id", user_id)
|
||||
.appendQueryParameter("target_id", track.media_id.toString())
|
||||
.appendQueryParameter("target_type", "Manga")
|
||||
.build()
|
||||
.appendQueryParameter("user_id", user_id)
|
||||
.appendQueryParameter("target_id", track.media_id.toString())
|
||||
.appendQueryParameter("target_type", "Manga")
|
||||
.build()
|
||||
val request = Request.Builder()
|
||||
.url(url.toString())
|
||||
.get()
|
||||
.build()
|
||||
.url(url.toString())
|
||||
.get()
|
||||
.build()
|
||||
|
||||
val urlMangas = Uri.parse("$apiUrl/mangas").buildUpon()
|
||||
.appendPath(track.media_id.toString())
|
||||
.build()
|
||||
.appendPath(track.media_id.toString())
|
||||
.build()
|
||||
val requestMangas = Request.Builder()
|
||||
.url(urlMangas.toString())
|
||||
.get()
|
||||
.build()
|
||||
.url(urlMangas.toString())
|
||||
.get()
|
||||
.build()
|
||||
return authClient.newCall(requestMangas)
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
JsonParser.parseString(responseBody).obj
|
||||
}.flatMap { mangas ->
|
||||
authClient.newCall(request)
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
if (responseBody.isEmpty()) {
|
||||
throw Exception("Null Response")
|
||||
}
|
||||
val response = JsonParser.parseString(responseBody).array
|
||||
if (response.size() > 1) {
|
||||
throw Exception("Too much mangas in response")
|
||||
}
|
||||
val entry = response.map {
|
||||
jsonToTrack(it.obj, mangas)
|
||||
}
|
||||
entry.firstOrNull()
|
||||
}
|
||||
}
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
JsonParser.parseString(responseBody).obj
|
||||
}.flatMap { mangas ->
|
||||
authClient.newCall(request)
|
||||
.asObservableSuccess()
|
||||
.map { netResponse ->
|
||||
val responseBody = netResponse.body?.string().orEmpty()
|
||||
if (responseBody.isEmpty()) {
|
||||
throw Exception("Null Response")
|
||||
}
|
||||
val response = JsonParser.parseString(responseBody).array
|
||||
if (response.size() > 1) {
|
||||
throw Exception("Too much mangas in response")
|
||||
}
|
||||
val entry = response.map {
|
||||
jsonToTrack(it.obj, mangas)
|
||||
}
|
||||
entry.firstOrNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun getCurrentUser(): Int {
|
||||
@@ -159,14 +159,15 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
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 {
|
||||
@@ -186,18 +187,20 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
|
||||
}
|
||||
|
||||
fun authUrl() =
|
||||
Uri.parse(loginUrl).buildUpon()
|
||||
.appendQueryParameter("client_id", clientId)
|
||||
.appendQueryParameter("redirect_uri", redirectUrl)
|
||||
.appendQueryParameter("response_type", "code")
|
||||
.build()
|
||||
Uri.parse(loginUrl).buildUpon()
|
||||
.appendQueryParameter("client_id", clientId)
|
||||
.appendQueryParameter("redirect_uri", redirectUrl)
|
||||
.appendQueryParameter("response_type", "code")
|
||||
.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)
|
||||
.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)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ class ShikimoriInterceptor(val shikimori: Shikimori, val gson: Gson) : Intercept
|
||||
}
|
||||
// Add the authorization header to the original request.
|
||||
val authRequest = originalRequest.newBuilder()
|
||||
.addHeader("Authorization", "Bearer ${oauth!!.access_token}")
|
||||
.header("User-Agent", "Tachiyomi")
|
||||
.build()
|
||||
.addHeader("Authorization", "Bearer ${oauth!!.access_token}")
|
||||
.header("User-Agent", "Tachiyomi")
|
||||
.build()
|
||||
|
||||
return chain.proceed(authRequest)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user