mirror of
https://github.com/InvertGeek/MixFile.git
synced 2026-06-03 10:02:07 +08:00
2.0.9.1
This commit is contained in:
@@ -17,8 +17,8 @@ android {
|
||||
applicationId = "com.donut.mixfile"
|
||||
minSdk = 26
|
||||
targetSdk = 36
|
||||
versionCode = 155
|
||||
versionName = "2.0.9"
|
||||
versionCode = 157
|
||||
versionName = "2.0.9.1"
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables {
|
||||
@@ -69,6 +69,8 @@ android {
|
||||
|
||||
|
||||
dependencies {
|
||||
// 引用 libs 目录下的所有 aar
|
||||
implementation(fileTree(mapOf("dir" to "libs", "include" to listOf("*.aar"))))
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")
|
||||
implementation("com.github.InvertGeek:mixfile-core:2.0.8")
|
||||
implementation("androidx.compose.material:material-icons-extended:1.7.8")
|
||||
|
||||
BIN
app/libs/media3-ffmpeg-decoder-1.9.0+1.aar
Normal file
BIN
app/libs/media3-ffmpeg-decoder-1.9.0+1.aar
Normal file
Binary file not shown.
@@ -17,6 +17,7 @@
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:extractNativeLibs="true"
|
||||
android:label="@string/app_name"
|
||||
android:networkSecurityConfig="@xml/network_config"
|
||||
android:roundIcon="@mipmap/ic_launcher"
|
||||
|
||||
@@ -169,7 +169,7 @@ fun BottomControl(
|
||||
onClick = {
|
||||
MixDialogBuilder(
|
||||
"选集",
|
||||
scheme = playerColorScheme
|
||||
colorScheme = playerColorScheme
|
||||
).apply {
|
||||
val indexMap =
|
||||
videos.mapIndexed { index, uri -> index to uri }
|
||||
@@ -206,7 +206,7 @@ fun BottomControl(
|
||||
onClick = {
|
||||
MixDialogBuilder(
|
||||
"播放速度",
|
||||
scheme = playerColorScheme
|
||||
colorScheme = playerColorScheme
|
||||
).apply {
|
||||
setContent {
|
||||
SingleSelectItemList(
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.donut.mixfile.activity.video.player
|
||||
|
||||
import android.net.Uri
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.Box
|
||||
@@ -26,13 +27,21 @@ import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import androidx.media3.common.MediaItem
|
||||
import androidx.media3.common.PlaybackException
|
||||
import androidx.media3.common.Player
|
||||
import androidx.media3.common.Player.REPEAT_MODE_ALL
|
||||
import androidx.media3.common.util.UnstableApi
|
||||
import androidx.media3.exoplayer.DefaultRenderersFactory
|
||||
import androidx.media3.exoplayer.ExoPlayer
|
||||
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
||||
import androidx.media3.extractor.DefaultExtractorsFactory
|
||||
import androidx.media3.extractor.ts.DefaultTsPayloadReaderFactory
|
||||
import androidx.media3.ui.PlayerView
|
||||
import com.donut.mixfile.activity.video.VideoHistory
|
||||
import com.donut.mixfile.activity.video.playHistory
|
||||
import com.donut.mixfile.ui.theme.mainColorScheme
|
||||
import com.donut.mixfile.util.ForceUpdateMutable
|
||||
import com.donut.mixfile.util.showErrorDialog
|
||||
import com.donut.mixfile.util.showToast
|
||||
import kotlinx.coroutines.delay
|
||||
import java.util.Locale
|
||||
@@ -56,6 +65,7 @@ val playerColorScheme
|
||||
onSecondaryContainer = mainColorScheme.primary.copy(0.8f)
|
||||
)
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
@Composable
|
||||
fun VideoPlayerScreen(
|
||||
videoUris: List<Uri>,
|
||||
@@ -64,21 +74,42 @@ fun VideoPlayerScreen(
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val player = remember {
|
||||
ExoPlayer.Builder(context).build().apply {
|
||||
setMediaItems(videoUris.map { MediaItem.fromUri(it) })
|
||||
repeatMode = REPEAT_MODE_ALL
|
||||
val cached = playHistory.firstOrNull { it.hash.contentEquals(hash) }
|
||||
if (cached != null) {
|
||||
setMediaItems(
|
||||
videoUris.map { MediaItem.fromUri(it) },
|
||||
cached.episode,
|
||||
(cached.time - 2000L).coerceAtLeast(0)
|
||||
)
|
||||
showToast("已跳转到上次播放位置", length = Toast.LENGTH_SHORT)
|
||||
}
|
||||
prepare()
|
||||
playWhenReady = true
|
||||
// 1. 创建渲染器工厂
|
||||
val renderersFactory = DefaultRenderersFactory(context).apply {
|
||||
setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER)
|
||||
|
||||
}
|
||||
|
||||
|
||||
val extractorsFactory = DefaultExtractorsFactory().apply {
|
||||
// 开启对所有可能的容器支持
|
||||
setConstantBitrateSeekingEnabled(true) // 允许对没有索引的流进行粗略进度拖动
|
||||
setTsExtractorFlags(DefaultTsPayloadReaderFactory.FLAG_ENABLE_HDMV_DTS_AUDIO_STREAMS)
|
||||
}
|
||||
|
||||
ExoPlayer.Builder(context, renderersFactory)
|
||||
.setMediaSourceFactory(DefaultMediaSourceFactory(context, extractorsFactory))
|
||||
.build()
|
||||
.apply {
|
||||
addListener(object : Player.Listener {
|
||||
override fun onPlayerError(error: PlaybackException) {
|
||||
showErrorDialog(error, "播放出错", playerColorScheme)
|
||||
}
|
||||
})
|
||||
setMediaItems(videoUris.map { MediaItem.fromUri(it) })
|
||||
repeatMode = REPEAT_MODE_ALL
|
||||
val cached = playHistory.firstOrNull { it.hash.contentEquals(hash) }
|
||||
if (cached != null) {
|
||||
setMediaItems(
|
||||
videoUris.map { MediaItem.fromUri(it) },
|
||||
cached.episode,
|
||||
(cached.time - 2000L).coerceAtLeast(0)
|
||||
)
|
||||
showToast("已跳转到上次播放位置", length = Toast.LENGTH_SHORT)
|
||||
}
|
||||
prepare()
|
||||
playWhenReady = true
|
||||
}
|
||||
}
|
||||
|
||||
var currentMediaItem by remember { mutableIntStateOf(player.currentMediaItemIndex) }
|
||||
|
||||
@@ -20,9 +20,9 @@ var CUSTOM_UPLOAD_URL by cachedMutableOf("", "CUSTOM_UPLOAD_URL")
|
||||
var CUSTOM_REFERER by cachedMutableOf("", "CUSTOM_REFERER")
|
||||
|
||||
|
||||
val UPLOADERS = listOf(A1Uploader, A2Uploader, A3Uploader, CustomUploader, JavaScriptUploader)
|
||||
val UPLOADERS = listOf(CustomUploader, JavaScriptUploader)
|
||||
|
||||
val DEFAULT_UPLOADER = A2Uploader
|
||||
val DEFAULT_UPLOADER = JavaScriptUploader
|
||||
|
||||
var currentUploader by cachedMutableOf(DEFAULT_UPLOADER.name, "current_uploader")
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class MixDialogBuilder(
|
||||
private val iconContentColor: Color? = null,
|
||||
private val titleContentColor: Color? = null,
|
||||
private val textContentColor: Color? = null,
|
||||
private val scheme: ColorScheme? = null,
|
||||
private val colorScheme: ColorScheme? = null,
|
||||
) {
|
||||
private var content = @Composable {}
|
||||
private var positiveButton = @Composable {}
|
||||
@@ -114,7 +114,7 @@ class MixDialogBuilder(
|
||||
iconContentColor,
|
||||
titleContentColor,
|
||||
textContentColor,
|
||||
scheme
|
||||
colorScheme
|
||||
)
|
||||
dialogCache[tag]?.invoke()
|
||||
dialogCache[tag] = close
|
||||
|
||||
@@ -224,8 +224,12 @@ fun showConfirmDialog(title: String, subtitle: String = "", onConfirm: () -> Uni
|
||||
|
||||
}
|
||||
|
||||
fun showErrorDialog(e: Throwable, title: String = "发生错误") {
|
||||
MixDialogBuilder(title).apply {
|
||||
fun showErrorDialog(
|
||||
e: Throwable,
|
||||
title: String = "发生错误",
|
||||
colorScheme: ColorScheme = mainColorScheme
|
||||
) {
|
||||
MixDialogBuilder(title, colorScheme = colorScheme).apply {
|
||||
setContent {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
@@ -249,4 +253,3 @@ fun showErrorDialog(e: Throwable, title: String = "发生错误") {
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user