mirror of
https://github.com/InvertGeek/MixFile.git
synced 2026-06-06 20:39:35 +08:00
1.18.3
This commit is contained in:
@@ -16,8 +16,8 @@ android {
|
||||
applicationId = "com.donut.mixfile"
|
||||
minSdk = 26
|
||||
targetSdk = 35
|
||||
versionCode = 140
|
||||
versionName = "1.18.2"
|
||||
versionCode = 141
|
||||
versionName = "1.18.3"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
|
||||
@@ -50,6 +50,7 @@ class App : Application(), ImageLoaderFactory {
|
||||
super.onCreate()
|
||||
MMKV.initialize(this)
|
||||
kv = MMKV.defaultMMKV()
|
||||
kv.enableCompareBeforeSet()
|
||||
Thread.setDefaultUncaughtExceptionHandler { t, e ->
|
||||
showError(e)
|
||||
if (Looper.myLooper() == null) {
|
||||
|
||||
@@ -184,14 +184,15 @@ fun VideoPlayerScreen(
|
||||
player = player,
|
||||
videos = videoUris,
|
||||
onPlayTimeChange = {
|
||||
playHistory = playHistory.filter { it.hash != hash }.toMutableList().apply {
|
||||
val history =
|
||||
VideoHistory(player.currentPosition, hash, player.currentMediaItemIndex)
|
||||
add(0, history)
|
||||
if (size > 500) {
|
||||
removeAt(lastIndex)
|
||||
playHistory =
|
||||
playHistory.filter { !it.hash.contentEquals(hash) }.toMutableList().apply {
|
||||
val history =
|
||||
VideoHistory(player.currentPosition, hash, player.currentMediaItemIndex)
|
||||
add(0, history)
|
||||
if (size > 500) {
|
||||
removeAt(lastIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onTrackTimeChange = {
|
||||
controlsVisible.set(true)
|
||||
|
||||
@@ -2,8 +2,8 @@ package com.donut.mixfile.server
|
||||
|
||||
import com.donut.mixfile.server.core.Uploader
|
||||
import com.donut.mixfile.server.core.uploaders.A3Uploader
|
||||
import com.donut.mixfile.server.core.uploaders.hidden.A1Uploader
|
||||
import com.donut.mixfile.server.core.uploaders.hidden.A2Uploader
|
||||
import com.donut.mixfile.server.core.uploaders.A1Uploader
|
||||
import com.donut.mixfile.server.core.uploaders.A2Uploader
|
||||
import com.donut.mixfile.util.cachedMutableOf
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.get
|
||||
|
||||
@@ -137,7 +137,7 @@ val mixFileServer = object : MixFileServer(
|
||||
}
|
||||
var serverStarted by mutableStateOf(false)
|
||||
|
||||
val WEB_DAV_KEY = "mixfile_web_dav_data"
|
||||
const val WEB_DAV_KEY = "mixfile_web_dav_data"
|
||||
|
||||
|
||||
class FileService : Service() {
|
||||
|
||||
@@ -40,7 +40,7 @@ fun MixFileServer.getUploadRoute(): RoutingHandler {
|
||||
|
||||
call.respondText(uploadFile(call.receiveChannel(), name, size, add.toBoolean()) {
|
||||
call.respondText("上传已取消", status = HttpStatusCode.InternalServerError)
|
||||
})
|
||||
}.first)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ suspend fun MixFileServer.uploadFile(
|
||||
add: Boolean = true,
|
||||
key: ByteArray = generateRandomByteArray(32),
|
||||
onStop: suspend () -> Unit = {}
|
||||
): String {
|
||||
): Pair<String, Long> {
|
||||
|
||||
val uploadTask = getUploadTask(name, size, add)
|
||||
|
||||
@@ -78,7 +78,7 @@ suspend fun MixFileServer.uploadFile(
|
||||
referer = uploader.referer
|
||||
)
|
||||
uploadTask.complete(mixShareInfo)
|
||||
return mixShareInfo.toString()
|
||||
return mixShareInfo.toString() to fileSize
|
||||
}
|
||||
|
||||
private suspend fun MixFileServer.doUploadFile(
|
||||
|
||||
@@ -168,9 +168,14 @@ fun MixFileServer.getWebDAVRoute(): Route.() -> Unit {
|
||||
call.respond(HttpStatusCode.Conflict)
|
||||
return@webdav
|
||||
}
|
||||
val shareInfo = uploadFile(call.receiveChannel(), davFileName, fileSize, add = false)
|
||||
val (shareInfo, finalSize) = uploadFile(
|
||||
call.receiveChannel(),
|
||||
davFileName,
|
||||
fileSize,
|
||||
add = false
|
||||
)
|
||||
val fileNode =
|
||||
WebDavFile(size = fileSize, shareInfoData = shareInfo, name = davFileName)
|
||||
WebDavFile(size = finalSize, shareInfoData = shareInfo, name = davFileName)
|
||||
webDav.addFileNode(davParentPath, fileNode)
|
||||
call.respond(HttpStatusCode.Created)
|
||||
webDav.saveData()
|
||||
@@ -181,6 +186,10 @@ fun MixFileServer.getWebDAVRoute(): Route.() -> Unit {
|
||||
webDav.saveData()
|
||||
}
|
||||
webdav("MKCOL") {
|
||||
if (davPath.isEmpty()) {
|
||||
call.respond(HttpStatusCode.Created)
|
||||
return@webdav
|
||||
}
|
||||
val fileList = webDav.listFiles(davParentPath)
|
||||
if (fileList == null) {
|
||||
call.respond(HttpStatusCode.Conflict)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.donut.mixfile.server.core.uploaders
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray
|
||||
import com.alibaba.fastjson2.to
|
||||
import com.donut.mixfile.server.core.Uploader
|
||||
import com.donut.mixfile.server.core.utils.add
|
||||
import com.donut.mixfile.server.core.utils.fileFormHeaders
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.body
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.request.forms.submitFormWithBinaryData
|
||||
|
||||
object A1Uploader : Uploader("线路A1") {
|
||||
|
||||
override val referer: String
|
||||
get() = "wf︆︈︇︄︇︄︇︀︇︃︃︊︂️︂️︆︋︆︆︂︎︆︆︆︌︆︁︇︃︆︈︂︎︆︃︆︎︂️ey".sCode
|
||||
|
||||
|
||||
override suspend fun doUpload(fileData: ByteArray, client: HttpClient): String {
|
||||
val result =
|
||||
client.submitFormWithBinaryData(
|
||||
"${referer}service/upload",
|
||||
formData {
|
||||
add("flag", "")
|
||||
add("FileUploadForm[file]", fileData, fileFormHeaders())
|
||||
}) {
|
||||
}.body<String>().to<JSONArray>()
|
||||
if (result.isEmpty()) {
|
||||
throw Exception("上传失败")
|
||||
}
|
||||
val data = result.getJSONObject(0)
|
||||
val url = data.getString("url") ?: throw Exception("上传失败")
|
||||
return "https:${url}"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package com.donut.mixfile.server.core.uploaders
|
||||
|
||||
import com.alibaba.fastjson2.to
|
||||
import com.donut.mixfile.server.core.Uploader
|
||||
import com.donut.mixfile.server.core.utils.add
|
||||
import com.donut.mixfile.server.core.utils.decodeHex
|
||||
import com.donut.mixfile.server.core.utils.fileFormHeaders
|
||||
import com.donut.mixfile.server.core.utils.genRandomString
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.call.body
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.request.forms.submitFormWithBinaryData
|
||||
import io.ktor.client.request.get
|
||||
import io.ktor.http.isSuccess
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
|
||||
|
||||
val String.sCode: String
|
||||
get() = decodeHex(this)
|
||||
|
||||
|
||||
object A2Uploader : Uploader("线路A2") {
|
||||
|
||||
private val domain =
|
||||
"d︆︈︇︄︇︄︇︀︇︃︃︊︂️︂️︇︇︇︇︇︇︂︎︇︇︆︊︇︈︂︎︆︃︆︎︂️wa".sCode
|
||||
|
||||
init {
|
||||
//旧文件兼容
|
||||
registerUrlTransform("A2") {
|
||||
it.replace(
|
||||
"CO︆︈︇︄︇︄︇︀︇︃︃︊︂️︂️︇︀︆︌︆︁︇︄︂︍︇︃︆︈︂︍︆︃︆️︆︍︆︍︇︅︆︎︆︉︇︄︇︉︂︍︇︀︇︂︆️︆︄︂︍︇︅︇︀︆︌︆️︆︁︆︄︂︍︇︅︆︇︆︃︂︎︆️︇︃︇︃︂︍︆︃︆︎︂︍︇︃︆︈︆︁︆︎︆︇︆︈︆︁︆︉︂︎︆︁︆︌︆︉︇︉︇︅︆︎︆︃︇︃︂︎︆︃︆️︆︍︂️gP".sCode,
|
||||
"d5︆︈︇︄︇︄︇︀︇︃︃︊︂️︂️︇︅︇︀︆︌︆️︆︁︆︄︂︍︆︂︆︂︇︃︂︎︆︍︆︉︇︉︆️︇︅︇︃︆︈︆︅︂︎︆︃︆️︆︍︂️w3".sCode
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class Token(
|
||||
val host: String,
|
||||
val accessid: String,
|
||||
val policy: String,
|
||||
val signature: String,
|
||||
val dir: String,
|
||||
)
|
||||
|
||||
|
||||
override val referer: String
|
||||
get() = domain
|
||||
|
||||
var tokenCache: Token? = null
|
||||
var tokenCacheTime: Long = 0
|
||||
val tokenLock = Mutex()
|
||||
|
||||
private suspend fun getToken(client: HttpClient): Token {
|
||||
tokenLock.withLock {
|
||||
val cached = tokenCache
|
||||
if (cached != null && System.currentTimeMillis() - tokenCacheTime < 1000 * 60) {
|
||||
return cached
|
||||
}
|
||||
val response =
|
||||
client.get("${domain}handler/getoss.ashx")
|
||||
if (!response.status.isSuccess()) {
|
||||
throw Exception("上传失败")
|
||||
}
|
||||
val data: Token = response.body<String>().to()
|
||||
tokenCache = data
|
||||
tokenCacheTime = System.currentTimeMillis()
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun doUpload(fileData: ByteArray, client: HttpClient): String {
|
||||
val token = getToken(client)
|
||||
|
||||
val key = "${token.dir}${genRandomString()}"
|
||||
|
||||
val response = client.submitFormWithBinaryData(token.host, formData {
|
||||
add("policy", token.policy)
|
||||
add("OSSAccessKeyId", token.accessid)
|
||||
add("Signature", token.signature)
|
||||
add("key", key)
|
||||
add("content-type", "image/gif")
|
||||
add("file", fileData, fileFormHeaders())
|
||||
})
|
||||
|
||||
if (!response.status.isSuccess()) {
|
||||
throw Exception("上传失败")
|
||||
}
|
||||
|
||||
return "${"a︆︈︇︄︇︄︇︀︇︃︃︊︂️︂️︇︀︇︅︆︂︆︎︆︅︇︇︆︆︇︂︂︎︇︀︆︁︇︀︆︅︇︂︆️︆︌︂︎︆︃︆︎︂️wa".sCode}/${key}"
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ import com.donut.mixfile.server.UPLOADERS
|
||||
import com.donut.mixfile.server.UPLOAD_RETRY_COUNT
|
||||
import com.donut.mixfile.server.UPLOAD_TASK_COUNT
|
||||
import com.donut.mixfile.server.core.Uploader
|
||||
import com.donut.mixfile.server.core.uploaders.hidden.A1Uploader
|
||||
import com.donut.mixfile.server.core.uploaders.A1Uploader
|
||||
import com.donut.mixfile.server.currentUploader
|
||||
import com.donut.mixfile.server.getCurrentUploader
|
||||
import com.donut.mixfile.ui.component.common.CommonSwitch
|
||||
|
||||
@@ -126,7 +126,7 @@ val Favorites = MixNavPage(
|
||||
LaunchedEffect(searchVal, currentCategory, favorites, favoriteSort) {
|
||||
result = if (searchVal.trim().isNotEmpty()) {
|
||||
favorites.filter {
|
||||
it.name.contains(searchVal)
|
||||
it.name.contains(searchVal, true)
|
||||
}.asReversed()
|
||||
} else {
|
||||
favorites.asReversed()
|
||||
|
||||
@@ -8,12 +8,9 @@ import com.alibaba.fastjson2.toJSONString
|
||||
import com.donut.mixfile.appScope
|
||||
import com.donut.mixfile.kv
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
|
||||
fun <T> constructCachedMutableValue(
|
||||
@@ -77,7 +74,7 @@ abstract class CachedMutableValue<T>(
|
||||
) {
|
||||
private var loaded = false
|
||||
private val mutex = Mutex()
|
||||
private var saveTask: Job? = null
|
||||
|
||||
private var stateValue by mutableLongStateOf(0)
|
||||
|
||||
abstract fun readCachedValue(): T
|
||||
@@ -103,13 +100,9 @@ abstract class CachedMutableValue<T>(
|
||||
}
|
||||
stateValue++
|
||||
this.value = value
|
||||
saveTask?.cancel()
|
||||
saveTask = appScope.launch(Dispatchers.Main) {
|
||||
appScope.launch(Dispatchers.IO) {
|
||||
mutex.withLock {
|
||||
delay(100)
|
||||
withContext(Dispatchers.IO) {
|
||||
writeCachedValue(this@CachedMutableValue.value)
|
||||
}
|
||||
writeCachedValue(this@CachedMutableValue.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user