Rebase source onto dev
This commit is contained in:
@@ -32,9 +32,8 @@ import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.Request
|
||||
import xyz.quaver.Code
|
||||
import xyz.quaver.hitomi.GalleryBlock
|
||||
import xyz.quaver.hitomi.Reader
|
||||
import xyz.quaver.hitomi.GalleryInfo
|
||||
import xyz.quaver.io.FileX
|
||||
import xyz.quaver.io.util.*
|
||||
import xyz.quaver.pupil.client
|
||||
@@ -46,24 +45,24 @@ import java.util.concurrent.ConcurrentHashMap
|
||||
@Serializable
|
||||
data class Metadata(
|
||||
var galleryBlock: GalleryBlock? = null,
|
||||
var reader: Reader? = null,
|
||||
var reader: GalleryInfo? = null,
|
||||
var imageList: MutableList<String?>? = null
|
||||
) {
|
||||
fun copy(): Metadata = Metadata(galleryBlock, reader, imageList?.let { MutableList(it.size) { i -> it[i] } })
|
||||
}
|
||||
|
||||
class Cache private constructor(context: Context, val galleryID: Int) : ContextWrapper(context) {
|
||||
class Cache private constructor(context: Context, val galleryID: String) : ContextWrapper(context) {
|
||||
|
||||
companion object {
|
||||
val instances = ConcurrentHashMap<Int, Cache>()
|
||||
val instances = ConcurrentHashMap<String, Cache>()
|
||||
|
||||
fun getInstance(context: Context, galleryID: Int) =
|
||||
fun getInstance(context: Context, galleryID: String) =
|
||||
instances[galleryID] ?: synchronized(this) {
|
||||
instances[galleryID] ?: Cache(context, galleryID).also { instances.put(galleryID, it) }
|
||||
instances[galleryID] ?: Cache(context, galleryID).also { instances[galleryID] = it }
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun delete(context: Context, galleryID: Int) {
|
||||
fun delete(context: Context, galleryID: String) {
|
||||
File(context.cacheDir, "imageCache/$galleryID").deleteRecursively()
|
||||
instances.remove(galleryID)
|
||||
}
|
||||
@@ -111,8 +110,8 @@ class Cache private constructor(context: Context, val galleryID: Int) : ContextW
|
||||
|
||||
suspend fun getGalleryBlock(): GalleryBlock? {
|
||||
val sources = listOf(
|
||||
{ xyz.quaver.hitomi.getGalleryBlock(galleryID) },
|
||||
{ xyz.quaver.hiyobi.getGalleryBlock(galleryID) }
|
||||
{ xyz.quaver.hitomi.getGalleryBlock(galleryID.toInt()) }
|
||||
// { xyz.quaver.hiyobi.getGalleryBlock(galleryID) }
|
||||
)
|
||||
|
||||
return metadata.galleryBlock
|
||||
@@ -154,22 +153,17 @@ class Cache private constructor(context: Context, val galleryID: Int) : ContextW
|
||||
}.getOrNull()?.uri }
|
||||
} } ?: Uri.EMPTY
|
||||
|
||||
suspend fun getReader(): Reader? {
|
||||
suspend fun getReader(): GalleryInfo? {
|
||||
val mirrors = Preferences.get<String>("mirrors").let { if (it.isEmpty()) emptyList() else it.split('>') }
|
||||
|
||||
val sources = mapOf(
|
||||
Code.HITOMI to { xyz.quaver.hitomi.getReader(galleryID) },
|
||||
Code.HIYOBI to { xyz.quaver.hiyobi.getReader(galleryID) }
|
||||
).let {
|
||||
if (mirrors.isNotEmpty())
|
||||
it.toSortedMap{ o1, o2 -> mirrors.indexOf(o1.name) - mirrors.indexOf(o2.name) }
|
||||
else
|
||||
it
|
||||
}
|
||||
"hitomi" to { xyz.quaver.hitomi.getGalleryInfo(galleryID.toInt()) },
|
||||
//Code.HIYOBI to { xyz.quaver.hiyobi.getReader(galleryID) }
|
||||
)
|
||||
|
||||
return metadata.reader
|
||||
?: withContext(Dispatchers.IO) {
|
||||
var reader: Reader? = null
|
||||
var reader: GalleryInfo? = null
|
||||
|
||||
for (source in sources) {
|
||||
reader = try {
|
||||
@@ -187,7 +181,7 @@ class Cache private constructor(context: Context, val galleryID: Int) : ContextW
|
||||
metadata.reader = it
|
||||
|
||||
if (metadata.imageList == null)
|
||||
metadata.imageList = MutableList(reader.galleryInfo.files.size) { null }
|
||||
metadata.imageList = MutableList(reader.files.size) { null }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -206,7 +200,7 @@ class Cache private constructor(context: Context, val galleryID: Int) : ContextW
|
||||
setMetadata { metadata -> metadata.imageList!![index] = fileName }
|
||||
}
|
||||
|
||||
private val lock = ConcurrentHashMap<Int, Mutex>()
|
||||
private val lock = ConcurrentHashMap<String, Mutex>()
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
fun moveToDownload() = CoroutineScope(Dispatchers.IO).launch {
|
||||
val downloadFolder = downloadFolder ?: return@launch
|
||||
|
||||
@@ -57,8 +57,8 @@ class DownloadManager private constructor(context: Context) : ContextWrapper(con
|
||||
}.invoke()
|
||||
|
||||
private var prevDownloadFolder: FileX? = null
|
||||
private var downloadFolderMapInstance: MutableMap<Int, String>? = null
|
||||
val downloadFolderMap: MutableMap<Int, String>
|
||||
private var downloadFolderMapInstance: MutableMap<String, String>? = null
|
||||
val downloadFolderMap: MutableMap<String, String>
|
||||
@Synchronized
|
||||
get() {
|
||||
if (prevDownloadFolder != downloadFolder) {
|
||||
@@ -68,14 +68,14 @@ class DownloadManager private constructor(context: Context) : ContextWrapper(con
|
||||
|
||||
val data = if (file.exists())
|
||||
kotlin.runCatching {
|
||||
file.readText()?.let { Json.decodeFromString<MutableMap<Int, String>>(it) }
|
||||
file.readText()?.let { Json.decodeFromString<MutableMap<String, String>>(it) }
|
||||
}.onFailure { file.delete() }.getOrNull()
|
||||
else
|
||||
null
|
||||
|
||||
data ?: {
|
||||
file.createNewFile()
|
||||
mutableMapOf<Int, String>()
|
||||
mutableMapOf<String, String>()
|
||||
}.invoke()
|
||||
}.invoke()
|
||||
}
|
||||
@@ -85,7 +85,7 @@ class DownloadManager private constructor(context: Context) : ContextWrapper(con
|
||||
|
||||
|
||||
@Synchronized
|
||||
fun isDownloading(galleryID: Int): Boolean {
|
||||
fun isDownloading(galleryID: String): Boolean {
|
||||
val isThisGallery: (Call) -> Boolean = { (it.request().tag() as? DownloadService.Tag)?.galleryID == galleryID }
|
||||
|
||||
return downloadFolderMap.containsKey(galleryID)
|
||||
@@ -93,11 +93,11 @@ class DownloadManager private constructor(context: Context) : ContextWrapper(con
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun getDownloadFolder(galleryID: Int): FileX? =
|
||||
fun getDownloadFolder(galleryID: String): FileX? =
|
||||
downloadFolderMap[galleryID]?.let { downloadFolder.getChild(it) }
|
||||
|
||||
@Synchronized
|
||||
fun addDownloadFolder(galleryID: Int) {
|
||||
fun addDownloadFolder(galleryID: String) {
|
||||
val name = runBlocking {
|
||||
Cache.getInstance(this@DownloadManager, galleryID).getGalleryBlock()
|
||||
}?.formatDownloadFolder() ?: return
|
||||
@@ -116,7 +116,7 @@ class DownloadManager private constructor(context: Context) : ContextWrapper(con
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun deleteDownloadFolder(galleryID: Int) {
|
||||
fun deleteDownloadFolder(galleryID: String) {
|
||||
downloadFolderMap[galleryID]?.let {
|
||||
kotlin.runCatching {
|
||||
downloadFolder.getChild(it).deleteRecursively()
|
||||
|
||||
@@ -26,9 +26,8 @@ import androidx.core.content.ContextCompat
|
||||
import kotlinx.serialization.json.*
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import xyz.quaver.Code
|
||||
import xyz.quaver.hitomi.GalleryBlock
|
||||
import xyz.quaver.hitomi.Reader
|
||||
import xyz.quaver.hitomi.GalleryInfo
|
||||
import xyz.quaver.hitomi.getReferer
|
||||
import xyz.quaver.hitomi.imageUrlFromImage
|
||||
import xyz.quaver.hiyobi.createImgList
|
||||
@@ -103,11 +102,17 @@ fun GalleryBlock.formatDownloadFolderTest(format: String): String =
|
||||
}
|
||||
}.replace(Regex("""[*\\|"?><:/]"""), "").ellipsize(127)
|
||||
|
||||
val Reader.requestBuilders: List<Request.Builder>
|
||||
val GalleryInfo.requestBuilders: List<Request.Builder>
|
||||
get() {
|
||||
val galleryID = this.galleryInfo.id ?: 0
|
||||
val galleryID = this.id ?: 0
|
||||
val lowQuality = Preferences["low_quality", true]
|
||||
|
||||
return this.files.map {
|
||||
Request.Builder()
|
||||
.url(imageUrlFromImage(galleryID, it, !lowQuality))
|
||||
.header("Referer", getReferer(galleryID))
|
||||
}
|
||||
/*
|
||||
return when(code) {
|
||||
Code.HITOMI -> {
|
||||
this.galleryInfo.files.map {
|
||||
@@ -122,9 +127,8 @@ val Reader.requestBuilders: List<Request.Builder>
|
||||
.url(it.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
fun String.ellipsize(n: Int): String =
|
||||
if (this.length > n)
|
||||
this.slice(0 until n) + "…"
|
||||
|
||||
@@ -46,7 +46,6 @@ import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import ru.noties.markwon.Markwon
|
||||
import xyz.quaver.hitomi.GalleryBlock
|
||||
import xyz.quaver.hitomi.Reader
|
||||
import xyz.quaver.hitomi.getGalleryBlock
|
||||
import xyz.quaver.hitomi.getReader
|
||||
import xyz.quaver.io.FileX
|
||||
@@ -196,7 +195,7 @@ fun checkUpdate(context: Context, force: Boolean = false) {
|
||||
}
|
||||
}
|
||||
|
||||
fun restore(url: String, onFailure: ((Throwable) -> Unit)? = null, onSuccess: ((List<Int>) -> Unit)? = null) {
|
||||
fun restore(url: String, onFailure: ((Throwable) -> Unit)? = null, onSuccess: ((List<String>) -> Unit)? = null) {
|
||||
if (!URLUtil.isValidUrl(url)) {
|
||||
onFailure?.invoke(IllegalArgumentException())
|
||||
return
|
||||
@@ -214,7 +213,7 @@ fun restore(url: String, onFailure: ((Throwable) -> Unit)? = null, onSuccess: ((
|
||||
|
||||
override fun onResponse(call: Call, response: Response) {
|
||||
kotlin.runCatching {
|
||||
Json.decodeFromString<List<Int>>(response.also { if (it.code() != 200) throw IOException() }.body().use { it?.string() } ?: "[]").let {
|
||||
Json.decodeFromString<List<String>>(response.also { if (it.code() != 200) throw IOException() }.body().use { it?.string() } ?: "[]").let {
|
||||
favorites.addAll(it)
|
||||
onSuccess?.invoke(it)
|
||||
}
|
||||
@@ -237,111 +236,4 @@ private val receiver = object: BroadcastReceiver() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@SuppressLint("RestrictedApi")
|
||||
fun xyz.quaver.pupil.util.downloader.DownloadManager.migrate() {
|
||||
registerReceiver(receiver, IntentFilter().apply { addAction(receiver.ACTION_CANCEL) })
|
||||
|
||||
val notificationManager = NotificationManagerCompat.from(this)
|
||||
val action = NotificationCompat.Action.Builder(0, getText(android.R.string.cancel),
|
||||
PendingIntent.getBroadcast(this, R.id.notification_import_cancel_action.normalizeID(), Intent(receiver.ACTION_CANCEL), PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
).build()
|
||||
val notification = NotificationCompat.Builder(this, "import")
|
||||
.setContentTitle(getText(R.string.import_old_galleries_notification))
|
||||
.setProgress(0, 0, true)
|
||||
.addAction(action)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setOngoing(true)
|
||||
|
||||
DownloadService.cancel(this)
|
||||
|
||||
job?.cancel()
|
||||
job = CoroutineScope(Dispatchers.IO).launch {
|
||||
val images = listOf(
|
||||
"jpg",
|
||||
"png",
|
||||
"gif",
|
||||
"webp"
|
||||
)
|
||||
|
||||
val downloadFolders = downloadFolder.listFiles { folder ->
|
||||
folder.isDirectory && !downloadFolderMap.values.contains(folder.name)
|
||||
}?.map {
|
||||
if (it !is FileX)
|
||||
FileX(this@migrate, it)
|
||||
else
|
||||
it
|
||||
}
|
||||
|
||||
if (downloadFolders.isNullOrEmpty()) return@launch
|
||||
|
||||
downloadFolders.forEachIndexed { index, folder ->
|
||||
notification
|
||||
.setContentText(getString(R.string.import_old_galleries_notification_text, index, downloadFolders.size))
|
||||
.setProgress(index, downloadFolders.size, false)
|
||||
notificationManager.notify(R.id.notification_id_import, notification.build())
|
||||
|
||||
val metadata = kotlin.runCatching {
|
||||
folder.getChild(".metadata").readText()?.let { Json.parseToJsonElement(it) }
|
||||
}.getOrNull()
|
||||
|
||||
val galleryID = metadata?.get("reader")?.get("galleryInfo")?.get("id")?.content?.toIntOrNull()
|
||||
?: folder.name.toIntOrNull() ?: return@forEachIndexed
|
||||
|
||||
val galleryBlock: GalleryBlock? = kotlin.runCatching {
|
||||
metadata?.get("galleryBlock")?.let { Json.decodeFromJsonElement<GalleryBlock>(it) }
|
||||
}.getOrNull() ?: kotlin.runCatching {
|
||||
getGalleryBlock(galleryID)
|
||||
}.getOrNull() ?: kotlin.runCatching {
|
||||
xyz.quaver.hiyobi.getGalleryBlock(galleryID)
|
||||
}.getOrNull()
|
||||
|
||||
val reader: Reader? = kotlin.runCatching {
|
||||
metadata?.get("reader")?.let { Json.decodeFromJsonElement<Reader>(it) }
|
||||
}.getOrNull() ?: kotlin.runCatching {
|
||||
getReader(galleryID)
|
||||
}.getOrNull() ?: kotlin.runCatching {
|
||||
xyz.quaver.hiyobi.getReader(galleryID)
|
||||
}.getOrNull()
|
||||
|
||||
metadata?.get("thumbnail")?.jsonPrimitive?.contentOrNull?.also { thumbnail ->
|
||||
val file = folder.getChild(".thumbnail").also {
|
||||
if (it.exists())
|
||||
it.delete()
|
||||
it.createNewFile()
|
||||
}
|
||||
|
||||
file.writeBytes(Base64.decode(thumbnail, Base64.DEFAULT))
|
||||
}
|
||||
|
||||
val list: MutableList<String?> =
|
||||
MutableList(reader!!.galleryInfo.files.size) { null }
|
||||
|
||||
folder.list { _, name ->
|
||||
name?.substringAfterLast('.') in images
|
||||
}?.sorted()?.take(list.size)?.forEachIndexed { i, name ->
|
||||
list[i] = name
|
||||
}
|
||||
|
||||
folder.getChild(".metadata").also { if (it.exists()) it.delete(); it.createNewFile() }.writeText(
|
||||
Json.encodeToString(Metadata(galleryBlock, reader, list))
|
||||
)
|
||||
|
||||
Cache.delete(this@migrate, galleryID)
|
||||
downloadFolderMap[galleryID] = folder.name
|
||||
|
||||
downloadFolder.getChild(".download").let { if (!it.exists()) it.createNewFile(); it.writeText(Json.encodeToString(downloadFolderMap)) }
|
||||
}
|
||||
|
||||
notification
|
||||
.setContentText(getText(R.string.import_old_galleries_notification_done))
|
||||
.setProgress(0, 0, false)
|
||||
.setOngoing(false)
|
||||
.mActions.clear()
|
||||
notificationManager.notify(R.id.notification_id_import, notification.build())
|
||||
|
||||
kotlin.runCatching {
|
||||
unregisterReceiver(receiver)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user