Improve tracking search results (#1178)
* initial commit changed tracking info screen added ability to click logo to launch website * added publishing status and type to description. adjusted layout some * added start date to track info * tweaked layout * tweaked layout * tweaked layout * code review changes * code review changes part 2 * code review changes
This commit is contained in:
@@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.track
|
||||
import android.support.annotation.CallSuper
|
||||
import android.support.annotation.DrawableRes
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import okhttp3.OkHttpClient
|
||||
@@ -44,7 +45,7 @@ abstract class TrackService(val id: Int) {
|
||||
|
||||
abstract fun bind(track: Track): Observable<Track>
|
||||
|
||||
abstract fun search(query: String): Observable<List<Track>>
|
||||
abstract fun search(query: String): Observable<List<TrackSearch>>
|
||||
|
||||
abstract fun refresh(track: Track): Observable<Track>
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import rx.Completable
|
||||
import rx.Observable
|
||||
|
||||
@@ -120,7 +121,7 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
|
||||
}
|
||||
}
|
||||
|
||||
override fun search(query: String): Observable<List<Track>> {
|
||||
override fun search(query: String): Observable<List<TrackSearch>> {
|
||||
return api.search(query)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.github.salomonbrys.kotson.int
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.JsonObject
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.OkHttpClient
|
||||
@@ -46,7 +47,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
}
|
||||
}
|
||||
|
||||
fun search(query: String): Observable<List<Track>> {
|
||||
fun search(query: String): Observable<List<TrackSearch>> {
|
||||
return rest.search(query, 1)
|
||||
.map { list ->
|
||||
list.filter { it.type != "Novel" }.map { it.toTrack() }
|
||||
@@ -140,6 +141,11 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
|
||||
private const val clientSecret = "nlGB5OmgE9YWq5dr3gIDbTQV0C"
|
||||
private const val clientUrl = "tachiyomi://anilist-auth"
|
||||
private const val baseUrl = "https://anilist.co/api/"
|
||||
private const val baseMangaUrl = "https://anilist.co/manga/"
|
||||
|
||||
fun mangaUrl(remoteId: Int): String {
|
||||
return baseMangaUrl + remoteId
|
||||
}
|
||||
|
||||
fun authUrl() = Uri.parse("${baseUrl}auth/authorize").buildUpon()
|
||||
.appendQueryParameter("grant_type", "authorization_code")
|
||||
|
||||
@@ -1,21 +1,45 @@
|
||||
package eu.kanade.tachiyomi.data.track.anilist
|
||||
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
data class ALManga(
|
||||
val id: Int,
|
||||
val title_romaji: String,
|
||||
val image_url_lge: String,
|
||||
val description: String,
|
||||
val type: String,
|
||||
val publishing_status: String,
|
||||
val start_date_fuzzy: String,
|
||||
val total_chapters: Int) {
|
||||
|
||||
fun toTrack() = Track.create(TrackManager.ANILIST).apply {
|
||||
fun toTrack() = TrackSearch.create(TrackManager.ANILIST).apply {
|
||||
remote_id = this@ALManga.id
|
||||
title = title_romaji
|
||||
total_chapters = this@ALManga.total_chapters
|
||||
cover_url = image_url_lge
|
||||
summary = description
|
||||
tracking_url = AnilistApi.mangaUrl(remote_id)
|
||||
publishing_status = this@ALManga.publishing_status
|
||||
publishing_type = type
|
||||
if (!start_date_fuzzy.isNullOrBlank()) {
|
||||
start_date = try {
|
||||
val inputDf = SimpleDateFormat("yyyyMMdd", Locale.US)
|
||||
val outputDf = SimpleDateFormat("yyyy-MM-dd", Locale.US)
|
||||
val date = inputDf.parse(BuildConfig.BUILD_TIME)
|
||||
outputDf.format(date)
|
||||
} catch (e: Exception) {
|
||||
start_date_fuzzy.orEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,11 +84,11 @@ fun Track.toAnilistStatus() = when (status) {
|
||||
private val preferences: PreferencesHelper by injectLazy()
|
||||
|
||||
fun Track.toAnilistScore(): String = when (preferences.anilistScoreType().getOrDefault()) {
|
||||
// 10 point
|
||||
// 10 point
|
||||
0 -> (score.toInt() / 10).toString()
|
||||
// 100 point
|
||||
// 100 point
|
||||
1 -> score.toInt().toString()
|
||||
// 5 stars
|
||||
// 5 stars
|
||||
2 -> when {
|
||||
score == 0f -> "0"
|
||||
score < 30 -> "1"
|
||||
@@ -73,14 +97,14 @@ fun Track.toAnilistScore(): String = when (preferences.anilistScoreType().getOrD
|
||||
score < 90 -> "4"
|
||||
else -> "5"
|
||||
}
|
||||
// Smiley
|
||||
// Smiley
|
||||
3 -> when {
|
||||
score == 0f -> "0"
|
||||
score <= 30 -> ":("
|
||||
score <= 60 -> ":|"
|
||||
else -> ":)"
|
||||
}
|
||||
// 10 point decimal
|
||||
// 10 point decimal
|
||||
4 -> (score / 10).toString()
|
||||
else -> throw Exception("Unknown score type")
|
||||
}
|
||||
@@ -6,6 +6,7 @@ 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
|
||||
@@ -96,7 +97,7 @@ class Kitsu(private val context: Context, id: Int) : TrackService(id) {
|
||||
}
|
||||
}
|
||||
|
||||
override fun search(query: String): Observable<List<Track>> {
|
||||
override fun search(query: String): Observable<List<TrackSearch>> {
|
||||
return api.search(query)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.github.salomonbrys.kotson.*
|
||||
import com.google.gson.GsonBuilder
|
||||
import com.google.gson.JsonObject
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.OkHttpClient
|
||||
@@ -27,25 +28,25 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
||||
return Observable.defer {
|
||||
// @formatter:off
|
||||
val data = jsonObject(
|
||||
"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"
|
||||
)
|
||||
"type" to "libraryEntries",
|
||||
"attributes" to jsonObject(
|
||||
"status" to track.toKitsuStatus(),
|
||||
"progress" to track.last_chapter_read
|
||||
),
|
||||
"media" to jsonObject(
|
||||
"data" to jsonObject(
|
||||
"id" to track.remote_id,
|
||||
"type" to "manga"
|
||||
)
|
||||
"relationships" to jsonObject(
|
||||
"user" to jsonObject(
|
||||
"data" to jsonObject(
|
||||
"id" to userId,
|
||||
"type" to "users"
|
||||
)
|
||||
),
|
||||
"media" to jsonObject(
|
||||
"data" to jsonObject(
|
||||
"id" to track.remote_id,
|
||||
"type" to "manga"
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
// @formatter:on
|
||||
|
||||
@@ -61,13 +62,13 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
||||
return Observable.defer {
|
||||
// @formatter:off
|
||||
val data = jsonObject(
|
||||
"type" to "libraryEntries",
|
||||
"id" to track.remote_id,
|
||||
"attributes" to jsonObject(
|
||||
"status" to track.toKitsuStatus(),
|
||||
"progress" to track.last_chapter_read,
|
||||
"ratingTwenty" to track.toKitsuScore()
|
||||
)
|
||||
"type" to "libraryEntries",
|
||||
"id" to track.remote_id,
|
||||
"attributes" to jsonObject(
|
||||
"status" to track.toKitsuStatus(),
|
||||
"progress" to track.last_chapter_read,
|
||||
"ratingTwenty" to track.toKitsuScore()
|
||||
)
|
||||
)
|
||||
// @formatter:on
|
||||
|
||||
@@ -76,7 +77,7 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
||||
}
|
||||
}
|
||||
|
||||
fun search(query: String): Observable<List<Track>> {
|
||||
fun search(query: String): Observable<List<TrackSearch>> {
|
||||
return rest.search(query)
|
||||
.map { json ->
|
||||
val data = json["data"].array
|
||||
@@ -186,6 +187,11 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
||||
private const val clientSecret = "54d7307928f63414defd96399fc31ba847961ceaecef3a5fd93144e960c0e151"
|
||||
private const val baseUrl = "https://kitsu.io/api/edge/"
|
||||
private const val loginUrl = "https://kitsu.io/api/"
|
||||
private const val baseMangaUrl = "https://kitsu.io/manga/"
|
||||
|
||||
fun mangaUrl(remoteId: Int): String {
|
||||
return baseMangaUrl + remoteId
|
||||
}
|
||||
|
||||
|
||||
fun refreshTokenRequest(token: String) = POST("${loginUrl}oauth/token",
|
||||
|
||||
@@ -5,24 +5,35 @@ import com.github.salomonbrys.kotson.*
|
||||
import com.google.gson.JsonObject
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
|
||||
open class KitsuManga(obj: JsonObject) {
|
||||
val id by obj.byInt
|
||||
val canonicalTitle by obj["attributes"].byString
|
||||
val chapterCount = obj["attributes"].obj.get("chapterCount").nullInt
|
||||
val type = obj["attributes"].obj.get("mangaType").nullString
|
||||
val type = obj["attributes"].obj.get("mangaType").nullString.orEmpty()
|
||||
val original by obj["attributes"].obj["posterImage"].byString
|
||||
val synopsis by obj["attributes"].byString
|
||||
val startDate = obj["attributes"].obj.get("startDate").nullString.orEmpty()
|
||||
val status = obj["attributes"].obj.get("status").nullString.orEmpty()
|
||||
|
||||
@CallSuper
|
||||
open fun toTrack() = Track.create(TrackManager.KITSU).apply {
|
||||
open fun toTrack() = TrackSearch.create(TrackManager.KITSU).apply {
|
||||
remote_id = this@KitsuManga.id
|
||||
title = canonicalTitle
|
||||
total_chapters = chapterCount ?: 0
|
||||
cover_url = original
|
||||
summary = synopsis
|
||||
tracking_url = KitsuApi.mangaUrl(remote_id)
|
||||
publishing_status = this@KitsuManga.status
|
||||
publishing_type = type
|
||||
start_date = startDate.orEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
class KitsuLibManga(obj: JsonObject, manga: JsonObject) : KitsuManga(manga) {
|
||||
val remoteId by obj.byInt("id")
|
||||
val status by obj["attributes"].byString
|
||||
//override val status by obj["attributes"].byString
|
||||
val ratingTwenty = obj["attributes"].obj.get("ratingTwenty").nullString
|
||||
val progress by obj["attributes"].byInt
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
package eu.kanade.tachiyomi.data.track.model
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
|
||||
class TrackSearch : Track {
|
||||
|
||||
override var id: Long? = null
|
||||
|
||||
override var manga_id: Long = 0
|
||||
|
||||
override var sync_id: Int = 0
|
||||
|
||||
override var remote_id: Int = 0
|
||||
|
||||
override lateinit var title: String
|
||||
|
||||
override var last_chapter_read: Int = 0
|
||||
|
||||
override var total_chapters: Int = 0
|
||||
|
||||
override var score: Float = 0f
|
||||
|
||||
override var status: Int = 0
|
||||
|
||||
override lateinit var tracking_url: String
|
||||
|
||||
var cover_url: String = ""
|
||||
|
||||
var summary: String = ""
|
||||
|
||||
var publishing_status: String = ""
|
||||
|
||||
var publishing_type: String = ""
|
||||
|
||||
var start_date: String = ""
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (other == null || javaClass != other.javaClass) return false
|
||||
|
||||
other as Track
|
||||
|
||||
if (manga_id != other.manga_id) return false
|
||||
if (sync_id != other.sync_id) return false
|
||||
return remote_id == other.remote_id
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = (manga_id xor manga_id.ushr(32)).toInt()
|
||||
result = 31 * result + sync_id
|
||||
result = 31 * result + remote_id
|
||||
return result
|
||||
}
|
||||
companion object {
|
||||
|
||||
fun create(serviceId: Int): TrackSearch = TrackSearch().apply {
|
||||
sync_id = serviceId
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import android.content.Context
|
||||
import android.graphics.Color
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Track
|
||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||
import eu.kanade.tachiyomi.data.track.TrackService
|
||||
import rx.Completable
|
||||
import rx.Observable
|
||||
@@ -81,7 +82,7 @@ class Myanimelist(private val context: Context, id: Int) : TrackService(id) {
|
||||
}
|
||||
}
|
||||
|
||||
override fun search(query: String): Observable<List<Track>> {
|
||||
override fun search(query: String): Observable<List<TrackSearch>> {
|
||||
return api.search(query, getUsername())
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.net.Uri
|
||||
import android.util.Xml
|
||||
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.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.asObservable
|
||||
@@ -12,6 +13,7 @@ import eu.kanade.tachiyomi.util.selectInt
|
||||
import eu.kanade.tachiyomi.util.selectText
|
||||
import okhttp3.*
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.parser.Parser
|
||||
import org.xmlpull.v1.XmlSerializer
|
||||
import rx.Observable
|
||||
import java.io.StringWriter
|
||||
@@ -36,7 +38,7 @@ class MyanimelistApi(private val client: OkHttpClient, username: String, passwor
|
||||
}
|
||||
}
|
||||
|
||||
fun search(query: String, username: String): Observable<List<Track>> {
|
||||
fun search(query: String, username: String): Observable<List<TrackSearch>> {
|
||||
return if (query.startsWith(PREFIX_MY)) {
|
||||
val realQuery = query.substring(PREFIX_MY.length).toLowerCase().trim()
|
||||
getList(username)
|
||||
@@ -46,34 +48,42 @@ class MyanimelistApi(private val client: OkHttpClient, username: String, passwor
|
||||
} else {
|
||||
client.newCall(GET(getSearchUrl(query), headers))
|
||||
.asObservable()
|
||||
.map { Jsoup.parse(it.body()!!.string()) }
|
||||
.map { Jsoup.parse(Parser.unescapeEntities(it.body()!!.string(), false), "", Parser.xmlParser()) }
|
||||
.flatMap { Observable.from(it.select("entry")) }
|
||||
.filter { it.select("type").text() != "Novel" }
|
||||
.map {
|
||||
Track.create(TrackManager.MYANIMELIST).apply {
|
||||
TrackSearch.create(TrackManager.MYANIMELIST).apply {
|
||||
title = it.selectText("title")!!
|
||||
remote_id = it.selectInt("id")
|
||||
total_chapters = it.selectInt("chapters")
|
||||
summary = it.selectText("synopsis")!!
|
||||
cover_url = it.selectText("image")!!
|
||||
tracking_url = MyanimelistApi.mangaUrl(remote_id)
|
||||
publishing_status = it.selectText("status")!!
|
||||
publishing_type = it.selectText("type")!!
|
||||
start_date = it.selectText("start_date")!!
|
||||
}
|
||||
}
|
||||
.toList()
|
||||
}
|
||||
}
|
||||
|
||||
fun getList(username: String): Observable<List<Track>> {
|
||||
fun getList(username: String): Observable<List<TrackSearch>> {
|
||||
return client
|
||||
.newCall(GET(getListUrl(username), headers))
|
||||
.asObservable()
|
||||
.map { Jsoup.parse(it.body()!!.string()) }
|
||||
.map { Jsoup.parse(Parser.unescapeEntities(it.body()!!.string(), false), "", Parser.xmlParser()) }
|
||||
.flatMap { Observable.from(it.select("manga")) }
|
||||
.map {
|
||||
Track.create(TrackManager.MYANIMELIST).apply {
|
||||
TrackSearch.create(TrackManager.MYANIMELIST).apply {
|
||||
title = it.selectText("series_title")!!
|
||||
remote_id = it.selectInt("series_mangadb_id")
|
||||
last_chapter_read = it.selectInt("my_read_chapters")
|
||||
status = it.selectInt("my_status")
|
||||
score = it.selectInt("my_score").toFloat()
|
||||
total_chapters = it.selectInt("series_chapters")
|
||||
cover_url = it.selectText("series_image")!!
|
||||
tracking_url = MyanimelistApi.mangaUrl(remote_id)
|
||||
}
|
||||
}
|
||||
.toList()
|
||||
@@ -176,6 +186,11 @@ class MyanimelistApi(private val client: OkHttpClient, username: String, passwor
|
||||
|
||||
companion object {
|
||||
const val baseUrl = "https://myanimelist.net"
|
||||
const val baseMangaUrl = baseUrl + "/manga/"
|
||||
|
||||
fun mangaUrl(remoteId: Int): String {
|
||||
return baseMangaUrl + remoteId
|
||||
}
|
||||
|
||||
private val ENTRY_TAG = "entry"
|
||||
private val CHAPTER_TAG = "chapter"
|
||||
|
||||
Reference in New Issue
Block a user