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