Created new cache/downloader
This commit is contained in:
@@ -99,7 +99,7 @@ dependencies {
|
|||||||
implementation ("xyz.quaver:libpupil:1.1") {
|
implementation ("xyz.quaver:libpupil:1.1") {
|
||||||
exclude group: 'org.jetbrains.kotlinx', module: 'kotlinx-serialization-core-jvm'
|
exclude group: 'org.jetbrains.kotlinx', module: 'kotlinx-serialization-core-jvm'
|
||||||
}
|
}
|
||||||
implementation "xyz.quaver:documentfilex:0.2"
|
implementation "xyz.quaver:documentfilex:0.2.2"
|
||||||
testImplementation 'junit:junit:4.13'
|
testImplementation 'junit:junit:4.13'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||||
androidTestImplementation 'androidx.test:rules:1.3.0'
|
androidTestImplementation 'androidx.test:rules:1.3.0'
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ class Pupil : Application() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Preferences.get<String>("dl_location").also {
|
Preferences.get<String>("download_folder").also {
|
||||||
if (!File(it).canWrite())
|
if (!File(it).canWrite())
|
||||||
throw Exception()
|
throw Exception()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,32 +19,21 @@
|
|||||||
package xyz.quaver.pupil.services
|
package xyz.quaver.pupil.services
|
||||||
|
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Context
|
|
||||||
import android.content.ContextWrapper
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Binder
|
|
||||||
import android.os.IBinder
|
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.app.NotificationManagerCompat
|
import androidx.core.app.NotificationManagerCompat
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import okhttp3.Interceptor
|
|
||||||
import okhttp3.ResponseBody
|
import okhttp3.ResponseBody
|
||||||
import okio.*
|
import okio.*
|
||||||
import xyz.quaver.pupil.PupilInterceptor
|
import xyz.quaver.pupil.PupilInterceptor
|
||||||
import xyz.quaver.pupil.R
|
import xyz.quaver.pupil.R
|
||||||
import xyz.quaver.pupil.interceptors
|
import xyz.quaver.pupil.interceptors
|
||||||
|
import xyz.quaver.pupil.util.downloader.Cache
|
||||||
|
|
||||||
private typealias ProgressListener = (DownloadService.Tag, Long, Long, Boolean) -> Unit
|
private typealias ProgressListener = (DownloadService.Tag, Long, Long, Boolean) -> Unit
|
||||||
|
|
||||||
class Cache(context: Context) : ContextWrapper(context) {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class DownloadService : Service() {
|
class DownloadService : Service() {
|
||||||
|
|
||||||
data class Tag(val galleryID: Int, val index: Int)
|
data class Tag(val galleryID: Int, val index: Int)
|
||||||
@@ -144,8 +133,17 @@ class DownloadService : Service() {
|
|||||||
private val binder = Binder()
|
private val binder = Binder()
|
||||||
override fun onBind(p0: Intent?) = binder
|
override fun onBind(p0: Intent?) = binder
|
||||||
|
|
||||||
|
val cache = SparseArray<Cache>()
|
||||||
fun load(galleryID: Int) {
|
fun load(galleryID: Int) {
|
||||||
|
if (progress.indexOfKey(galleryID) < 0)
|
||||||
|
progress.put(galleryID, mutableListOf())
|
||||||
|
|
||||||
|
if (cache.indexOfKey(galleryID) < 0)
|
||||||
|
cache.put(galleryID, Cache.getInstance(this, galleryID))
|
||||||
|
|
||||||
|
cache[galleryID].metadata.imageList?.forEach {
|
||||||
|
progress[galleryID]?.add(if (it == null) Float.POSITIVE_INFINITY else 0F)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun download(galleryID: Int) = CoroutineScope(Dispatchers.IO).launch {
|
fun download(galleryID: Int) = CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import android.util.SparseArray
|
|||||||
import androidx.preference.PreferenceManager
|
import androidx.preference.PreferenceManager
|
||||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.serialization.decodeFromString
|
import kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@@ -41,6 +43,7 @@ import java.io.FileOutputStream
|
|||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
|
||||||
|
@Deprecated("Use downloader.Cache instead")
|
||||||
class Cache(context: Context) : ContextWrapper(context) {
|
class Cache(context: Context) : ContextWrapper(context) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import java.io.File
|
|||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.concurrent.LinkedBlockingQueue
|
import java.util.concurrent.LinkedBlockingQueue
|
||||||
|
|
||||||
|
@Deprecated("Use DownloadService instead")
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class DownloadWorker private constructor(context: Context) : ContextWrapper(context) {
|
class DownloadWorker private constructor(context: Context) : ContextWrapper(context) {
|
||||||
|
|
||||||
|
|||||||
@@ -22,12 +22,13 @@ import kotlinx.serialization.Serializable
|
|||||||
import xyz.quaver.hitomi.GalleryBlock
|
import xyz.quaver.hitomi.GalleryBlock
|
||||||
import xyz.quaver.hitomi.Reader
|
import xyz.quaver.hitomi.Reader
|
||||||
|
|
||||||
|
@Deprecated("Use downloader.Cache.Metadata instead")
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Metadata(
|
data class Metadata(
|
||||||
val thumbnail: String? = null,
|
var thumbnail: String? = null,
|
||||||
val galleryBlock: GalleryBlock? = null,
|
var galleryBlock: GalleryBlock? = null,
|
||||||
val reader: Reader? = null,
|
var reader: Reader? = null,
|
||||||
val isDownloading: Boolean? = null
|
var isDownloading: Boolean? = null
|
||||||
) {
|
) {
|
||||||
constructor(
|
constructor(
|
||||||
metadata: Metadata?,
|
metadata: Metadata?,
|
||||||
|
|||||||
239
app/src/main/java/xyz/quaver/pupil/util/downloader/Cache.kt
Normal file
239
app/src/main/java/xyz/quaver/pupil/util/downloader/Cache.kt
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
/*
|
||||||
|
* 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.util.downloader
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.ContextWrapper
|
||||||
|
import android.util.Base64
|
||||||
|
import android.util.SparseArray
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import okhttp3.Request
|
||||||
|
import xyz.quaver.Code
|
||||||
|
import xyz.quaver.hitomi.Gallery
|
||||||
|
import xyz.quaver.hitomi.GalleryBlock
|
||||||
|
import xyz.quaver.hitomi.Reader
|
||||||
|
import xyz.quaver.hitomi.getGallery
|
||||||
|
import xyz.quaver.io.FileX
|
||||||
|
import xyz.quaver.io.util.getChild
|
||||||
|
import xyz.quaver.io.util.readBytes
|
||||||
|
import xyz.quaver.io.util.readText
|
||||||
|
import xyz.quaver.io.util.writeBytes
|
||||||
|
import xyz.quaver.pupil.client
|
||||||
|
import xyz.quaver.pupil.util.Preferences
|
||||||
|
import xyz.quaver.pupil.util.formatDownloadFolder
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Metadata(
|
||||||
|
var galleryBlock: GalleryBlock? = null,
|
||||||
|
var gallery: Gallery? = null,
|
||||||
|
var thumbnail: String? = null,
|
||||||
|
var reader: Reader? = null,
|
||||||
|
var imageList: MutableList<String?>? = null
|
||||||
|
) {
|
||||||
|
fun copy(): Metadata = Metadata(galleryBlock, gallery, thumbnail, reader, imageList?.let { MutableList(it.size) { i -> it[i] } })
|
||||||
|
}
|
||||||
|
|
||||||
|
class Cache private constructor(context: Context, val galleryID: Int) : ContextWrapper(context) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val instances = SparseArray<Cache>()
|
||||||
|
|
||||||
|
fun getInstance(context: Context, galleryID: Int) =
|
||||||
|
instances[galleryID] ?: synchronized(this) {
|
||||||
|
instances[galleryID] ?: Cache(context, galleryID).also { instances.put(galleryID, it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var metadata = kotlin.runCatching {
|
||||||
|
findFile(".metadata")?.readText()?.let {
|
||||||
|
Json.decodeFromString<Metadata>(it)
|
||||||
|
}
|
||||||
|
}.getOrNull() ?: Metadata()
|
||||||
|
|
||||||
|
val downloadFolder: FileX?
|
||||||
|
get() = DownloadFolderManager.getInstance(this).getDownloadFolder(galleryID)
|
||||||
|
|
||||||
|
val cacheFolder: FileX
|
||||||
|
get() = FileX(this, cacheDir, "imageCache/$galleryID")
|
||||||
|
|
||||||
|
val cachedGallery: FileX
|
||||||
|
get() = DownloadFolderManager.getInstance(this).getDownloadFolder(galleryID)
|
||||||
|
?: FileX(this, cacheDir, "imageCache/$galleryID")
|
||||||
|
|
||||||
|
fun findFile(fileName: String): FileX? =
|
||||||
|
cacheFolder.getChild(fileName).let {
|
||||||
|
if (it.exists()) it else null
|
||||||
|
} ?: downloadFolder?.let { downloadFolder -> downloadFolder.getChild(fileName).let {
|
||||||
|
if (it.exists()) it else null
|
||||||
|
} }
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun setMetadata(change: (Metadata) -> Unit) {
|
||||||
|
change.invoke(metadata)
|
||||||
|
|
||||||
|
val file = cachedGallery.getChild(".metadata")
|
||||||
|
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
file.writeText(Json.encodeToString(Metadata))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getGalleryBlock(): GalleryBlock? {
|
||||||
|
val sources = listOf(
|
||||||
|
{ xyz.quaver.hitomi.getGalleryBlock(galleryID) },
|
||||||
|
{ xyz.quaver.hiyobi.getGalleryBlock(galleryID) }
|
||||||
|
)
|
||||||
|
|
||||||
|
return metadata.galleryBlock
|
||||||
|
?: withContext(Dispatchers.IO) {
|
||||||
|
var galleryBlock: GalleryBlock? = null
|
||||||
|
|
||||||
|
for (source in sources) {
|
||||||
|
galleryBlock = try {
|
||||||
|
source.invoke()
|
||||||
|
} catch (e: Exception) { null }
|
||||||
|
|
||||||
|
if (galleryBlock != null)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
galleryBlock?.also {
|
||||||
|
launch { setMetadata { metadata -> metadata.galleryBlock = it } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getGallery(): Gallery? =
|
||||||
|
metadata.gallery
|
||||||
|
?: withContext(Dispatchers.IO) {
|
||||||
|
kotlin.runCatching {
|
||||||
|
getGallery(galleryID)
|
||||||
|
}.getOrNull()?.also {
|
||||||
|
launch { setMetadata { metadata ->
|
||||||
|
metadata.gallery = it
|
||||||
|
|
||||||
|
if (metadata.imageList == null)
|
||||||
|
metadata.imageList = MutableList(it.thumbnails.size) { null }
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
|
suspend fun getThumbnail(): String? =
|
||||||
|
metadata.thumbnail
|
||||||
|
?: withContext(Dispatchers.IO) {
|
||||||
|
getGalleryBlock()?.thumbnails?.firstOrNull()?.let { thumbnail ->
|
||||||
|
kotlin.runCatching {
|
||||||
|
val request = Request.Builder()
|
||||||
|
.url(thumbnail)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val image = client.newCall(request).execute().body()?.use { it.bytes() }
|
||||||
|
|
||||||
|
Base64.encodeToString(image, Base64.DEFAULT)
|
||||||
|
}.getOrNull()
|
||||||
|
}?.also {
|
||||||
|
launch { setMetadata { metadata -> metadata.thumbnail = it } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun getReader(galleryID: Int): Reader? {
|
||||||
|
val mirrors = Preferences.get<String>("mirrors").split('>')
|
||||||
|
|
||||||
|
val sources = mapOf(
|
||||||
|
Code.HITOMI to { xyz.quaver.hitomi.getReader(galleryID) },
|
||||||
|
Code.HIYOBI to { xyz.quaver.hiyobi.getReader(galleryID) }
|
||||||
|
).toSortedMap { o1, o2 -> mirrors.indexOf(o1.name) - mirrors.indexOf(o2.name) }
|
||||||
|
|
||||||
|
return metadata.reader
|
||||||
|
?: withContext(Dispatchers.IO) {
|
||||||
|
var reader: Reader? = null
|
||||||
|
|
||||||
|
for (source in sources) {
|
||||||
|
reader = try { withTimeoutOrNull(1000) {
|
||||||
|
source.value.invoke()
|
||||||
|
} } catch (e: Exception) { null }
|
||||||
|
|
||||||
|
if (reader != null)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
reader?.also {
|
||||||
|
launch { setMetadata { metadata ->
|
||||||
|
metadata.reader = it
|
||||||
|
|
||||||
|
if (metadata.imageList == null)
|
||||||
|
metadata.imageList = MutableList(reader.galleryInfo.files.size) { null }
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getImage(index: Int): FileX? =
|
||||||
|
metadata.imageList?.get(index)?.let { findFile(it) }
|
||||||
|
|
||||||
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
|
fun putImage(index: Int, fileName: String, data: ByteArray) = CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
val file = FileX(this@Cache, cachedGallery, fileName).also {
|
||||||
|
it.createNewFile()
|
||||||
|
}
|
||||||
|
|
||||||
|
file.writeBytes(data)
|
||||||
|
|
||||||
|
setMetadata { metadata -> metadata.imageList!![index] = fileName }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("BlockingMethodInNonBlockingContext")
|
||||||
|
fun moveToDownload() = CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
if (downloadFolder == null)
|
||||||
|
DownloadFolderManager.getInstance(this@Cache).addDownloadFolder(galleryID, this@Cache.formatDownloadFolder())
|
||||||
|
|
||||||
|
metadata.imageList?.forEach {
|
||||||
|
it ?: return@forEach
|
||||||
|
|
||||||
|
val target = downloadFolder!!.getChild(it)
|
||||||
|
val source = cacheFolder.getChild(it)
|
||||||
|
|
||||||
|
if (!source.exists())
|
||||||
|
return@forEach
|
||||||
|
|
||||||
|
kotlin.runCatching {
|
||||||
|
target.createNewFile()
|
||||||
|
source.readBytes()?.let { target.writeBytes(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val cacheMetadata = cacheFolder.getChild(".metadata")
|
||||||
|
val downloadMetadata = downloadFolder!!.getChild(".metadata")
|
||||||
|
|
||||||
|
if (cacheMetadata.exists()) {
|
||||||
|
kotlin.runCatching {
|
||||||
|
downloadMetadata.createNewFile()
|
||||||
|
cacheMetadata.readBytes()?.let { downloadMetadata.writeBytes(it) }
|
||||||
|
cacheMetadata.delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cacheFolder.delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* 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.util.downloader
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.ContextWrapper
|
||||||
|
import android.webkit.URLUtil
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import xyz.quaver.io.FileX
|
||||||
|
import xyz.quaver.io.util.readText
|
||||||
|
import xyz.quaver.pupil.util.Preferences
|
||||||
|
|
||||||
|
class DownloadFolderManager private constructor(context: Context) : ContextWrapper(context) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Volatile private var instance: DownloadFolderManager? = null
|
||||||
|
|
||||||
|
fun getInstance(context: Context) =
|
||||||
|
instance ?: synchronized(this) {
|
||||||
|
instance ?: DownloadFolderManager(context).also { instance = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val defaultDownloadFolder = FileX(this, getExternalFilesDir(null)!!)
|
||||||
|
|
||||||
|
val downloadFolder = {
|
||||||
|
val uri: String = Preferences["download_directory"]
|
||||||
|
|
||||||
|
if (!URLUtil.isValidUrl(uri))
|
||||||
|
Preferences["download_directory"] = defaultDownloadFolder
|
||||||
|
|
||||||
|
kotlin.runCatching {
|
||||||
|
FileX(this, uri)
|
||||||
|
}.getOrElse {
|
||||||
|
Preferences["download_directory"] = defaultDownloadFolder
|
||||||
|
FileX(this, defaultDownloadFolder)
|
||||||
|
}
|
||||||
|
}.invoke()
|
||||||
|
|
||||||
|
private val downloadFolderMap: MutableMap<Int, String> =
|
||||||
|
kotlin.runCatching {
|
||||||
|
FileX(this@DownloadFolderManager, downloadFolder, ".download").readText()?.let {
|
||||||
|
Json.decodeFromString<MutableMap<Int, String>>(it)
|
||||||
|
}
|
||||||
|
}.getOrNull() ?: mutableMapOf()
|
||||||
|
private val downloadFolderMapMutex = Mutex()
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun getDownloadFolder(galleryID: Int): FileX? =
|
||||||
|
downloadFolderMap[galleryID]?.let { FileX(this, downloadFolder, it) }
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun addDownloadFolder(galleryID: Int, name: String) {
|
||||||
|
if (downloadFolderMap.containsKey(galleryID))
|
||||||
|
return
|
||||||
|
|
||||||
|
if (FileX(this@DownloadFolderManager, downloadFolder, name).mkdir()) {
|
||||||
|
downloadFolderMap[galleryID] = name
|
||||||
|
|
||||||
|
CoroutineScope(Dispatchers.IO).launch { downloadFolderMapMutex.withLock {
|
||||||
|
FileX(this@DownloadFolderManager, downloadFolder, ".download").writeText(Json.encodeToString(downloadFolderMap))
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Synchronized
|
||||||
|
fun removeDownloadFolder(galleryID: Int) {
|
||||||
|
if (!downloadFolderMap.containsKey(galleryID))
|
||||||
|
return
|
||||||
|
|
||||||
|
downloadFolderMap[galleryID]?.let {
|
||||||
|
if (FileX(this@DownloadFolderManager, downloadFolder, it).delete()) {
|
||||||
|
downloadFolderMap.remove(galleryID)
|
||||||
|
|
||||||
|
CoroutineScope(Dispatchers.IO).launch { downloadFolderMapMutex.withLock {
|
||||||
|
FileX(this@DownloadFolderManager, downloadFolder, ".download").writeText(Json.encodeToString(downloadFolderMap))
|
||||||
|
} }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -18,19 +18,15 @@
|
|||||||
|
|
||||||
package xyz.quaver.pupil.util
|
package xyz.quaver.pupil.util
|
||||||
|
|
||||||
import android.annotation.TargetApi
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
|
||||||
import android.os.storage.StorageManager
|
import android.os.storage.StorageManager
|
||||||
import android.provider.DocumentsContract
|
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.net.toUri
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.lang.reflect.Array
|
import java.lang.reflect.Array
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
|
||||||
|
|
||||||
fun getCachedGallery(context: Context, galleryID: Int) =
|
fun getCachedGallery(context: Context, galleryID: Int) =
|
||||||
File(getDownloadDirectory(context), galleryID.toString()).let {
|
File(getDownloadDirectory(context), galleryID.toString()).let {
|
||||||
if (it.exists())
|
if (it.exists())
|
||||||
|
|||||||
@@ -19,7 +19,14 @@
|
|||||||
package xyz.quaver.pupil.util
|
package xyz.quaver.pupil.util
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.coroutines.sync.withLock
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
|
import xyz.quaver.pupil.util.downloader.Cache
|
||||||
|
import xyz.quaver.pupil.util.downloader.Metadata
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
@@ -68,3 +75,19 @@ fun OkHttpClient.Builder.proxyInfo(proxyInfo: ProxyInfo) = this.apply {
|
|||||||
proxyAuthenticator(it)
|
proxyAuthenticator(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val formatMap = mapOf<String, (Cache) -> (String)>(
|
||||||
|
"\$ID" to { runBlocking { it.getGalleryBlock()?.id.toString() } },
|
||||||
|
"\$TITLE" to { runBlocking { it.getGalleryBlock()?.title.toString() } },
|
||||||
|
// TODO
|
||||||
|
)
|
||||||
|
/**
|
||||||
|
* Formats download folder name with given Metadata
|
||||||
|
*/
|
||||||
|
fun Cache.formatDownloadFolder(): String {
|
||||||
|
return Preferences["download_folder_format", "\$ID"].apply {
|
||||||
|
formatMap.entries.forEach { (key, lambda) ->
|
||||||
|
this.replace(key, lambda.invoke(this@formatDownloadFolder))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user