From 525a37475c868e836eb5234d8bb28ecc98bb0848 Mon Sep 17 00:00:00 2001 From: deniscerri <64997243+deniscerri@users.noreply.github.com> Date: Sat, 15 Apr 2023 14:15:55 +0200 Subject: [PATCH] more fixes --- app/build.gradle | 9 +- .../downloadcard/CutVideoBottomSheetDialog.kt | 91 ++++++++++++++++--- app/src/main/res/layout/cut_video_sheet.xml | 21 +++++ 3 files changed, 105 insertions(+), 16 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index aafed3b2..efc31e67 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,6 +14,9 @@ try { }catch(IOException ignored){} android { + namespace 'com.deniscerri.ytdlnis' + compileSdk 33 + signingConfigs { debug { storeFile file(properties["signingConfig.storeFile"]) @@ -22,11 +25,10 @@ android { keyPassword properties["signingConfig.keyPassword"] } } - compileSdkVersion 33 defaultConfig { applicationId "com.deniscerri.ytdl" - minSdkVersion 23 - targetSdkVersion 33 + minSdk 23 + targetSdk 33 versionCode project.versionCode versionName project.versionName testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -106,7 +108,6 @@ android { composeOptions { kotlinCompilerExtensionVersion composeVer } - namespace 'com.deniscerri.ytdlnis' } diff --git a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt index 7721f659..ba8f7560 100644 --- a/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt +++ b/app/src/main/java/com/deniscerri/ytdlnis/ui/downloadcard/CutVideoBottomSheetDialog.kt @@ -8,14 +8,12 @@ import android.graphics.Color import android.net.Uri import android.os.Bundle import android.util.DisplayMetrics -import android.util.Log import android.view.KeyEvent import android.view.LayoutInflater import android.view.View import android.widget.* import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.children -import androidx.core.view.forEach import androidx.lifecycle.lifecycleScope import com.deniscerri.ytdlnis.R import com.deniscerri.ytdlnis.database.models.ChapterItem @@ -23,13 +21,28 @@ import com.deniscerri.ytdlnis.database.models.DownloadItem import com.deniscerri.ytdlnis.util.FileUtil import com.deniscerri.ytdlnis.util.InfoUtil import com.deniscerri.ytdlnis.util.UiUtil +import com.google.android.exoplayer2.DefaultLoadControl +import com.google.android.exoplayer2.DefaultRenderersFactory +import com.google.android.exoplayer2.DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER import com.google.android.exoplayer2.ExoPlayer import com.google.android.exoplayer2.MediaItem.fromUri import com.google.android.exoplayer2.Player -import com.google.android.exoplayer2.source.DefaultMediaSourceFactory +import com.google.android.exoplayer2.database.DatabaseProvider +import com.google.android.exoplayer2.database.StandaloneDatabaseProvider +import com.google.android.exoplayer2.mediacodec.MediaCodecInfo +import com.google.android.exoplayer2.mediacodec.MediaCodecSelector import com.google.android.exoplayer2.source.MediaSource import com.google.android.exoplayer2.source.MergingMediaSource +import com.google.android.exoplayer2.source.ProgressiveMediaSource +import com.google.android.exoplayer2.trackselection.DefaultTrackSelector import com.google.android.exoplayer2.ui.PlayerView +import com.google.android.exoplayer2.upstream.DefaultDataSource +import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory +import com.google.android.exoplayer2.upstream.cache.CacheDataSource +import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor +import com.google.android.exoplayer2.upstream.cache.SimpleCache +import com.google.android.exoplayer2.util.MimeTypes +import com.google.android.exoplayer2.util.Util import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialogFragment import com.google.android.material.card.MaterialCardView @@ -47,6 +60,7 @@ import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.launch import kotlinx.coroutines.withContext +import java.io.File import java.lang.reflect.Type import java.util.* import kotlin.properties.Delegates @@ -60,6 +74,7 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list private lateinit var player: Player private lateinit var cutSection : ConstraintLayout + private lateinit var durationText: TextView private lateinit var progress : ProgressBar private lateinit var rangeSlider : RangeSlider private lateinit var fromTextInput : TextInputLayout @@ -78,6 +93,8 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list private lateinit var chapters: List private lateinit var selectedCuts: MutableList + private lateinit var cache: SimpleCache + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -100,7 +117,52 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list behavior.peekHeight = displayMetrics.heightPixels / 2 } - player = ExoPlayer.Builder(requireContext()).build() + val renderersFactory = DefaultRenderersFactory(requireContext().applicationContext) + .setEnableDecoderFallback(true) + .setExtensionRendererMode(EXTENSION_RENDERER_MODE_PREFER) + .setMediaCodecSelector { mimeType, requiresSecureDecoder, requiresTunnelingDecoder -> + var decoderInfos: MutableList = + MediaCodecSelector.DEFAULT + .getDecoderInfos( + mimeType, + requiresSecureDecoder, + requiresTunnelingDecoder + ) + if (MimeTypes.VIDEO_H264 == mimeType) { + // copy the list because MediaCodecSelector.DEFAULT returns an unmodifiable list + decoderInfos = ArrayList(decoderInfos) + decoderInfos.reverse() + } + decoderInfos + } + + val trackSelector = DefaultTrackSelector() + val loadControl = DefaultLoadControl() + +// Specify cache folder, my cache folder named media which is inside getCacheDir. + val cacheFolder = File(requireContext().cacheDir, "media") + +// Specify cache size and removing policies + val cacheEvictor = LeastRecentlyUsedCacheEvictor(1 * 1024 * 1024) // My cache size will be 1MB and it will automatically remove least recently used files if the size is reached out. + +// Build cache + val databaseProvider: DatabaseProvider = StandaloneDatabaseProvider(requireContext()) + cache = SimpleCache(cacheFolder, cacheEvictor, databaseProvider) + +// Build data source factory with cache enabled, if data is available in cache it will return immediately, otherwise it will open a new connection to get the data. + val defaultDataSourceFactory = DefaultDataSourceFactory( + requireContext(), + Util.getUserAgent(requireContext(), requireContext().getString(R.string.app_name)) + ) + + val cacheDataSourceFactory = CacheDataSource.Factory() + .setCache(cache) + .setUpstreamDataSourceFactory(defaultDataSourceFactory) + + player = ExoPlayer.Builder(requireContext(), renderersFactory) + .setTrackSelector(trackSelector) + .setLoadControl(loadControl) + .build() val frame = view.findViewById(R.id.frame_layout) val videoView = view.findViewById(R.id.video_view) videoView.player = player @@ -109,6 +171,8 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list //cut section cutSection = view.findViewById(R.id.cut_section) + durationText = view.findViewById(R.id.durationText) + durationText.text = "" progress = view.findViewById(R.id.progress) rangeSlider = view.findViewById(R.id.rangeSlider) fromTextInput = view.findViewById(R.id.from_textinput) @@ -154,16 +218,17 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list if (data.isEmpty()) throw Exception("No Streaming URL found!") if (data.size == 2){ - val audioSource: MediaSource = - DefaultMediaSourceFactory(requireContext()) + val audioSource : MediaSource = + ProgressiveMediaSource.Factory(cacheDataSourceFactory) .createMediaSource(fromUri(Uri.parse(data[0]))) val videoSource: MediaSource = - DefaultMediaSourceFactory(requireContext()) + ProgressiveMediaSource.Factory(cacheDataSourceFactory) .createMediaSource(fromUri(Uri.parse(data[1]))) (player as ExoPlayer).setMediaSource(MergingMediaSource(videoSource, audioSource)) }else{ player.addMediaItem(fromUri(Uri.parse(data[0]))) } + player.addMediaItem(fromUri(Uri.parse(data[0]))) progress.visibility = View.GONE populateSuggestedChapters() @@ -180,18 +245,20 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list //poll video progress lifecycleScope.launch { videoProgress(player).collect { - val startTimestamp = (rangeSlider.valueFrom.toInt() * timeSeconds) / 100 - val endTimestamp = (rangeSlider.valueTo.toInt() * timeSeconds) / 100 + val currentTime = infoUtil.formatIntegerDuration(it, Locale.US) + durationText.text = "$currentTime / ${item.duration}" + val startTimestamp = convertStringToTimestamp(fromTextInput.editText!!.text.toString()) + val endTimestamp = convertStringToTimestamp(toTextInput.editText!!.text.toString()) if (it >= endTimestamp){ + player.prepare() player.seekTo((startTimestamp * 1000).toLong()) } } } videoView.setOnClickListener { - if (player.isPlaying) player.stop() + if (player.isPlaying) player.pause() else { - player.prepare() player.play() } } @@ -479,7 +546,6 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list private fun convertStringToTimestamp(duration: String): Int { return try { val timeArray = duration.split(":") - Log.e("aa", timeArray.toString()) var timeSeconds = timeArray[timeArray.lastIndex].toInt() var times = 60 for (i in timeArray.lastIndex - 1 downTo 0) { @@ -506,6 +572,7 @@ class CutVideoBottomSheetDialog(private val item: DownloadItem, private val list private fun cleanUp(){ player.stop() + cache.release() parentFragmentManager.beginTransaction().remove(parentFragmentManager.findFragmentByTag("cutVideoSheet")!!).commit() } } diff --git a/app/src/main/res/layout/cut_video_sheet.xml b/app/src/main/res/layout/cut_video_sheet.xml index c0fccd1a..7085a4e8 100644 --- a/app/src/main/res/layout/cut_video_sheet.xml +++ b/app/src/main/res/layout/cut_video_sheet.xml @@ -39,6 +39,27 @@ app:layout_constraintTop_toTopOf="parent" /> + + +