mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-08-06 08:10:17 +00:00
Basic chapter system working
This commit is contained in:
parent
1d18c13817
commit
d8aecd325b
14 changed files with 202 additions and 2 deletions
|
@ -31,6 +31,12 @@ let Type = {
|
||||||
RAW: 0,
|
RAW: 0,
|
||||||
HTML: 1,
|
HTML: 1,
|
||||||
MARKUP: 2
|
MARKUP: 2
|
||||||
|
},
|
||||||
|
Chapter: {
|
||||||
|
NORMAL: 0,
|
||||||
|
|
||||||
|
SKIPPABLE: 5,
|
||||||
|
SKIP: 6
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.futo.platformplayer.api.media
|
||||||
import androidx.collection.LruCache
|
import androidx.collection.LruCache
|
||||||
import com.futo.platformplayer.api.media.models.ResultCapabilities
|
import com.futo.platformplayer.api.media.models.ResultCapabilities
|
||||||
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
|
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
|
||||||
|
import com.futo.platformplayer.api.media.models.chapters.IChapter
|
||||||
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
||||||
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
||||||
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
|
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
|
||||||
|
@ -49,6 +50,7 @@ class CachedPlatformClient : IPlatformClient {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getContentChapters(url: String): List<IChapter> = _client.getContentChapters(url);
|
||||||
override fun getPlaybackTracker(url: String): IPlaybackTracker? = _client.getPlaybackTracker(url);
|
override fun getPlaybackTracker(url: String): IPlaybackTracker? = _client.getPlaybackTracker(url);
|
||||||
|
|
||||||
override fun isChannelUrl(url: String): Boolean = _client.isChannelUrl(url);
|
override fun isChannelUrl(url: String): Boolean = _client.isChannelUrl(url);
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.futo.platformplayer.api.media
|
||||||
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
|
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
|
||||||
import com.futo.platformplayer.api.media.models.ResultCapabilities
|
import com.futo.platformplayer.api.media.models.ResultCapabilities
|
||||||
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
|
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
|
||||||
|
import com.futo.platformplayer.api.media.models.chapters.IChapter
|
||||||
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
||||||
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
||||||
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
|
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
|
||||||
|
@ -100,6 +101,8 @@ interface IPlatformClient {
|
||||||
*/
|
*/
|
||||||
fun getContentDetails(url: String): IPlatformContentDetails;
|
fun getContentDetails(url: String): IPlatformContentDetails;
|
||||||
|
|
||||||
|
fun getContentChapters(url: String): List<IChapter>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the playback tracker for a piece of content
|
* Gets the playback tracker for a piece of content
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -15,7 +15,8 @@ data class PlatformClientCapabilities(
|
||||||
val hasGetSearchCapabilities: Boolean = false,
|
val hasGetSearchCapabilities: Boolean = false,
|
||||||
val hasGetChannelCapabilities: Boolean = false,
|
val hasGetChannelCapabilities: Boolean = false,
|
||||||
val hasGetLiveEvents: Boolean = false,
|
val hasGetLiveEvents: Boolean = false,
|
||||||
val hasGetLiveChatWindow: Boolean = false
|
val hasGetLiveChatWindow: Boolean = false,
|
||||||
|
val hasGetContentChapters: Boolean = false
|
||||||
) {
|
) {
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.futo.platformplayer.api.media.models.chapters
|
||||||
|
|
||||||
|
import com.futo.platformplayer.api.media.exceptions.UnknownPlatformException
|
||||||
|
import com.futo.platformplayer.api.media.models.contents.ContentType
|
||||||
|
|
||||||
|
interface IChapter {
|
||||||
|
val name: String;
|
||||||
|
val type: ChapterType;
|
||||||
|
val timeStart: Int;
|
||||||
|
val timeEnd: Int;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class ChapterType(val value: Int) {
|
||||||
|
NORMAL(0),
|
||||||
|
|
||||||
|
SKIPPABLE(5),
|
||||||
|
SKIP(6);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromInt(value: Int): ChapterType
|
||||||
|
{
|
||||||
|
val result = ChapterType.values().firstOrNull { it.value == value };
|
||||||
|
if(result == null)
|
||||||
|
throw UnknownPlatformException(value.toString());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ import com.futo.platformplayer.api.media.PlatformClientCapabilities
|
||||||
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
|
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
|
||||||
import com.futo.platformplayer.api.media.models.ResultCapabilities
|
import com.futo.platformplayer.api.media.models.ResultCapabilities
|
||||||
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
|
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
|
||||||
|
import com.futo.platformplayer.api.media.models.chapters.IChapter
|
||||||
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
||||||
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
||||||
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
|
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
|
||||||
|
@ -181,6 +182,7 @@ open class JSClient : IPlatformClient {
|
||||||
hasGetChannelCapabilities = plugin.executeBoolean("!!source.getChannelCapabilities") ?: false,
|
hasGetChannelCapabilities = plugin.executeBoolean("!!source.getChannelCapabilities") ?: false,
|
||||||
hasGetLiveEvents = plugin.executeBoolean("!!source.getLiveEvents") ?: false,
|
hasGetLiveEvents = plugin.executeBoolean("!!source.getLiveEvents") ?: false,
|
||||||
hasGetLiveChatWindow = plugin.executeBoolean("!!source.getLiveChatWindow") ?: false,
|
hasGetLiveChatWindow = plugin.executeBoolean("!!source.getLiveChatWindow") ?: false,
|
||||||
|
hasGetContentChapters = plugin.executeBoolean("!!source.getContentChapters") ?: false,
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -414,6 +416,17 @@ open class JSClient : IPlatformClient {
|
||||||
plugin.executeTyped("source.getContentDetails(${Json.encodeToString(url)})"));
|
plugin.executeTyped("source.getContentDetails(${Json.encodeToString(url)})"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JSOptional //getContentChapters = function(url, initialData)
|
||||||
|
@JSDocs(15, "source.getContentChapters(url)", "Gets chapters for content details")
|
||||||
|
@JSDocsParameter("url", "A content url (this platform)")
|
||||||
|
override fun getContentChapters(url: String): List<IChapter> = isBusyWith {
|
||||||
|
if(!capabilities.hasGetContentChapters)
|
||||||
|
return@isBusyWith listOf();
|
||||||
|
ensureEnabled();
|
||||||
|
return@isBusyWith JSChapter.fromV8(config,
|
||||||
|
plugin.executeTyped("source.getContentChapters(${Json.encodeToString(url)})"));
|
||||||
|
}
|
||||||
|
|
||||||
@JSOptional
|
@JSOptional
|
||||||
@JSDocs(15, "source.getPlaybackTracker(url)", "Gets a playback tracker for given content url")
|
@JSDocs(15, "source.getPlaybackTracker(url)", "Gets a playback tracker for given content url")
|
||||||
@JSDocsParameter("url", "A content url (this platform)")
|
@JSDocsParameter("url", "A content url (this platform)")
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.futo.platformplayer.api.media.platforms.js.models
|
||||||
|
|
||||||
|
import com.caoccao.javet.values.reference.V8ValueArray
|
||||||
|
import com.caoccao.javet.values.reference.V8ValueObject
|
||||||
|
import com.futo.platformplayer.api.media.models.chapters.ChapterType
|
||||||
|
import com.futo.platformplayer.api.media.models.chapters.IChapter
|
||||||
|
import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig
|
||||||
|
import com.futo.platformplayer.engine.IV8PluginConfig
|
||||||
|
import com.futo.platformplayer.getOrDefault
|
||||||
|
import com.futo.platformplayer.getOrThrow
|
||||||
|
|
||||||
|
class JSChapter : IChapter {
|
||||||
|
override val name: String;
|
||||||
|
override val type: ChapterType;
|
||||||
|
override val timeStart: Int;
|
||||||
|
override val timeEnd: Int;
|
||||||
|
|
||||||
|
constructor(name: String, timeStart: Int, timeEnd: Int, type: ChapterType = ChapterType.NORMAL) {
|
||||||
|
this.name = name;
|
||||||
|
this.timeStart = timeStart;
|
||||||
|
this.timeEnd = timeEnd;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromV8(config: IV8PluginConfig, obj: V8ValueObject): IChapter {
|
||||||
|
val context = "Chapter";
|
||||||
|
|
||||||
|
val name = obj.getOrThrow<String>(config,"name", context);
|
||||||
|
val type = ChapterType.fromInt(obj.getOrDefault<Int>(config, "type", context, ChapterType.NORMAL.value) ?: ChapterType.NORMAL.value);
|
||||||
|
val timeStart = obj.getOrThrow<Int>(config, "timeStart", context);
|
||||||
|
val timeEnd = obj.getOrThrow<Int>(config, "timeEnd", context);
|
||||||
|
|
||||||
|
return JSChapter(name, timeStart, timeEnd, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fromV8(config: IV8PluginConfig, arr: V8ValueArray): List<IChapter> {
|
||||||
|
return arr.keys.mapNotNull {
|
||||||
|
val obj = arr.get<V8ValueObject>(it);
|
||||||
|
return@mapNotNull fromV8(config, obj);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -949,6 +949,17 @@ class VideoDetailView : ConstraintLayout {
|
||||||
if(video is JSVideoDetails) {
|
if(video is JSVideoDetails) {
|
||||||
val me = this;
|
val me = this;
|
||||||
fragment.lifecycleScope.launch(Dispatchers.IO) {
|
fragment.lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
try {
|
||||||
|
//TODO: Implement video.getContentChapters()
|
||||||
|
val chapters = null ?: StatePlatform.instance.getContentChapters(video.url);
|
||||||
|
_player.setChapters(chapters);
|
||||||
|
}
|
||||||
|
catch(ex: Throwable) {
|
||||||
|
Logger.e(TAG, "Failed to get chapters", ex);
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
UIDialogs.toast(context, "Failed to get chapters\n" + ex.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
val stopwatch = com.futo.platformplayer.debug.Stopwatch()
|
val stopwatch = com.futo.platformplayer.debug.Stopwatch()
|
||||||
var tracker = video.getPlaybackTracker()
|
var tracker = video.getPlaybackTracker()
|
||||||
|
|
|
@ -14,6 +14,7 @@ import com.futo.platformplayer.api.media.models.FilterGroup
|
||||||
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
|
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
|
||||||
import com.futo.platformplayer.api.media.models.ResultCapabilities
|
import com.futo.platformplayer.api.media.models.ResultCapabilities
|
||||||
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
|
import com.futo.platformplayer.api.media.models.channels.IPlatformChannel
|
||||||
|
import com.futo.platformplayer.api.media.models.chapters.IChapter
|
||||||
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
||||||
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
||||||
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
|
import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails
|
||||||
|
@ -615,6 +616,14 @@ class StatePlatform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getContentChapters(url: String): List<IChapter>? {
|
||||||
|
val baseClient = getContentClientOrNull(url) ?: return null;
|
||||||
|
if (baseClient !is JSClient) {
|
||||||
|
return baseClient.getContentChapters(url);
|
||||||
|
}
|
||||||
|
val client = _trackerClientPool.getClientPooled(baseClient, 1);
|
||||||
|
return client.getContentChapters(url);
|
||||||
|
}
|
||||||
fun getPlaybackTracker(url: String): IPlaybackTracker? {
|
fun getPlaybackTracker(url: String): IPlaybackTracker? {
|
||||||
val baseClient = getContentClientOrNull(url) ?: return null;
|
val baseClient = getContentClientOrNull(url) ?: return null;
|
||||||
if (baseClient !is JSClient) {
|
if (baseClient !is JSClient) {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import android.widget.TextView
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
import androidx.constraintlayout.widget.ConstraintLayout
|
||||||
import androidx.core.view.setMargins
|
import androidx.core.view.setMargins
|
||||||
import com.futo.platformplayer.*
|
import com.futo.platformplayer.*
|
||||||
|
import com.futo.platformplayer.api.media.models.chapters.IChapter
|
||||||
import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource
|
import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource
|
||||||
import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource
|
import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource
|
||||||
import com.futo.platformplayer.constructs.Event0
|
import com.futo.platformplayer.constructs.Event0
|
||||||
|
@ -63,6 +64,7 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
||||||
private val _control_rotate_lock: ImageButton;
|
private val _control_rotate_lock: ImageButton;
|
||||||
private val _control_cast: ImageButton;
|
private val _control_cast: ImageButton;
|
||||||
private val _control_play: ImageButton;
|
private val _control_play: ImageButton;
|
||||||
|
private val _control_chapter: TextView;
|
||||||
private val _time_bar: TimeBar;
|
private val _time_bar: TimeBar;
|
||||||
|
|
||||||
private val _control_fullscreen_fullscreen: ImageButton;
|
private val _control_fullscreen_fullscreen: ImageButton;
|
||||||
|
@ -72,6 +74,7 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
||||||
private val _control_play_fullscreen: ImageButton;
|
private val _control_play_fullscreen: ImageButton;
|
||||||
private val _time_bar_fullscreen: TimeBar;
|
private val _time_bar_fullscreen: TimeBar;
|
||||||
private val _overlay_brightness: FrameLayout;
|
private val _overlay_brightness: FrameLayout;
|
||||||
|
private val _control_chapter_fullscreen: TextView;
|
||||||
|
|
||||||
private val _title_fullscreen: TextView;
|
private val _title_fullscreen: TextView;
|
||||||
private val _author_fullscreen: TextView;
|
private val _author_fullscreen: TextView;
|
||||||
|
@ -87,6 +90,9 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
||||||
var isFitMode : Boolean = false
|
var isFitMode : Boolean = false
|
||||||
private set;
|
private set;
|
||||||
|
|
||||||
|
private var _currentChapter: IChapter? = null;
|
||||||
|
|
||||||
|
|
||||||
//Events
|
//Events
|
||||||
val onMinimize = Event1<FutoVideoPlayer>();
|
val onMinimize = Event1<FutoVideoPlayer>();
|
||||||
val onVideoSettings = Event1<FutoVideoPlayer>();
|
val onVideoSettings = Event1<FutoVideoPlayer>();
|
||||||
|
@ -112,6 +118,7 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
||||||
_control_cast = videoControls.findViewById(R.id.exo_cast);
|
_control_cast = videoControls.findViewById(R.id.exo_cast);
|
||||||
_control_play = videoControls.findViewById(com.google.android.exoplayer2.ui.R.id.exo_play);
|
_control_play = videoControls.findViewById(com.google.android.exoplayer2.ui.R.id.exo_play);
|
||||||
_time_bar = videoControls.findViewById(com.google.android.exoplayer2.ui.R.id.exo_progress);
|
_time_bar = videoControls.findViewById(com.google.android.exoplayer2.ui.R.id.exo_progress);
|
||||||
|
_control_chapter = videoControls.findViewById(R.id.text_chapter_current);
|
||||||
|
|
||||||
_videoControls_fullscreen = findViewById(R.id.video_player_controller_fullscreen);
|
_videoControls_fullscreen = findViewById(R.id.video_player_controller_fullscreen);
|
||||||
_control_fullscreen_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_fullscreen);
|
_control_fullscreen_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_fullscreen);
|
||||||
|
@ -119,6 +126,7 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
||||||
_control_videosettings_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_settings);
|
_control_videosettings_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_settings);
|
||||||
_control_rotate_lock_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_rotate_lock);
|
_control_rotate_lock_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_rotate_lock);
|
||||||
_control_play_fullscreen = videoControls.findViewById(com.google.android.exoplayer2.ui.R.id.exo_play);
|
_control_play_fullscreen = videoControls.findViewById(com.google.android.exoplayer2.ui.R.id.exo_play);
|
||||||
|
_control_chapter_fullscreen = _videoControls_fullscreen.findViewById(R.id.text_chapter_current);
|
||||||
_time_bar_fullscreen = _videoControls_fullscreen.findViewById(com.google.android.exoplayer2.ui.R.id.exo_progress);
|
_time_bar_fullscreen = _videoControls_fullscreen.findViewById(com.google.android.exoplayer2.ui.R.id.exo_progress);
|
||||||
|
|
||||||
_overlay_brightness = findViewById(R.id.overlay_brightness);
|
_overlay_brightness = findViewById(R.id.overlay_brightness);
|
||||||
|
@ -218,8 +226,25 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
||||||
updateRotateLock();
|
updateRotateLock();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var lastPos = 0L;
|
||||||
videoControls.setProgressUpdateListener { position, bufferedPosition ->
|
videoControls.setProgressUpdateListener { position, bufferedPosition ->
|
||||||
onTimeBarChanged.emit(position, bufferedPosition);
|
onTimeBarChanged.emit(position, bufferedPosition);
|
||||||
|
|
||||||
|
val delta = position - lastPos;
|
||||||
|
if(delta > 1000 || delta < 0) {
|
||||||
|
lastPos = position;
|
||||||
|
val currentChapter = getCurrentChapter(position)
|
||||||
|
if(_currentChapter != currentChapter) {
|
||||||
|
_currentChapter = currentChapter;
|
||||||
|
if (currentChapter != null) {
|
||||||
|
_control_chapter.text = " • " + currentChapter.name;
|
||||||
|
_control_chapter_fullscreen.text = " • " + currentChapter.name;
|
||||||
|
} else {
|
||||||
|
_control_chapter.text = "";
|
||||||
|
_control_chapter_fullscreen.text = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isInEditMode) {
|
if(!isInEditMode) {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.widget.RelativeLayout
|
import android.widget.RelativeLayout
|
||||||
|
import com.futo.platformplayer.api.media.models.chapters.IChapter
|
||||||
import com.futo.platformplayer.logging.Logger
|
import com.futo.platformplayer.logging.Logger
|
||||||
import com.futo.platformplayer.api.media.models.streams.VideoMuxedSourceDescriptor
|
import com.futo.platformplayer.api.media.models.streams.VideoMuxedSourceDescriptor
|
||||||
import com.futo.platformplayer.helpers.VideoHelper
|
import com.futo.platformplayer.helpers.VideoHelper
|
||||||
|
@ -53,6 +54,8 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
|
||||||
private var _shouldPlaybackRestartOnConnectivity: Boolean = false;
|
private var _shouldPlaybackRestartOnConnectivity: Boolean = false;
|
||||||
private val _referenceObject = Object();
|
private val _referenceObject = Object();
|
||||||
|
|
||||||
|
private var _chapters: List<IChapter>? = null;
|
||||||
|
|
||||||
var exoPlayer: PlayerManager? = null
|
var exoPlayer: PlayerManager? = null
|
||||||
private set;
|
private set;
|
||||||
val exoPlayerStateName: String;
|
val exoPlayerStateName: String;
|
||||||
|
@ -208,6 +211,16 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setChapters(chapters: List<IChapter>?) {
|
||||||
|
_chapters = chapters;
|
||||||
|
}
|
||||||
|
fun getChapters(): List<IChapter> {
|
||||||
|
return _chapters?.let { it.toList() } ?: listOf();
|
||||||
|
}
|
||||||
|
fun getCurrentChapter(pos: Long): IChapter? {
|
||||||
|
return _chapters?.let { chaps -> chaps.find { pos / 1000 > it.timeStart && pos / 1000 < it.timeEnd } };
|
||||||
|
}
|
||||||
|
|
||||||
fun setSource(videoSource: IVideoSource?, audioSource: IAudioSource? = null, play: Boolean = false, keepSubtitles: Boolean = false) {
|
fun setSource(videoSource: IVideoSource?, audioSource: IAudioSource? = null, play: Boolean = false, keepSubtitles: Boolean = false) {
|
||||||
swapSources(videoSource, audioSource,false, play, keepSubtitles);
|
swapSources(videoSource, audioSource,false, play, keepSubtitles);
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,27 @@
|
||||||
app:layout_constraintLeft_toRightOf="@id/text_divider"
|
app:layout_constraintLeft_toRightOf="@id/text_divider"
|
||||||
app:layout_constraintTop_toTopOf="@id/exo_position"
|
app:layout_constraintTop_toTopOf="@id/exo_position"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/exo_position"/>
|
app:layout_constraintBottom_toBottomOf="@id/exo_position"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_chapter_current"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
android:layout_marginTop="-2dp"
|
||||||
|
android:paddingRight="10dp"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:gravity="left"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/exo_duration"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/exo_duration"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/exo_duration"
|
||||||
|
app:layout_constraintRight_toLeftOf="@id/exo_fullscreen"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="">
|
||||||
|
|
||||||
|
</TextView>
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.SubtitleView
|
<com.google.android.exoplayer2.ui.SubtitleView
|
||||||
android:id="@id/exo_subtitles"
|
android:id="@id/exo_subtitles"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -159,6 +159,26 @@
|
||||||
app:layout_constraintTop_toTopOf="@id/exo_position"
|
app:layout_constraintTop_toTopOf="@id/exo_position"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/exo_position"/>
|
app:layout_constraintBottom_toBottomOf="@id/exo_position"/>
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/text_chapter_current"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
android:paddingRight="10dp"
|
||||||
|
android:layout_marginTop="-2dp"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:gravity="left"
|
||||||
|
app:layout_constraintLeft_toRightOf="@id/exo_duration"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/exo_duration"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/exo_duration"
|
||||||
|
app:layout_constraintRight_toLeftOf="@id/exo_fullscreen"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="">
|
||||||
|
|
||||||
|
</TextView>
|
||||||
|
|
||||||
<com.google.android.exoplayer2.ui.DefaultTimeBar
|
<com.google.android.exoplayer2.ui.DefaultTimeBar
|
||||||
android:id="@id/exo_progress"
|
android:id="@id/exo_progress"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit a1d432865ef87cc4860be998a02ba95f60ccfcd8
|
Subproject commit 5011bfcddb084007b938e6276b11f63e940006eb
|
Loading…
Add table
Add a link
Reference in a new issue