WIP
This commit is contained in:
@@ -21,20 +21,27 @@ package xyz.quaver.pupil.sources
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import androidx.core.content.ContextCompat
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import okhttp3.Request
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.encoding.Decoder
|
||||
import kotlinx.serialization.encoding.Encoder
|
||||
import xyz.quaver.floatingsearchview.databinding.SearchSuggestionItemBinding
|
||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||
import xyz.quaver.pupil.R
|
||||
|
||||
data class SearchResult(
|
||||
@Serializable(with = ItemInfo.SearchResultSerializer::class)
|
||||
data class ItemInfo(
|
||||
val source: String,
|
||||
val id: String,
|
||||
val title: String,
|
||||
val thumbnail: String,
|
||||
val artists: String,
|
||||
val extra: Map<ExtraType, suspend () -> String>,
|
||||
val tags: List<String>
|
||||
val tags: List<String>,
|
||||
val extra: Map<ExtraType, Deferred<String?>> = emptyMap()
|
||||
) {
|
||||
enum class ExtraType {
|
||||
GROUP,
|
||||
@@ -45,6 +52,48 @@ data class SearchResult(
|
||||
PAGECOUNT
|
||||
}
|
||||
|
||||
@Serializable
|
||||
@SerialName("SearchResult")
|
||||
data class ItemInfoSurrogate(
|
||||
val source: String,
|
||||
val id: String,
|
||||
val title: String,
|
||||
val thumbnail: String,
|
||||
val artists: String,
|
||||
val tags: List<String>,
|
||||
val extra: Map<ExtraType, String?> = emptyMap()
|
||||
)
|
||||
|
||||
object SearchResultSerializer : KSerializer<ItemInfo> {
|
||||
override val descriptor = ItemInfoSurrogate.serializer().descriptor
|
||||
|
||||
override fun serialize(encoder: Encoder, value: ItemInfo) {
|
||||
val surrogate = ItemInfoSurrogate(
|
||||
value.source,
|
||||
value.id,
|
||||
value.title,
|
||||
value.thumbnail,
|
||||
value.artists,
|
||||
value.tags,
|
||||
value.extra.mapValues { runBlocking { it.value.await() } }
|
||||
)
|
||||
encoder.encodeSerializableValue(ItemInfoSurrogate.serializer(), surrogate)
|
||||
}
|
||||
|
||||
override fun deserialize(decoder: Decoder): ItemInfo {
|
||||
val surrogate = decoder.decodeSerializableValue(ItemInfoSurrogate.serializer())
|
||||
return ItemInfo(
|
||||
surrogate.source,
|
||||
surrogate.id,
|
||||
surrogate.title,
|
||||
surrogate.thumbnail,
|
||||
surrogate.artists,
|
||||
surrogate.tags,
|
||||
surrogate.extra.mapValues { CoroutineScope(Dispatchers.Unconfined).async { it.value } }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val extraTypeMap = mapOf(
|
||||
ExtraType.SERIES to R.string.galleryblock_series,
|
||||
@@ -67,9 +116,14 @@ abstract class Source<Query_SortMode: Enum<Query_SortMode>, Suggestion: SearchSu
|
||||
abstract val iconResID: Int
|
||||
abstract val availableSortMode: Array<Query_SortMode>
|
||||
|
||||
abstract suspend fun search(query: String, range: IntRange, sortMode: Enum<*>) : Pair<Channel<SearchResult>, Int>
|
||||
abstract suspend fun search(query: String, range: IntRange, sortMode: Enum<*>) : Pair<Channel<ItemInfo>, Int>
|
||||
abstract suspend fun suggestion(query: String) : List<Suggestion>
|
||||
abstract suspend fun images(id: String) : List<Request.Builder>
|
||||
abstract suspend fun images(id: String) : List<String>
|
||||
/* abstract suspend */ fun info(id: String)/* : ItemInfo */{}
|
||||
|
||||
open fun getHeadersForImage(id: String, url: String): Map<String, String> {
|
||||
return emptyMap()
|
||||
}
|
||||
|
||||
open fun onSuggestionBind(binding: SearchSuggestionItemBinding, item: Suggestion) {
|
||||
binding.leftIcon.setImageResource(R.drawable.tag)
|
||||
|
||||
@@ -18,18 +18,18 @@
|
||||
|
||||
package xyz.quaver.pupil.sources
|
||||
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.TextView
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import okhttp3.Request
|
||||
import xyz.quaver.floatingsearchview.databinding.SearchSuggestionItemBinding
|
||||
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
|
||||
import xyz.quaver.hitomi.*
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.sources.SearchResult.ExtraType
|
||||
import xyz.quaver.pupil.sources.ItemInfo.ExtraType
|
||||
import xyz.quaver.pupil.util.translations
|
||||
import xyz.quaver.pupil.util.wordCapitalize
|
||||
import kotlin.math.max
|
||||
@@ -63,7 +63,7 @@ class Hitomi : Source<Hitomi.SortMode, Hitomi.TagSuggestion>() {
|
||||
var cachedSortMode: SortMode? = null
|
||||
val cache = mutableListOf<Int>()
|
||||
|
||||
override suspend fun search(query: String, range: IntRange, sortMode: Enum<*>): Pair<Channel<SearchResult>, Int> {
|
||||
override suspend fun search(query: String, range: IntRange, sortMode: Enum<*>): Pair<Channel<ItemInfo>, Int> {
|
||||
if (cachedQuery != query || cachedSortMode != sortMode || cache.isEmpty()) {
|
||||
cachedQuery = null
|
||||
cache.clear()
|
||||
@@ -75,7 +75,7 @@ class Hitomi : Source<Hitomi.SortMode, Hitomi.TagSuggestion>() {
|
||||
cachedQuery = query
|
||||
}
|
||||
|
||||
val channel = Channel<SearchResult>()
|
||||
val channel = Channel<ItemInfo>()
|
||||
val sanitizedRange = max(0, range.first) .. min(range.last, cache.size-1)
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
@@ -84,12 +84,7 @@ class Hitomi : Source<Hitomi.SortMode, Hitomi.TagSuggestion>() {
|
||||
getGalleryBlock(it)
|
||||
}
|
||||
}.forEach {
|
||||
kotlin.runCatching {
|
||||
yield()
|
||||
channel.send(transform(it.await()))
|
||||
}.onFailure {
|
||||
channel.close()
|
||||
}
|
||||
channel.send(transform(name, it.await()))
|
||||
}
|
||||
|
||||
channel.close()
|
||||
@@ -98,19 +93,23 @@ class Hitomi : Source<Hitomi.SortMode, Hitomi.TagSuggestion>() {
|
||||
return Pair(channel, cache.size)
|
||||
}
|
||||
|
||||
override suspend fun images(id: String): List<Request.Builder> {
|
||||
override suspend fun images(id: String): List<String> {
|
||||
val galleryID = id.toInt()
|
||||
|
||||
val reader = getGalleryInfo(galleryID)
|
||||
|
||||
return reader.files.map {
|
||||
Request.Builder()
|
||||
.url(imageUrlFromImage(galleryID, it, true))
|
||||
.header("Referer", getReferer(galleryID))
|
||||
imageUrlFromImage(galleryID, it, true)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun suggestion(query: String) : List<TagSuggestion> {
|
||||
override fun getHeadersForImage(id: String, url: String): Map<String, String> {
|
||||
return mapOf(
|
||||
"Referer" to getReferer(id.toInt())
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun suggestion(query: String) : List<Hitomi.TagSuggestion> {
|
||||
return getSuggestionsForQuery(query.takeLastWhile { !it.isWhitespace() }).map {
|
||||
TagSuggestion(it)
|
||||
}
|
||||
@@ -189,20 +188,25 @@ class Hitomi : Source<Hitomi.SortMode, Hitomi.TagSuggestion>() {
|
||||
"japanese" to "日本語"
|
||||
)
|
||||
|
||||
fun transform(galleryBlock: GalleryBlock): SearchResult =
|
||||
SearchResult(
|
||||
fun transform(name: String, galleryBlock: GalleryBlock) =
|
||||
ItemInfo(
|
||||
name,
|
||||
galleryBlock.id.toString(),
|
||||
galleryBlock.title,
|
||||
galleryBlock.thumbnails.first(),
|
||||
galleryBlock.artists.joinToString { it.wordCapitalize() },
|
||||
galleryBlock.relatedTags,
|
||||
mapOf(
|
||||
ExtraType.GROUP to { getGallery(galleryBlock.id).groups.joinToString { it.wordCapitalize() } },
|
||||
ExtraType.SERIES to { galleryBlock.series.joinToString { it.wordCapitalize() } },
|
||||
ExtraType.TYPE to { galleryBlock.type.wordCapitalize() },
|
||||
ExtraType.LANGUAGE to { languageMap[galleryBlock.language] ?: galleryBlock.language },
|
||||
ExtraType.PAGECOUNT to { getGalleryInfo(galleryBlock.id).files.size.toString() }
|
||||
),
|
||||
galleryBlock.relatedTags
|
||||
ExtraType.GROUP to CoroutineScope(Dispatchers.IO).async { kotlin.runCatching {
|
||||
getGallery(galleryBlock.id).groups.joinToString { it.wordCapitalize() }
|
||||
}.getOrDefault("") },
|
||||
ExtraType.SERIES to CoroutineScope(Dispatchers.Unconfined).async { galleryBlock.series.joinToString { it.wordCapitalize() } },
|
||||
ExtraType.TYPE to CoroutineScope(Dispatchers.Unconfined).async { galleryBlock.type.wordCapitalize() },
|
||||
ExtraType.LANGUAGE to CoroutineScope(Dispatchers.Unconfined).async { languageMap[galleryBlock.language] ?: galleryBlock.language },
|
||||
ExtraType.PAGECOUNT to CoroutineScope(Dispatchers.IO).async { kotlin.runCatching {
|
||||
getGalleryInfo(galleryBlock.id).files.size.toString()
|
||||
}.getOrNull() }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -37,8 +37,8 @@ class Hiyobi : Source<DefaultSortMode, DefaultSearchSuggestion>() {
|
||||
override val iconResID: Int = R.drawable.ic_hiyobi
|
||||
override val availableSortMode: Array<DefaultSortMode> = DefaultSortMode.values()
|
||||
|
||||
override suspend fun search(query: String, range: IntRange, sortMode: Enum<*>): Pair<Channel<SearchResult>, Int> {
|
||||
val channel = Channel<SearchResult>()
|
||||
override suspend fun search(query: String, range: IntRange, sortMode: Enum<*>): Pair<Channel<ItemInfo>, Int> {
|
||||
val channel = Channel<ItemInfo>()
|
||||
|
||||
val (results, total) = if (query.isEmpty())
|
||||
list(range)
|
||||
@@ -47,7 +47,7 @@ class Hiyobi : Source<DefaultSortMode, DefaultSearchSuggestion>() {
|
||||
|
||||
CoroutineScope(Dispatchers.Unconfined).launch {
|
||||
results.forEach {
|
||||
channel.send(transform(it))
|
||||
channel.send(transform(name, it))
|
||||
}
|
||||
|
||||
channel.close()
|
||||
@@ -72,10 +72,9 @@ class Hiyobi : Source<DefaultSortMode, DefaultSearchSuggestion>() {
|
||||
return result.map { DefaultSearchSuggestion(it) }
|
||||
}
|
||||
|
||||
override suspend fun images(id: String): List<Request.Builder> {
|
||||
override suspend fun images(id: String): List<String> {
|
||||
return createImgList(id, getGalleryInfo(id), true).map {
|
||||
Request.Builder()
|
||||
.url(it.path)
|
||||
it.path
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,21 +114,23 @@ class Hiyobi : Source<DefaultSortMode, DefaultSearchSuggestion>() {
|
||||
_allTags = it
|
||||
} else _allTags!!
|
||||
|
||||
fun transform(galleryBlock: GalleryBlock): SearchResult =
|
||||
SearchResult(
|
||||
suspend fun transform(name: String, galleryBlock: GalleryBlock): ItemInfo = withContext(Dispatchers.IO) {
|
||||
ItemInfo(
|
||||
name,
|
||||
galleryBlock.id,
|
||||
galleryBlock.title,
|
||||
"https://cdn.$hiyobi/tn/${galleryBlock.id}.jpg",
|
||||
galleryBlock.artists.joinToString { it.value.wordCapitalize() },
|
||||
galleryBlock.tags.map { it.value },
|
||||
mapOf(
|
||||
SearchResult.ExtraType.CHARACTER to { galleryBlock.characters.joinToString { it.value.wordCapitalize() } },
|
||||
SearchResult.ExtraType.SERIES to { galleryBlock.parodys.joinToString { it.value.wordCapitalize() } },
|
||||
SearchResult.ExtraType.TYPE to { galleryBlock.type.name.replace('_', ' ').wordCapitalize() },
|
||||
SearchResult.ExtraType.PAGECOUNT to { getGalleryInfo(galleryBlock.id).files.size.toString() },
|
||||
SearchResult.ExtraType.GROUP to { galleryBlock.groups.joinToString { it.value.wordCapitalize() } }
|
||||
),
|
||||
galleryBlock.tags.map { it.value }
|
||||
ItemInfo.ExtraType.CHARACTER to async { galleryBlock.characters.joinToString { it.value.wordCapitalize() } },
|
||||
ItemInfo.ExtraType.SERIES to async { galleryBlock.parodys.joinToString { it.value.wordCapitalize() } },
|
||||
ItemInfo.ExtraType.TYPE to async { galleryBlock.type.name.replace('_', ' ').wordCapitalize() },
|
||||
ItemInfo.ExtraType.PAGECOUNT to async { getGalleryInfo(galleryBlock.id).files.size.toString() },
|
||||
ItemInfo.ExtraType.GROUP to async { galleryBlock.groups.joinToString { it.value.wordCapitalize() } }
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user