dependency update

This commit is contained in:
tom5079
2025-03-08 15:27:57 -08:00
parent 3ee5e683f4
commit 47d96a6ba9
3 changed files with 93 additions and 72 deletions

View File

@@ -17,7 +17,6 @@ import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import kotlinx.datetime.Clock.System.now
import kotlinx.datetime.Instant
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import java.nio.ByteBuffer
import java.nio.ByteOrder
@@ -41,7 +40,7 @@ const val nozomiURLIndexDir = "nozomiurlindex"
data class Suggestion(
val tag: SearchQuery.Tag,
val count: Int
val count: Int,
)
fun IntBuffer.toSet(): Set<Int> {
@@ -92,7 +91,7 @@ class ImagePathResolver(ggjs: String) {
class ExpirableEntry<T>(
private val expiryDuration: Duration,
private val action: suspend () -> T
private val action: suspend () -> T,
) {
private var value: T? = null
private var expiresAt: Instant = now()
@@ -121,7 +120,8 @@ object HitomiHttpClient {
}
private val tagIndexVersion = ExpirableEntry(1.minutes) { getIndexVersion("tagindex") }
private val galleriesIndexVersion = ExpirableEntry(1.minutes) { getIndexVersion("galleriesindex") }
private val galleriesIndexVersion =
ExpirableEntry(1.minutes) { getIndexVersion("galleriesindex") }
private suspend fun getIndexVersion(name: String): String = withContext(Dispatchers.IO) {
httpClient.get("https://$domain/$name/version?_=${System.currentTimeMillis()}").bodyAsText()
@@ -144,7 +144,7 @@ object HitomiHttpClient {
"galleries" -> "https://$domain/$galleriesIndexDir/galleries.${galleriesIndexVersion.getValue()}.index"
"languages" -> "https://$domain/$galleriesIndexDir/languages.${galleriesIndexVersion.getValue()}.index"
"nozomiurl" -> "https://$domain/$galleriesIndexDir/nozomiurl.${galleriesIndexVersion.getValue()}.index"
else -> "https://$domain/$indexDir/$field.${HitomiHttpClient.tagIndexVersion.getValue()}.index"
else -> "https://$domain/$indexDir/$field.${tagIndexVersion.getValue()}.index"
}
return Node.decodeNode(
@@ -155,7 +155,7 @@ object HitomiHttpClient {
private suspend fun bSearch(
field: String,
key: Node.Key,
node: Node
node: Node,
): Node.Data? {
if (node.keys.isEmpty()) {
return null
@@ -174,7 +174,8 @@ object HitomiHttpClient {
}
private suspend fun getGalleryIDsFromData(offset: Long, length: Int): IntBuffer {
val url = "https://$domain/$galleriesIndexDir/galleries.${galleriesIndexVersion.getValue()}.data"
val url =
"https://$domain/$galleriesIndexDir/galleries.${galleriesIndexVersion.getValue()}.data"
if (length > 100000000 || length <= 0) {
error("length $length is too long")
}
@@ -216,7 +217,7 @@ object HitomiHttpClient {
private suspend fun getGalleryIDsFromNozomi(
area: String?,
tag: String,
language: String
language: String,
): IntBuffer {
val nozomiAddress = if (area == null) {
"https://$domain/$compressedNozomiPrefix/$tag-$language$nozomiExtension"
@@ -233,7 +234,10 @@ object HitomiHttpClient {
return ByteBuffer.wrap(result).asIntBuffer()
}
private suspend fun getGalleryIDsForQuery(query: SearchQuery.Tag, language: String = "all"): IntBuffer = when (query.namespace) {
private suspend fun getGalleryIDsForQuery(
query: SearchQuery.Tag,
language: String = "all",
): IntBuffer = when (query.namespace) {
"female", "male" -> getGalleryIDsFromNozomi("tag", query.toString(), language)
"language" -> getGalleryIDsFromNozomi(null, "index", query.tag)
null -> {
@@ -242,12 +246,17 @@ object HitomiHttpClient {
val node = getNodeAtAddress("galleries", 0)
val data = bSearch("galleries", key, node)
if (data != null) getGalleryIDsFromData(data.offset, data.length) else IntBuffer.allocate(0)
if (data != null) getGalleryIDsFromData(
data.offset,
data.length
) else IntBuffer.allocate(0)
}
else -> getGalleryIDsFromNozomi(query.namespace, query.tag, language)
}
suspend fun getSuggestionsForQuery(query: SearchQuery.Tag): Result<List<Suggestion>> = runCatching {
suspend fun getSuggestionsForQuery(query: SearchQuery.Tag): Result<List<Suggestion>> =
runCatching {
val field = query.namespace ?: "global"
val key = Node.Key(query.tag)
val node = getNodeAtAddress(field, 0)
@@ -289,6 +298,7 @@ object HitomiHttpClient {
result
}
is SearchQuery.And -> coroutineScope {
val queries = query.queries.map { query ->
async {
@@ -306,6 +316,7 @@ object HitomiHttpClient {
result
}
is SearchQuery.Or -> coroutineScope {
val queries = query.queries.map { query ->
async {
@@ -322,11 +333,13 @@ object HitomiHttpClient {
result
}
null -> getGalleryIDsFromNozomi(null, "index", "all").toSet()
}
}
suspend fun getImageURL(galleryFile: GalleryFile, thumbnail: Boolean = false): List<String> = buildList {
suspend fun getImageURL(galleryFile: GalleryFile, thumbnail: Boolean = false): List<String> =
buildList {
val imagePathResolver = imagePathResolver.getValue()
listOf("webp", "avif", "jxl").forEach { type ->
@@ -360,11 +373,12 @@ object HitomiHttpClient {
galleryFile: GalleryFile,
thumbnail: Boolean = false,
acceptImage: (String) -> Boolean = { true },
onDownload: (bytesSentTotal: Long, contentLength: Long) -> Unit = { _, _ -> }
onDownload: (bytesSentTotal: Long, contentLength: Long?) -> Unit = { _, _ -> },
): Result<Pair<ByteReadChannel, String>> {
return runCatching {
withContext(Dispatchers.IO) {
val url = getImageURL(galleryFile, thumbnail).firstOrNull(acceptImage) ?: error("No available image")
val url = getImageURL(galleryFile, thumbnail).firstOrNull(acceptImage)
?: error("No available image")
val channel: ByteReadChannel = httpClient.get(url) { onDownload(onDownload) }.body()
Pair(channel, url)
}

View File

@@ -17,20 +17,24 @@ import java.io.File
sealed class ImageLoadProgress {
data object NotStarted : ImageLoadProgress()
data class Progress(val bytesSent: Long, val contentLength: Long) : ImageLoadProgress()
data class Progress(val bytesSent: Long, val contentLength: Long?) : ImageLoadProgress()
data class Finished(val file: File) : ImageLoadProgress()
data class Error(val exception: Throwable) : ImageLoadProgress()
}
interface ImageCache {
suspend fun load(galleryFile: GalleryFile, forceDownload: Boolean = false): StateFlow<ImageLoadProgress>
suspend fun load(
galleryFile: GalleryFile,
forceDownload: Boolean = false,
): StateFlow<ImageLoadProgress>
suspend fun free(vararg files: GalleryFile)
suspend fun clear()
}
class FileImageCache(
private val cacheDir: File,
private val cacheLimit: Long = 128 * 1024 * 1024 // 128MB
private val cacheLimit: Long = 128 * 1024 * 1024, // 128MB
) : ImageCache {
private val mutex = Mutex()
@@ -74,7 +78,10 @@ class FileImageCache(
}
}
override suspend fun load(galleryFile: GalleryFile, forceDownload: Boolean): StateFlow<ImageLoadProgress> {
override suspend fun load(
galleryFile: GalleryFile,
forceDownload: Boolean,
): StateFlow<ImageLoadProgress> {
val hash = galleryFile.hash
mutex.withLock {

View File

@@ -1,27 +1,27 @@
[versions]
agp = "8.8.1"
android-compileSdk = "34"
agp = "8.8.2"
android-compileSdk = "35"
android-minSdk = "21"
android-targetSdk = "34"
android-targetSdk = "35"
kotlin = "2.0.0"
ksp = "2.0.0-1.0.21"
androidxComposeBom = "2024.06.00"
androidxCore = "1.13.1"
androidxActivity = "1.9.0"
androidxLifecycle = "2.8.3"
androidxNavigation = "2.7.7"
accompanist = "0.34.0"
material3 = "1.2.1"
material-icons = "1.6.8"
firebase = "33.1.1"
crashlytics = "3.0.2"
androidxComposeBom = "2025.02.00"
androidxCore = "1.15.0"
androidxActivity = "1.10.1"
androidxLifecycle = "2.8.7"
androidxNavigation = "2.8.8"
accompanist = "0.37.2"
material3 = "1.3.1"
material-icons = "1.7.8"
firebase = "33.10.0"
crashlytics = "3.0.3"
hilt = "2.51.1"
ktor = "2.3.8"
ktor = "3.1.0"
coil = "2.6.0"
room = "2.6.1"
kotlinx-serialization = "1.3.2"
kotlinx-coroutines = "1.8.0"
kotlinx-serialization = "1.8.0"
kotlinx-coroutines = "1.10.1"
kotlinx-datetime = "0.6.0"
[libraries]