WIP
This commit is contained in:
@@ -1,239 +0,0 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package xyz.quaver.pupil.sources
|
||||
|
||||
import android.app.Application
|
||||
import android.view.LayoutInflater
|
||||
import android.widget.TextView
|
||||
import io.ktor.http.*
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
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.ItemInfo.ExtraType
|
||||
import xyz.quaver.pupil.util.Preferences
|
||||
import xyz.quaver.pupil.util.wordCapitalize
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class Hitomi(app: Application) : Source() {
|
||||
|
||||
@Parcelize
|
||||
data class TagSuggestion(val s: String, val t: Int, val u: String, val n: String) : SearchSuggestion {
|
||||
constructor(s: Suggestion) : this(s.s, s.t, s.u, s.n)
|
||||
|
||||
@IgnoredOnParcel
|
||||
override val body = s
|
||||
/*
|
||||
TODO
|
||||
if (translations[s] != null)
|
||||
"${translations[s]} ($s)"
|
||||
else
|
||||
s
|
||||
*/
|
||||
}
|
||||
|
||||
override val name: String = "hitomi.la"
|
||||
override val iconResID: Int = R.drawable.hitomi
|
||||
override val preferenceID: Int = R.xml.hitomi_preferences
|
||||
override val availableSortMode: List<String> = app.resources.getStringArray(R.array.hitomi_sort_mode).toList()
|
||||
|
||||
var cachedQuery: String? = null
|
||||
var cachedSortMode: Int = -1
|
||||
val cache = mutableListOf<Int>()
|
||||
|
||||
override suspend fun search(query: String, range: IntRange, sortMode: Int): Pair<Channel<ItemInfo>, Int> {
|
||||
if (cachedQuery != query || cachedSortMode != sortMode || cache.isEmpty()) {
|
||||
cachedQuery = null
|
||||
cache.clear()
|
||||
yield()
|
||||
doSearch("$query ${Preferences["hitomi.default_query", ""]}", sortMode == 1).let {
|
||||
yield()
|
||||
cache.addAll(it)
|
||||
}
|
||||
cachedQuery = query
|
||||
}
|
||||
|
||||
val channel = Channel<ItemInfo>()
|
||||
val sanitizedRange = max(0, range.first) .. min(range.last, cache.size-1)
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
cache.slice(sanitizedRange).map {
|
||||
async {
|
||||
getGalleryBlock(it)
|
||||
}
|
||||
}.forEach {
|
||||
channel.send(transform(name, it.await()))
|
||||
}
|
||||
|
||||
channel.close()
|
||||
}
|
||||
|
||||
return Pair(channel, cache.size)
|
||||
}
|
||||
|
||||
override suspend fun suggestion(query: String) : List<TagSuggestion> {
|
||||
return getSuggestionsForQuery(query.takeLastWhile { !it.isWhitespace() }).map {
|
||||
TagSuggestion(it)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun images(itemID: String): List<String> {
|
||||
val galleryID = itemID.toInt()
|
||||
|
||||
val reader = getGalleryInfo(galleryID)
|
||||
|
||||
return reader.files.map {
|
||||
imageUrlFromImage(galleryID, it, true)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun info(itemID: String): ItemInfo = coroutineScope {
|
||||
kotlin.runCatching {
|
||||
getGallery(itemID.toInt()).let {
|
||||
ItemInfo(
|
||||
name,
|
||||
itemID,
|
||||
it.title,
|
||||
it.cover,
|
||||
it.artists.joinToString { it.wordCapitalize() },
|
||||
mapOf(
|
||||
ExtraType.TYPE to async { it.type.wordCapitalize() },
|
||||
ExtraType.GROUP to async { it.groups.joinToString { it.wordCapitalize() } },
|
||||
ExtraType.LANGUAGE to async { it.language },
|
||||
ExtraType.SERIES to async { it.series.joinToString { it.wordCapitalize() } },
|
||||
ExtraType.CHARACTER to async { it.characters.joinToString { it.wordCapitalize() } },
|
||||
ExtraType.TAGS to async { it.tags.joinToString() },
|
||||
ExtraType.PREVIEW to async { it.thumbnails.joinToString() },
|
||||
ExtraType.RELATED_ITEM to async { it.related.joinToString() },
|
||||
ExtraType.PAGECOUNT to async { it.thumbnails.size.toString() },
|
||||
)
|
||||
)
|
||||
}
|
||||
}.getOrElse {
|
||||
transform(name, getGalleryBlock(itemID.toInt()))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getHeadersBuilderForImage(itemID: String, url: String): HeadersBuilder.() -> Unit = {
|
||||
append("Referer", getReferer(itemID.toInt()))
|
||||
}
|
||||
|
||||
override fun onSuggestionBind(binding: SearchSuggestionItemBinding, item: SearchSuggestion) {
|
||||
item as TagSuggestion
|
||||
|
||||
binding.leftIcon.setImageResource(
|
||||
when(item.n) {
|
||||
"female" -> R.drawable.gender_female
|
||||
"male" -> R.drawable.gender_male
|
||||
"language" -> R.drawable.translate
|
||||
"group" -> R.drawable.account_group
|
||||
"character" -> R.drawable.account_star
|
||||
"series" -> R.drawable.book_open
|
||||
"artist" -> R.drawable.brush
|
||||
else -> R.drawable.tag
|
||||
}
|
||||
)
|
||||
|
||||
if (item.t > 0) {
|
||||
with (binding.root) {
|
||||
val count = findViewById<TextView>(R.id.count)
|
||||
if (count == null)
|
||||
addView(
|
||||
LayoutInflater.from(context).inflate(R.layout.suggestion_count, binding.root, false)
|
||||
.apply {
|
||||
this as TextView
|
||||
|
||||
text = item.t.toString()
|
||||
}, 2
|
||||
)
|
||||
else
|
||||
count.text = item.t.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val languageMap = mapOf(
|
||||
"indonesian" to "Bahasa Indonesia",
|
||||
"catalan" to "català",
|
||||
"cebuano" to "Cebuano",
|
||||
"czech" to "Čeština",
|
||||
"danish" to "Dansk",
|
||||
"german" to "Deutsch",
|
||||
"estonian" to "eesti",
|
||||
"english" to "English",
|
||||
"spanish" to "Español",
|
||||
"esperanto" to "Esperanto",
|
||||
"french" to "Français",
|
||||
"italian" to "Italiano",
|
||||
"latin" to "Latina",
|
||||
"hungarian" to "magyar",
|
||||
"dutch" to "Nederlands",
|
||||
"norwegian" to "norsk",
|
||||
"polish" to "polski",
|
||||
"portuguese" to "Português",
|
||||
"romanian" to "română",
|
||||
"albanian" to "shqip",
|
||||
"slovak" to "Slovenčina",
|
||||
"finnish" to "Suomi",
|
||||
"swedish" to "Svenska",
|
||||
"tagalog" to "Tagalog",
|
||||
"vietnamese" to "tiếng việt",
|
||||
"turkish" to "Türkçe",
|
||||
"greek" to "Ελληνικά",
|
||||
"mongolian" to "Монгол",
|
||||
"russian" to "Русский",
|
||||
"ukrainian" to "Українська",
|
||||
"hebrew" to "עברית",
|
||||
"arabic" to "العربية",
|
||||
"persian" to "فارسی",
|
||||
"thai" to "ไทย",
|
||||
"korean" to "한국어",
|
||||
"chinese" to "中文",
|
||||
"japanese" to "日本語"
|
||||
)
|
||||
|
||||
fun transform(name: String, galleryBlock: GalleryBlock) =
|
||||
ItemInfo(
|
||||
name,
|
||||
galleryBlock.id.toString(),
|
||||
galleryBlock.title,
|
||||
galleryBlock.thumbnails.first(),
|
||||
galleryBlock.artists.joinToString { it.wordCapitalize() },
|
||||
mapOf(
|
||||
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 { galleryBlock.language },
|
||||
ExtraType.PAGECOUNT to CoroutineScope(Dispatchers.IO).async { kotlin.runCatching {
|
||||
getGalleryInfo(galleryBlock.id).files.size.toString()
|
||||
}.getOrNull() },
|
||||
ExtraType.TAGS to CoroutineScope(Dispatchers.Unconfined).async { galleryBlock.relatedTags.joinToString() }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user