|
@@ -1,35 +1,79 @@
|
|
|
package io.legado.app.help.exoplayer
|
|
package io.legado.app.help.exoplayer
|
|
|
|
|
|
|
|
|
|
+import android.annotation.SuppressLint
|
|
|
|
|
+import android.content.Context
|
|
|
import android.net.Uri
|
|
import android.net.Uri
|
|
|
-import com.google.android.exoplayer2.MediaItem
|
|
|
|
|
-import com.google.android.exoplayer2.database.StandaloneDatabaseProvider
|
|
|
|
|
-import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSource
|
|
|
|
|
-import com.google.android.exoplayer2.offline.DefaultDownloaderFactory
|
|
|
|
|
-import com.google.android.exoplayer2.offline.DownloadRequest
|
|
|
|
|
-import com.google.android.exoplayer2.offline.DownloaderFactory
|
|
|
|
|
-import com.google.android.exoplayer2.source.MediaSource
|
|
|
|
|
-import com.google.android.exoplayer2.source.ProgressiveMediaSource
|
|
|
|
|
-import com.google.android.exoplayer2.upstream.DataSource
|
|
|
|
|
-import com.google.android.exoplayer2.upstream.FileDataSource
|
|
|
|
|
-import com.google.android.exoplayer2.upstream.cache.*
|
|
|
|
|
|
|
+import androidx.media3.common.MediaItem
|
|
|
|
|
+import androidx.media3.database.StandaloneDatabaseProvider
|
|
|
|
|
+import androidx.media3.datasource.DataSource
|
|
|
|
|
+import androidx.media3.datasource.FileDataSource
|
|
|
|
|
+import androidx.media3.datasource.ResolvingDataSource
|
|
|
|
|
+import androidx.media3.datasource.cache.Cache
|
|
|
|
|
+import androidx.media3.datasource.cache.CacheDataSink
|
|
|
|
|
+import androidx.media3.datasource.cache.CacheDataSource
|
|
|
|
|
+import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor
|
|
|
|
|
+import androidx.media3.datasource.cache.SimpleCache
|
|
|
|
|
+import androidx.media3.datasource.okhttp.OkHttpDataSource
|
|
|
|
|
+import androidx.media3.exoplayer.DefaultLoadControl
|
|
|
|
|
+import androidx.media3.exoplayer.ExoPlayer
|
|
|
|
|
+import androidx.media3.exoplayer.offline.DefaultDownloaderFactory
|
|
|
|
|
+import androidx.media3.exoplayer.offline.DownloadRequest
|
|
|
|
|
+import androidx.media3.exoplayer.offline.DownloaderFactory
|
|
|
|
|
+import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
|
|
|
|
+import com.google.gson.GsonBuilder
|
|
|
|
|
+import com.google.gson.reflect.TypeToken
|
|
|
import io.legado.app.help.http.okHttpClient
|
|
import io.legado.app.help.http.okHttpClient
|
|
|
import okhttp3.CacheControl
|
|
import okhttp3.CacheControl
|
|
|
import splitties.init.appCtx
|
|
import splitties.init.appCtx
|
|
|
import java.io.File
|
|
import java.io.File
|
|
|
|
|
+import java.lang.reflect.Type
|
|
|
import java.util.concurrent.TimeUnit
|
|
import java.util.concurrent.TimeUnit
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+@SuppressLint("UnsafeOptInUsageError")
|
|
|
object ExoPlayerHelper {
|
|
object ExoPlayerHelper {
|
|
|
|
|
|
|
|
- fun createMediaSource(
|
|
|
|
|
- uri: Uri,
|
|
|
|
|
- defaultRequestProperties: Map<String, String>
|
|
|
|
|
- ): MediaSource {
|
|
|
|
|
- val mediaItem = MediaItem.fromUri(uri)
|
|
|
|
|
- val mediaSourceFactory = ProgressiveMediaSource.Factory(
|
|
|
|
|
- cacheDataSourceFactory.setDefaultRequestProperties(defaultRequestProperties)
|
|
|
|
|
|
|
+ private const val SPLIT_TAG = "\uD83D\uDEA7"
|
|
|
|
|
+
|
|
|
|
|
+ private val gson by lazy {
|
|
|
|
|
+ GsonBuilder().create()
|
|
|
|
|
+ }
|
|
|
|
|
+ private val mapType by lazy {
|
|
|
|
|
+ val type: Type = object : TypeToken<Map<String?, String?>?>() {}.type
|
|
|
|
|
+ type
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+// fun createMediaSource(
|
|
|
|
|
+// uri: Uri,
|
|
|
|
|
+// defaultRequestProperties: Map<String, String>
|
|
|
|
|
+// ): MediaSource {
|
|
|
|
|
+// val mediaItem = MediaItem.fromUri(uri)
|
|
|
|
|
+// val mediaSourceFactory = ProgressiveMediaSource.Factory(
|
|
|
|
|
+// cacheDataSourceFactory.setDefaultRequestProperties(defaultRequestProperties)
|
|
|
|
|
+// )
|
|
|
|
|
+// return mediaSourceFactory.createMediaSource(mediaItem)
|
|
|
|
|
+// }
|
|
|
|
|
+
|
|
|
|
|
+ fun createMediaItem(url: String, headers: Map<String, String>): MediaItem {
|
|
|
|
|
+ val formatUrl = url + SPLIT_TAG + gson.toJson(headers, mapType)
|
|
|
|
|
+ return MediaItem.Builder().setUri(formatUrl).build()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ fun createExoPlayer(context: Context): ExoPlayer {
|
|
|
|
|
+ return ExoPlayer.Builder(context).setLoadControl(
|
|
|
|
|
+ DefaultLoadControl.Builder().setBufferDurationsMs(
|
|
|
|
|
+ DefaultLoadControl.DEFAULT_MIN_BUFFER_MS,
|
|
|
|
|
+ DefaultLoadControl.DEFAULT_MAX_BUFFER_MS,
|
|
|
|
|
+ DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS / 10,
|
|
|
|
|
+ DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS / 10
|
|
|
|
|
+ ).build()
|
|
|
|
|
+
|
|
|
)
|
|
)
|
|
|
- return mediaSourceFactory.createMediaSource(mediaItem)
|
|
|
|
|
|
|
+ .setMediaSourceFactory(
|
|
|
|
|
+ DefaultMediaSourceFactory(context)
|
|
|
|
|
+ .setDataSourceFactory(resolvingDataSource)
|
|
|
|
|
+ .setLiveTargetOffsetMs(5000)
|
|
|
|
|
+ ).build()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -62,6 +106,31 @@ object ExoPlayerHelper {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+ private val resolvingDataSource: ResolvingDataSource.Factory by lazy {
|
|
|
|
|
+ ResolvingDataSource.Factory(
|
|
|
|
|
+ cacheDataSourceFactory
|
|
|
|
|
+ ) {
|
|
|
|
|
+ var res = it
|
|
|
|
|
+
|
|
|
|
|
+ if (it.uri.toString().contains(SPLIT_TAG)) {
|
|
|
|
|
+ val urls = it.uri.toString().split(SPLIT_TAG)
|
|
|
|
|
+ val url = urls[0]
|
|
|
|
|
+ res = res.withUri(Uri.parse(url))
|
|
|
|
|
+ try {
|
|
|
|
|
+ val headers: Map<String, String> = gson.fromJson(urls[1], mapType)
|
|
|
|
|
+ res = res.withAdditionalHeaders(headers)
|
|
|
|
|
+ } catch (_: Exception) {
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ res
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 支持缓存的DataSource.Factory
|
|
* 支持缓存的DataSource.Factory
|
|
|
*/
|
|
*/
|