Mangadex support manga rating
This commit is contained in:
parent
77f5acf2dd
commit
d7856fe351
@ -26,6 +26,7 @@ import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.util.lang.runAsObservable
|
||||
import exh.md.MangaDexFabHeaderAdapter
|
||||
import exh.md.dto.MangaDto
|
||||
import exh.md.dto.StatisticsMangaDto
|
||||
import exh.md.handlers.ApiMangaParser
|
||||
import exh.md.handlers.BilibiliHandler
|
||||
import exh.md.handlers.ComikeyHandler
|
||||
@ -58,7 +59,7 @@ import kotlin.reflect.KClass
|
||||
@Suppress("OverridingDeprecatedMember")
|
||||
class MangaDex(delegate: HttpSource, val context: Context) :
|
||||
DelegatedHttpSource(delegate),
|
||||
MetadataSource<MangaDexSearchMetadata, Pair<MangaDto, List<String>>>,
|
||||
MetadataSource<MangaDexSearchMetadata, Triple<MangaDto, List<String>, StatisticsMangaDto>>,
|
||||
UrlImportableSource,
|
||||
FollowsSource,
|
||||
LoginSource,
|
||||
@ -206,8 +207,8 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
||||
return MangaDexDescriptionAdapter(controller)
|
||||
}
|
||||
|
||||
override suspend fun parseIntoMetadata(metadata: MangaDexSearchMetadata, input: Pair<MangaDto, List<String>>) {
|
||||
apiMangaParser.parseIntoMetadata(metadata, input.first, input.second)
|
||||
override suspend fun parseIntoMetadata(metadata: MangaDexSearchMetadata, input: Triple<MangaDto, List<String>, StatisticsMangaDto>) {
|
||||
apiMangaParser.parseIntoMetadata(metadata, input.first, input.second, input.third)
|
||||
}
|
||||
|
||||
// LoginSource methods
|
||||
@ -265,11 +266,11 @@ class MangaDex(delegate: HttpSource, val context: Context) :
|
||||
// Tracker methods
|
||||
/*suspend fun updateReadingProgress(track: Track): Boolean {
|
||||
return followsHandler.updateReadingProgress(track)
|
||||
}
|
||||
}*/
|
||||
|
||||
suspend fun updateRating(track: Track): Boolean {
|
||||
return followsHandler.updateRating(track)
|
||||
}*/
|
||||
}
|
||||
|
||||
suspend fun getTrackingAndMangaInfo(track: Track): Pair<Track, MangaDexSearchMetadata?> {
|
||||
return mangaHandler.getTrackingInfo(track)
|
||||
|
18
app/src/main/java/exh/md/dto/StatisticsDto.kt
Normal file
18
app/src/main/java/exh/md/dto/StatisticsDto.kt
Normal file
@ -0,0 +1,18 @@
|
||||
package exh.md.dto
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class StatisticsDto(
|
||||
val statistics: Map<String, StatisticsMangaDto>
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StatisticsMangaDto(
|
||||
val rating: StatisticsMangaRatingDto
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class StatisticsMangaRatingDto(
|
||||
val average: Double?
|
||||
)
|
@ -6,6 +6,7 @@ import exh.log.xLogE
|
||||
import exh.md.dto.ChapterDataDto
|
||||
import exh.md.dto.ChapterDto
|
||||
import exh.md.dto.MangaDto
|
||||
import exh.md.dto.StatisticsMangaDto
|
||||
import exh.md.utils.MdConstants
|
||||
import exh.md.utils.MdUtil
|
||||
import exh.md.utils.asMdMap
|
||||
@ -36,14 +37,20 @@ class ApiMangaParser(
|
||||
}?.call()
|
||||
?: error("Could not find no-args constructor for meta class: ${metaClass.qualifiedName}!")
|
||||
|
||||
fun parseToManga(manga: MangaInfo, input: MangaDto, simpleChapters: List<String>, sourceId: Long): MangaInfo {
|
||||
fun parseToManga(
|
||||
manga: MangaInfo,
|
||||
sourceId: Long,
|
||||
input: MangaDto,
|
||||
simpleChapters: List<String>,
|
||||
statistics: StatisticsMangaDto?
|
||||
): MangaInfo {
|
||||
val mangaId = db.getManga(manga.key, sourceId).executeAsBlocking()?.id
|
||||
val metadata = if (mangaId != null) {
|
||||
val flatMetadata = db.getFlatMetadataForManga(mangaId).executeAsBlocking()
|
||||
flatMetadata?.raise(metaClass) ?: newMetaInstance()
|
||||
} else newMetaInstance()
|
||||
|
||||
parseIntoMetadata(metadata, input, simpleChapters)
|
||||
parseIntoMetadata(metadata, input, simpleChapters, statistics)
|
||||
if (mangaId != null) {
|
||||
metadata.mangaId = mangaId
|
||||
db.insertFlatMetadata(metadata.flatten())
|
||||
@ -52,7 +59,12 @@ class ApiMangaParser(
|
||||
return metadata.createMangaInfo(manga)
|
||||
}
|
||||
|
||||
fun parseIntoMetadata(metadata: MangaDexSearchMetadata, mangaDto: MangaDto, simpleChapters: List<String>) {
|
||||
fun parseIntoMetadata(
|
||||
metadata: MangaDexSearchMetadata,
|
||||
mangaDto: MangaDto,
|
||||
simpleChapters: List<String>,
|
||||
statistics: StatisticsMangaDto?
|
||||
) {
|
||||
with(metadata) {
|
||||
try {
|
||||
val mangaAttributesDto = mangaDto.data.attributes
|
||||
@ -83,12 +95,12 @@ class ApiMangaParser(
|
||||
val lastChapter = mangaAttributesDto.lastChapter?.toFloatOrNull()
|
||||
lastChapterNumber = lastChapter?.floor()
|
||||
|
||||
/*networkManga.rating?.let {
|
||||
manga.rating = it.bayesian ?: it.mean
|
||||
manga.users = it.users
|
||||
}*/
|
||||
statistics?.rating?.let {
|
||||
rating = it.average?.toFloat()
|
||||
// manga.users = it.users
|
||||
}
|
||||
|
||||
mangaAttributesDto.links?.asMdMap()?.let { links ->
|
||||
mangaAttributesDto.links?.asMdMap<String>()?.let { links ->
|
||||
links["al"]?.let { anilistId = it }
|
||||
links["kt"]?.let { kitsuId = it }
|
||||
links["mal"]?.let { myAnimeListId = it }
|
||||
|
@ -15,7 +15,9 @@ import exh.md.utils.MdUtil
|
||||
import exh.md.utils.mdListCall
|
||||
import exh.metadata.metadata.MangaDexSearchMetadata
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import rx.Observable
|
||||
import tachiyomi.source.model.ChapterInfo
|
||||
import tachiyomi.source.model.MangaInfo
|
||||
@ -27,9 +29,19 @@ class MangaHandler(
|
||||
private val followsHandler: FollowsHandler
|
||||
) {
|
||||
suspend fun getMangaDetails(manga: MangaInfo, sourceId: Long): MangaInfo {
|
||||
val response = withIOContext { service.viewManga(MdUtil.getMangaId(manga.key)) }
|
||||
val simpleChapters = withIOContext { getSimpleChapters(manga) }
|
||||
return apiMangaParser.parseToManga(manga, response, simpleChapters, sourceId)
|
||||
return coroutineScope {
|
||||
val mangaId = MdUtil.getMangaId(manga.key)
|
||||
val response = async(Dispatchers.IO) { service.viewManga(mangaId) }
|
||||
val simpleChapters = async(Dispatchers.IO) { getSimpleChapters(manga) }
|
||||
val statistics = async(Dispatchers.IO) { service.mangasRating(mangaId).statistics[mangaId] }
|
||||
apiMangaParser.parseToManga(
|
||||
manga,
|
||||
sourceId,
|
||||
response.await(),
|
||||
simpleChapters.await(),
|
||||
statistics.await()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun fetchMangaDetailsObservable(manga: SManga, sourceId: Long): Observable<SManga> {
|
||||
|
@ -13,6 +13,7 @@ import exh.md.dto.MangaDto
|
||||
import exh.md.dto.MangaListDto
|
||||
import exh.md.dto.RelationListDto
|
||||
import exh.md.dto.ResultDto
|
||||
import exh.md.dto.StatisticsDto
|
||||
import exh.md.utils.MdApi
|
||||
import exh.md.utils.MdConstants
|
||||
import exh.md.utils.MdUtil
|
||||
@ -66,6 +67,25 @@ class MangaDexService(
|
||||
).await().parseAs(MdUtil.jsonParser)
|
||||
}
|
||||
|
||||
suspend fun mangasRating(
|
||||
vararg ids: String
|
||||
): StatisticsDto {
|
||||
return client.newCall(
|
||||
GET(
|
||||
MdApi.statistics.toHttpUrl()
|
||||
.newBuilder()
|
||||
.apply {
|
||||
ids.forEach { id ->
|
||||
addQueryParameter("manga[]", id)
|
||||
}
|
||||
}
|
||||
.build()
|
||||
.toString(),
|
||||
cache = CacheControl.FORCE_NETWORK
|
||||
)
|
||||
).await().parseAs(MdUtil.jsonParser)
|
||||
}
|
||||
|
||||
suspend fun aggregateChapters(
|
||||
id: String,
|
||||
translatedLanguage: String
|
||||
|
@ -10,6 +10,7 @@ object MdApi {
|
||||
const val chapter = "$baseUrl/chapter"
|
||||
const val group = "$baseUrl/group"
|
||||
const val author = "$baseUrl/author"
|
||||
const val statistics = "$baseUrl/statistics/manga"
|
||||
const val chapterImageServer = "$baseUrl/at-home/server"
|
||||
const val userFollows = "$baseUrl/user/follows/manga"
|
||||
const val readingStatusForAllManga = "$baseUrl/manga/status"
|
||||
|
@ -3,9 +3,8 @@ package exh.md.utils
|
||||
import exh.md.dto.ListCallDto
|
||||
import exh.util.under
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.contentOrNull
|
||||
import kotlinx.serialization.json.decodeFromJsonElement
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
|
||||
suspend fun <T> mdListCall(request: suspend (offset: Int) -> ListCallDto<T>): List<T> {
|
||||
val results = mutableListOf<T>()
|
||||
@ -20,8 +19,8 @@ suspend fun <T> mdListCall(request: suspend (offset: Int) -> ListCallDto<T>): Li
|
||||
return results
|
||||
}
|
||||
|
||||
fun JsonElement.asMdMap(): Map<String, String> {
|
||||
fun <T> JsonElement.asMdMap(): Map<String, T> {
|
||||
return runCatching {
|
||||
jsonObject.map { it.key to it.value.jsonPrimitive.contentOrNull.orEmpty() }.toMap()
|
||||
MdUtil.jsonParser.decodeFromJsonElement<Map<String, T>>(jsonObject)
|
||||
}.getOrElse { emptyMap() }
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ class MangaDexSearchMetadata : RaisedSearchMetadata() {
|
||||
var langFlag: String? = null
|
||||
|
||||
var lastChapterNumber: Int? = null
|
||||
// var rating: String? = null
|
||||
var rating: Float? = null
|
||||
// var users: String? = null
|
||||
|
||||
var anilistId: String? = null
|
||||
|
@ -1,5 +1,6 @@
|
||||
package exh.ui.metadata.adapters
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@ -10,9 +11,11 @@ import eu.kanade.tachiyomi.databinding.DescriptionAdapterMdBinding
|
||||
import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaController
|
||||
import eu.kanade.tachiyomi.util.system.copyToClipboard
|
||||
import exh.metadata.MetadataUtil.getRatingString
|
||||
import exh.metadata.bindDrawable
|
||||
import exh.metadata.metadata.MangaDexSearchMetadata
|
||||
import exh.ui.metadata.MetadataViewController
|
||||
import kotlin.math.round
|
||||
|
||||
class MangaDexDescriptionAdapter(
|
||||
private val controller: MangaController
|
||||
@ -39,12 +42,12 @@ class MangaDexDescriptionAdapter(
|
||||
if (meta == null || meta !is MangaDexSearchMetadata) return
|
||||
|
||||
// todo
|
||||
/*val ratingFloat = meta.rating?.toFloatOrNull()
|
||||
val ratingFloat = meta.rating
|
||||
binding.ratingBar.rating = ratingFloat?.div(2F) ?: 0F
|
||||
@SuppressLint("SetTextI18n")
|
||||
binding.rating.text = (round((meta.rating?.toFloatOrNull() ?: 0F) * 100.0) / 100.0).toString() + " - " + getRatingString(itemView.context, ratingFloat)*/
|
||||
binding.rating.isVisible = false
|
||||
binding.ratingBar.isVisible = false
|
||||
binding.rating.text = (round((ratingFloat ?: 0F) * 100.0) / 100.0).toString() + " - " + getRatingString(itemView.context, ratingFloat)
|
||||
binding.rating.isVisible = ratingFloat != null
|
||||
binding.ratingBar.isVisible = ratingFloat != null
|
||||
|
||||
binding.moreInfo.bindDrawable(itemView.context, R.drawable.ic_info_24dp)
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
@ -11,9 +12,11 @@
|
||||
android:layout_marginStart="8dp"
|
||||
android:textAppearance="?attr/textAppearanceBodyMedium"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/rating_bar"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
|
||||
<me.zhanghai.android.materialratingbar.MaterialRatingBar
|
||||
@ -25,9 +28,11 @@
|
||||
android:focusable="false"
|
||||
android:isIndicator="true"
|
||||
android:numStars="5"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/more_info"
|
||||
|
Loading…
x
Reference in New Issue
Block a user