add yt test video
This commit is contained in:
parent
edc720590c
commit
2fee9e59f6
|
@ -38,7 +38,13 @@ data class StreamVariant(
|
||||||
val streamType: StreamType,
|
val streamType: StreamType,
|
||||||
val language: String?,
|
val language: String?,
|
||||||
val streamVariantIdentifier: String
|
val streamVariantIdentifier: String
|
||||||
)
|
) {
|
||||||
|
override fun equals(other: Any?) =
|
||||||
|
other is StreamVariant
|
||||||
|
&& other.streamType == streamType
|
||||||
|
&& other.language == language
|
||||||
|
&& other.streamVariantIdentifier == streamVariantIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
data class RepoMetaInfo(
|
data class RepoMetaInfo(
|
||||||
val canHandleTimestampedLinks: Boolean,
|
val canHandleTimestampedLinks: Boolean,
|
||||||
|
@ -52,7 +58,7 @@ data class Stream(
|
||||||
|
|
||||||
interface MediaRepository {
|
interface MediaRepository {
|
||||||
|
|
||||||
fun getRepoInfo() : RepoMetaInfo
|
fun getRepoInfo(): RepoMetaInfo
|
||||||
|
|
||||||
suspend fun getMetaInfo(item: String): MediaMetadata
|
suspend fun getMetaInfo(item: String): MediaMetadata
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ enum class PlayMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class RepeatMode {
|
enum class RepeatMode {
|
||||||
DONT_REPEAT,
|
DO_NOT_REPEAT,
|
||||||
REPEAT_ALL,
|
REPEAT_ALL,
|
||||||
REPEAT_ONE
|
REPEAT_ONE
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,14 +100,14 @@ class NewPlayerImpl(
|
||||||
|
|
||||||
override var repeatMode: RepeatMode
|
override var repeatMode: RepeatMode
|
||||||
get() = when (exoPlayer.value?.repeatMode) {
|
get() = when (exoPlayer.value?.repeatMode) {
|
||||||
Player.REPEAT_MODE_OFF -> RepeatMode.DONT_REPEAT
|
Player.REPEAT_MODE_OFF -> RepeatMode.DO_NOT_REPEAT
|
||||||
Player.REPEAT_MODE_ALL -> RepeatMode.REPEAT_ALL
|
Player.REPEAT_MODE_ALL -> RepeatMode.REPEAT_ALL
|
||||||
Player.REPEAT_MODE_ONE -> RepeatMode.REPEAT_ONE
|
Player.REPEAT_MODE_ONE -> RepeatMode.REPEAT_ONE
|
||||||
else -> throw NewPlayerException("Unknown Repeatmode option returned by ExoPlayer: ${exoPlayer.value?.repeatMode}")
|
else -> throw NewPlayerException("Unknown Repeatmode option returned by ExoPlayer: ${exoPlayer.value?.repeatMode}")
|
||||||
}
|
}
|
||||||
set(value) {
|
set(value) {
|
||||||
when (value) {
|
when (value) {
|
||||||
RepeatMode.DONT_REPEAT -> exoPlayer.value?.repeatMode = Player.REPEAT_MODE_OFF
|
RepeatMode.DO_NOT_REPEAT -> exoPlayer.value?.repeatMode = Player.REPEAT_MODE_OFF
|
||||||
RepeatMode.REPEAT_ALL -> exoPlayer.value?.repeatMode = Player.REPEAT_MODE_ALL
|
RepeatMode.REPEAT_ALL -> exoPlayer.value?.repeatMode = Player.REPEAT_MODE_ALL
|
||||||
RepeatMode.REPEAT_ONE -> exoPlayer.value?.repeatMode = Player.REPEAT_MODE_ONE
|
RepeatMode.REPEAT_ONE -> exoPlayer.value?.repeatMode = Player.REPEAT_MODE_ONE
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,7 +96,7 @@ data class VideoPlayerUIState(
|
||||||
playList = emptyList(),
|
playList = emptyList(),
|
||||||
chapters = emptyList(),
|
chapters = emptyList(),
|
||||||
shuffleEnabled = false,
|
shuffleEnabled = false,
|
||||||
repeatMode = RepeatMode.DONT_REPEAT,
|
repeatMode = RepeatMode.DO_NOT_REPEAT,
|
||||||
playListDurationInS = 0,
|
playListDurationInS = 0,
|
||||||
currentlyPlaying = null,
|
currentlyPlaying = null,
|
||||||
currentPlaylistItemIndex = 0
|
currentPlaylistItemIndex = 0
|
||||||
|
|
|
@ -415,6 +415,10 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun finishFastSeek() {
|
override fun finishFastSeek() {
|
||||||
|
if (mutableUiState.value.uiMode.controllerUiVisible) {
|
||||||
|
resetHideUiDelayedJob()
|
||||||
|
}
|
||||||
|
|
||||||
val fastSeekAmount = mutableUiState.value.fastSeekSeconds
|
val fastSeekAmount = mutableUiState.value.fastSeekSeconds
|
||||||
if (fastSeekAmount != 0) {
|
if (fastSeekAmount != 0) {
|
||||||
Log.d(TAG, "$fastSeekAmount")
|
Log.d(TAG, "$fastSeekAmount")
|
||||||
|
@ -513,9 +517,9 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
||||||
override fun cycleRepeatMode() {
|
override fun cycleRepeatMode() {
|
||||||
newPlayer?.let {
|
newPlayer?.let {
|
||||||
it.repeatMode = when (it.repeatMode) {
|
it.repeatMode = when (it.repeatMode) {
|
||||||
RepeatMode.DONT_REPEAT -> RepeatMode.REPEAT_ALL
|
RepeatMode.DO_NOT_REPEAT -> RepeatMode.REPEAT_ALL
|
||||||
RepeatMode.REPEAT_ALL -> RepeatMode.REPEAT_ONE
|
RepeatMode.REPEAT_ALL -> RepeatMode.REPEAT_ONE
|
||||||
RepeatMode.REPEAT_ONE -> RepeatMode.DONT_REPEAT
|
RepeatMode.REPEAT_ONE -> RepeatMode.DO_NOT_REPEAT
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ fun StreamSelectTopBar(
|
||||||
onClick = viewModel::cycleRepeatMode
|
onClick = viewModel::cycleRepeatMode
|
||||||
) {
|
) {
|
||||||
when (uiState.repeatMode) {
|
when (uiState.repeatMode) {
|
||||||
RepeatMode.DONT_REPEAT -> Icon(
|
RepeatMode.DO_NOT_REPEAT -> Icon(
|
||||||
imageVector = Icons.Filled.Repeat,
|
imageVector = Icons.Filled.Repeat,
|
||||||
contentDescription = stringResource(R.string.repeat_mode_no_repeat)
|
contentDescription = stringResource(R.string.repeat_mode_no_repeat)
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
package net.newpipe.newplayer.utils
|
||||||
|
|
||||||
|
import androidx.annotation.OptIn
|
||||||
|
import androidx.media3.common.MediaItem
|
||||||
|
import androidx.media3.common.Tracks
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import androidx.media3.datasource.HttpDataSource
|
||||||
|
import androidx.media3.exoplayer.dash.DashMediaSource
|
||||||
|
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
|
||||||
|
import androidx.media3.exoplayer.source.MediaSource
|
||||||
|
import androidx.media3.exoplayer.source.MergingMediaSource
|
||||||
|
import androidx.media3.exoplayer.source.ProgressiveMediaSource
|
||||||
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
|
import net.newpipe.newplayer.MediaRepository
|
||||||
|
import net.newpipe.newplayer.StreamType
|
||||||
|
import net.newpipe.newplayer.StreamVariant
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
class MediaSourceBuilder(
|
||||||
|
private val repository: MediaRepository,
|
||||||
|
private val uniqueIdToIdLookup: HashMap<Long, String>,
|
||||||
|
private val mutableErrorFlow: MutableSharedFlow<Exception>,
|
||||||
|
private val httpDataSourceFactory: HttpDataSource.Factory
|
||||||
|
) {
|
||||||
|
suspend fun buildMediaSource(item: String) {
|
||||||
|
val availableStreamVariants = repository.getAvailableStreamVariants(item)
|
||||||
|
|
||||||
|
|
||||||
|
val tracks: Tracks? = null
|
||||||
|
MergingMediaSource
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
private suspend
|
||||||
|
fun toMediaItem(item: String, streamVariant: StreamVariant): MediaItem {
|
||||||
|
val dataStream = repository.getStream(item, streamVariant)
|
||||||
|
|
||||||
|
val uniqueId = Random.nextLong()
|
||||||
|
uniqueIdToIdLookup[uniqueId] = item
|
||||||
|
val mediaItemBuilder = MediaItem.Builder()
|
||||||
|
.setMediaId(uniqueId.toString())
|
||||||
|
.setUri(dataStream.streamUri)
|
||||||
|
|
||||||
|
if (dataStream.mimeType != null) {
|
||||||
|
mediaItemBuilder.setMimeType(dataStream.mimeType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mediaItemBuilder.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
private fun toMediaSource(mediaItem: MediaItem, streamVariant: StreamVariant) =
|
||||||
|
if (streamVariant.streamType == StreamType.DYNAMIC)
|
||||||
|
DashMediaSource.Factory(httpDataSourceFactory)
|
||||||
|
.createMediaSource(mediaItem)
|
||||||
|
else
|
||||||
|
ProgressiveMediaSource.Factory(httpDataSourceFactory)
|
||||||
|
.createMediaSource(mediaItem)
|
||||||
|
|
||||||
|
|
||||||
|
private suspend fun
|
||||||
|
addMetadata(mediaItem: MediaItem, item: String): MediaItem {
|
||||||
|
val mediaItemBuilder = mediaItem.buildUpon()
|
||||||
|
|
||||||
|
try {
|
||||||
|
val metadata = repository.getMetaInfo(item)
|
||||||
|
mediaItemBuilder.setMediaMetadata(metadata)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
mutableErrorFlow.emit(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return mediaItemBuilder.build()
|
||||||
|
}
|
||||||
|
}
|
|
@ -44,7 +44,7 @@
|
||||||
<integer name="portrait_length">23</integer>
|
<integer name="portrait_length">23</integer>
|
||||||
|
|
||||||
<!-- "Intel Management Engine deep dive" a talk from 36c3 -->
|
<!-- "Intel Management Engine deep dive" a talk from 36c3 -->
|
||||||
<string name ="ccc_imu_link" translatable="false">https://media.ccc.de/v/36c3-10694-intel_management_engine_deep_dive</string>
|
<string name="ccc_imu_link" translatable="false">https://media.ccc.de/v/36c3-10694-intel_management_engine_deep_dive</string>
|
||||||
<string name="ccc_imu_1080_mp4" translatable="false">https://ftp.fau.de/cdn.media.ccc.de/congress/2019/h264-hd/36c3-10694-eng-deu-Intel_Management_Engine_deep_dive_hd.mp4</string>
|
<string name="ccc_imu_1080_mp4" translatable="false">https://ftp.fau.de/cdn.media.ccc.de/congress/2019/h264-hd/36c3-10694-eng-deu-Intel_Management_Engine_deep_dive_hd.mp4</string>
|
||||||
<string name="ccc_imu_576_mp4" translatable="false">https://ftp.fau.de/cdn.media.ccc.de/congress/2019/h264-sd/36c3-10694-eng-deu-Intel_Management_Engine_deep_dive_sd.mp4</string>
|
<string name="ccc_imu_576_mp4" translatable="false">https://ftp.fau.de/cdn.media.ccc.de/congress/2019/h264-sd/36c3-10694-eng-deu-Intel_Management_Engine_deep_dive_sd.mp4</string>
|
||||||
<string name="ccc_imu_1080_webm" translatable="false">https://ftp.fau.de/cdn.media.ccc.de/congress/2019/webm-hd/36c3-10694-eng-deu-Intel_Management_Engine_deep_dive_webm-hd.webm</string>
|
<string name="ccc_imu_1080_webm" translatable="false">https://ftp.fau.de/cdn.media.ccc.de/congress/2019/webm-hd/36c3-10694-eng-deu-Intel_Management_Engine_deep_dive_webm-hd.webm</string>
|
||||||
|
@ -64,4 +64,17 @@
|
||||||
</integer-array>
|
</integer-array>
|
||||||
<string name="ccc_imu_subtitles" translatable="false">https://cdn.media.ccc.de/congress/2019/36c3-10694-eng-deu-Intel_Management_Engine_deep_dive.en.srt</string>
|
<string name="ccc_imu_subtitles" translatable="false">https://cdn.media.ccc.de/congress/2019/36c3-10694-eng-deu-Intel_Management_Engine_deep_dive.en.srt</string>
|
||||||
<integer name="ccc_imu_length">3607</integer>
|
<integer name="ccc_imu_length">3607</integer>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- "Reverse Engineering the MOS 6502 CPU" a talk from 27c3 -->
|
||||||
|
<string name="yt_test_link" translatable="false">https://cloud.newpipe-ev.de/files/link/public/RyuyJKSUEzsHtwB</string>
|
||||||
|
<string name="yt_test_video_fullhd" translatable="false">https://cloud.newpipe-ev.de/remote.php/dav/public-files/RyuyJKSUEzsHtwB/fullhd.mp4</string>
|
||||||
|
<string name="yt_test_video_hd" translatable="false">https://cloud.newpipe-ev.de/remote.php/dav/public-files/RyuyJKSUEzsHtwB/hd.mp4</string>
|
||||||
|
<string name="yt_test_video_sd" translatable="false">https://cloud.newpipe-ev.de/remote.php/dav/public-files/RyuyJKSUEzsHtwB/sd.mp4</string>
|
||||||
|
<string name="yt_test_audio_english" translatable="false">https://cloud.newpipe-ev.de/remote.php/dav/public-files/RyuyJKSUEzsHtwB/english.m4a</string>
|
||||||
|
<string name="yt_test_audio_spanish" translatable="false">https://cloud.newpipe-ev.de/remote.php/dav/public-files/RyuyJKSUEzsHtwB/spanish.m4a</string>
|
||||||
|
<string name="yt_test_title" translatable="false">Some YT Test video</string>
|
||||||
|
<string name="yt_test_channel" translatable="false">A Channel on YT</string>
|
||||||
|
<integer name="yt_test_length">254</integer>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in New Issue