修复A2线路,优化网页端

This commit is contained in:
1
2024-09-24 21:44:46 +08:00
parent 0d5d0880ee
commit ba84869fb7
13 changed files with 64 additions and 65 deletions

View File

@@ -14,8 +14,8 @@ android {
applicationId = "com.donut.mixfile"
minSdk = 24
targetSdk = 34
versionCode = 35
versionName = "1.4.4"
versionCode = 36
versionName = "1.4.5"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {

View File

@@ -299,7 +299,7 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
font-size: max(.6rem, 14px);
}
`;let aa=null,la=null;function aS(e){const[t,n]=fe([]),[r,o]=fe("");if(aa=n,la=o,t.length===0)return null;const i=r.split(`
`).length===t.length;return $(Qa,{open:!0,children:$(sS,{className:"shadow",children:[i?$("h3",{className:"file-card animate__animated animate__bounceIn",children:[t.length," 个文件全部上传成功"]}):$("h3",{children:[t.length," 个文件正在上传"]}),$("div",{class:"content",children:t.map((s,a)=>$(iS,{file:s},a))}),i&&$(ia.CopyToClipboard,{className:"file-card animate__animated animate__bounceIn",text:r,onCopy:()=>{zo("复制成功!")},children:$(jn,{variant:"outlined",children:"全部复制"})}),$(jn,{variant:"contained",onClick:()=>{aa([]),la("")},children:i?"关闭":"取消"})]})})}function Qc(e){aa(t=>[...t,...e])}function lS(e){la(t=>`${t}
`).length===t.length;return $(Qa,{open:!0,children:$(sS,{className:"shadow",children:[i?$("h3",{className:"file-card animate__animated animate__bounceIn",children:[t.length," 个文件全部上传成功"]}):$("h3",{children:[t.length," 个文件正在上传"]}),$("div",{class:"content",children:t.map((s,a)=>$(iS,{file:s},a))}),$(ia.CopyToClipboard,{className:"file-card animate__animated animate__bounceIn",text:r,onCopy:()=>{zo("复制成功!")},children:$(jn,{variant:"outlined",children:"全部复制"})}),$(jn,{variant:"contained",onClick:()=>{aa([]),la("")},children:i?"关闭":"取消"})]})})}function Qc(e){aa(t=>[...t,...e])}function lS(e){la(t=>`${t}
${e}`.trim())}class cS{constructor(t){this.queue=void 0,this.maxConcurrent=void 0,this.count=void 0,this.queue=[],this.maxConcurrent=t,this.count=0}get canAcquire(){return this.count<this.maxConcurrent}acquire(){return this.canAcquire?(this.count++,Promise.resolve()):new Promise(t=>this.queue.push(t))}release(){const t=this.queue.shift();t?setTimeout(t,0):this.count--}}const Bt="_default";class uS{constructor(t=1){this.semaphoreInstances=void 0,this.maxConcurrent=void 0,this.semaphoreInstances={},this.maxConcurrent=t}hasSemaphoreInstance(t=Bt){return!!this.semaphoreInstances[t]}getSemaphoreInstance(t=Bt){return this.hasSemaphoreInstance(t)||(this.semaphoreInstances[t]=new cS(this.maxConcurrent)),this.semaphoreInstances[t]}tidy(t=Bt){this.hasSemaphoreInstance(t)&&this.getSemaphoreInstance(t).count===0&&delete this.semaphoreInstances[t]}canAcquire(t=Bt){return this.getSemaphoreInstance(t).canAcquire}acquire(t=Bt){return this.getSemaphoreInstance(t).acquire()}release(t=Bt){this.getSemaphoreInstance(t).release(),this.tidy(t)}count(t=Bt){return this.hasSemaphoreInstance(t)?this.getSemaphoreInstance(t).count:0}hasTasks(t=Bt){return this.count(t)>0}async request(t,n=Bt){try{return await this.acquire(n),await t()}finally{this.release(n)}}async requestIfAvailable(t,n=Bt){return this.canAcquire(n)?this.request(t,n):null}}const dS=cn.div`
display: flex;
flex-wrap: wrap;

View File

@@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta content="width=device-width,user-scalable=no,initial-scale=1,maximum-scale=1,minimum-scale=1" name="viewport"/>
<title>MixFile</title>
<script type="module" crossorigin src="/assets/index-BN0yumEX.js"></script>
<script type="module" crossorigin src="/assets/index-DKGuaJ-j.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BuZ9x1Ok.css">
</head>
<body>

View File

@@ -22,7 +22,7 @@ var UPLOAD_RETRY_TIMES by cachedMutableOf(3, "UPLOAD_RETRY_TIMES")
val uploadClient = HttpClient(CIO).config {
install(ContentNegotiation) {
gson()
register(ContentType.Text.Html, GsonConverter(GsonBuilder().create()))
register(ContentType.Any, GsonConverter(GsonBuilder().create()))
}
install(HttpRequestRetry) {
maxRetries = UPLOAD_RETRY_TIMES.toInt()

View File

@@ -22,7 +22,7 @@ abstract class Uploader(val name: String) {
open val referer = ""
open val chunkSize = 1024L * 1024L
abstract suspend fun doUpload(fileData: ByteArray): String?
abstract suspend fun doUpload(fileData: ByteArray): String
companion object {
val urlTransforms = mutableMapOf<String, (String) -> String>()
@@ -52,7 +52,7 @@ abstract class Uploader(val name: String) {
}
}
suspend fun upload(head: ByteArray, fileData: ByteArray, key: ByteArray): String? {
suspend fun upload(head: ByteArray, fileData: ByteArray, key: ByteArray): String {
val encryptedData = encryptBytes(head, fileData, key)
try {
return doUpload(encryptedData)

View File

@@ -96,7 +96,7 @@ suspend fun uploadFile(
fileIndex++
tasks.add(async {
try {
val url = uploader.upload(head, fileData, secret) ?: return@async null
val url = uploader.upload(head, fileData, secret)
fileList[currentIndex] = url
withContext(Dispatchers.Main) {
uploadTask.progress.updateProgress(channel.totalBytesRead, fileSize)
@@ -114,7 +114,6 @@ suspend fun uploadFile(
MixFile(chunkSize = chunkSize, version = 0, fileList = fileList, fileSize = fileSize)
val mixFileUrl =
uploader.upload(head, mixFile.toBytes(), secret)
?: return@coroutineScope null
return@coroutineScope mixFileUrl
}
}

View File

@@ -14,7 +14,7 @@ object A3Uploader : Uploader("线路A3") {
override val referer: String
get() = ""
override suspend fun doUpload(fileData: ByteArray): String? {
override suspend fun doUpload(fileData: ByteArray): String {
val result = uploadClient.submitFormWithBinaryData("https://pic.2xb.cn/uppic.php?type=qq",
formData {
add("file", fileData, fileFormHeaders())
@@ -22,7 +22,7 @@ object A3Uploader : Uploader("线路A3") {
}.body<JsonObject>()
val code = result.get("code").asInt
if (code != 200) {
return null
throw Exception("上传失败: $code")
}
return result.get("url").asString

View File

@@ -118,11 +118,11 @@ val MixSettings = MixNavPage(
color = MaterialTheme.colorScheme.primary
)
Slider(
value = UPLOAD_TASK_COUNT.toFloat() / 100f,
steps = 100,
value = UPLOAD_TASK_COUNT.toFloat() / 10f,
steps = 10,
modifier = Modifier.fillMaxWidth(),
onValueChange = {
UPLOAD_TASK_COUNT = (it * 100).toLong().coerceAtLeast(1)
UPLOAD_TASK_COUNT = (it * 10).toLong().coerceAtLeast(1)
}
)
}
@@ -148,11 +148,11 @@ val MixSettings = MixNavPage(
color = MaterialTheme.colorScheme.primary
)
Slider(
value = UPLOAD_RETRY_TIMES.toFloat() / 20f,
steps = 20,
value = UPLOAD_RETRY_TIMES.toFloat() / 10f,
steps = 10,
modifier = Modifier.fillMaxWidth(),
onValueChange = {
UPLOAD_RETRY_TIMES = (it * 20).toLong().coerceAtLeast(0)
UPLOAD_RETRY_TIMES = (it * 10).toLong().coerceAtLeast(0)
}
)
}
@@ -181,6 +181,27 @@ val MixSettings = MixNavPage(
) {
enablePreview = it
}
SettingButton(text = "上传线路: $currentUploader") {
selectUploader()
}
if (getCurrentUploader() == CustomUploader) {
OutlinedTextField(value = CUSTOM_UPLOAD_URL, onValueChange = {
CUSTOM_UPLOAD_URL = it
}, label = { Text(text = "请求地址") }, modifier = Modifier.fillMaxWidth())
OutlinedTextField(value = CUSTOM_REFERER, onValueChange = {
CUSTOM_REFERER = it
}, label = { Text(text = "referer") }, modifier = Modifier.fillMaxWidth())
Text(
color = Color.Gray,
text = """
自定义线路请自行实现,app会使用put方式发送请求
请求体为图片二进制,成功请返回200状态码,内容直接返回url
失败返回403或500(会重试)状态码
另外需要实现get方法返回填充图片,推荐gif格式
图片尺寸不宜过大,否则影响上传速度
""".trimIndent()
)
}
HorizontalDivider()
ElevatedButton(onClick = {
MixDialogBuilder("确定清除记录?").apply {
@@ -207,27 +228,6 @@ val MixSettings = MixNavPage(
Text(text = "省电限制未设置!")
}
}
SettingButton(text = "上传线路: $currentUploader") {
selectUploader()
}
if (getCurrentUploader() == CustomUploader) {
OutlinedTextField(value = CUSTOM_UPLOAD_URL, onValueChange = {
CUSTOM_UPLOAD_URL = it
}, label = { Text(text = "请求地址") }, modifier = Modifier.fillMaxWidth())
OutlinedTextField(value = CUSTOM_REFERER, onValueChange = {
CUSTOM_REFERER = it
}, label = { Text(text = "referer") }, modifier = Modifier.fillMaxWidth())
Text(
color = Color.Gray,
text = """
自定义线路请自行实现,app会使用put方式发送请求
请求体为图片二进制,成功请返回200状态码,内容直接返回url
失败返回403或500(会重试)状态码
另外需要实现get方法返回填充图片,推荐gif格式
图片尺寸不宜过大,否则影响上传速度
""".trimIndent()
)
}
}
fun selectUploader() {

View File

@@ -76,7 +76,7 @@ fun showUploadTaskWindow() {
@Composable
fun UploadDialogCard() {
AnimatedVisibility(visible = uploadTasks.any { it.uploading }) {
AnimatedVisibility(visible = uploadTasks.isNotEmpty()) {
ElevatedCard(
modifier = Modifier
.fillMaxWidth(),
@@ -91,14 +91,26 @@ fun UploadDialogCard() {
.padding(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "${uploadTasks.filter { it.uploading }.size} 个文件正在上传中",
modifier = Modifier,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
color = colorScheme.primary
)
CircularProgressIndicator(modifier = Modifier.size(20.dp))
val uploading = uploadTasks.filter { it.uploading }.size
if (uploading > 0) {
Text(
text = "$uploading 个文件正在上传中",
modifier = Modifier,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
color = colorScheme.primary
)
CircularProgressIndicator(modifier = Modifier.size(20.dp))
} else {
val failed = uploadTasks.filter { !it.uploading }.size
Text(
text = "$failed 个文件上传失败",
modifier = Modifier,
fontSize = 20.sp,
fontWeight = FontWeight.Bold,
color = colorScheme.error
)
}
}
}
}

View File

@@ -153,10 +153,10 @@ val Home = MixNavPage(
fun tryResolveFileList(text: String): Boolean {
val textList = text.split("\n").map { it.trim() }.filter { it.isNotEmpty() }
val fileList = textList.mapNotNull { resolveMixShareInfo(it) }
if (fileList.isEmpty()){
if (fileList.isEmpty()) {
return false
}
if (fileList.size == 1){
if (fileList.size == 1) {
showFileInfoDialog(fileList.first())
return true
}

View File

@@ -8,20 +8,8 @@ import android.net.Uri
import android.os.Build
import android.provider.OpenableColumns
import android.util.Log
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Close
import androidx.compose.material3.Icon
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import com.donut.mixfile.app
import com.donut.mixfile.appScope
import com.donut.mixfile.ui.theme.colorScheme
import com.github.amr.mimetypes.MimeTypes
import io.ktor.client.request.forms.FormBuilder
import io.ktor.http.Headers
@@ -307,6 +295,8 @@ fun decompressGzip(compressed: ByteArray): String {
}
}
fun readRawFile(id: Int) = app.resources.openRawResource(id).readBytes()
fun isValidUri(uriString: String): Boolean {
try {

View File

@@ -25,7 +25,7 @@ data class FileDataLog(
val size: Long,
@JsonAdapter(TimestampAdapter::class)
val time: Date = Date(),
var category: String = "默认",
var category: String = currentCategory,
) {
init {

View File

@@ -1,8 +1,6 @@
package com.donut.mixfile
import com.donut.mixfile.server.uploaders.hidden.A2Uploader
import com.donut.mixfile.server.uploaders.hidden.sCode
import com.donut.mixfile.ui.routes.home.UploadTask
import com.donut.mixfile.util.file.encodeHex
import kotlinx.coroutines.runBlocking
import org.junit.Test