mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
player stuff
This commit is contained in:
parent
0f5de62e92
commit
3d2f00313b
7 changed files with 364 additions and 67 deletions
|
@ -21,6 +21,7 @@ android {
|
||||||
buildTypes {
|
buildTypes {
|
||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
|
debuggable true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,19 @@
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:usesCleartextTraffic="true"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
|
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|keyboard|keyboardHidden|navigation"
|
||||||
android:label="@string/app_name">
|
android:label="@string/app_name">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
|
|
@ -11,6 +11,13 @@ fun <T> LifecycleOwner.observe(liveData: LiveData<T>, action: (t: T) -> Unit) {
|
||||||
liveData.observe(this, Observer { it?.let { t -> action(t) } })
|
liveData.observe(this, Observer { it?.let { t -> action(t) } })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T> LifecycleOwner.observeDirectly(liveData: LiveData<T>, action: (t: T) -> Unit) {
|
||||||
|
liveData.observe(this, Observer { it?.let { t -> action(t) } })
|
||||||
|
val currentValue = liveData.value
|
||||||
|
if (currentValue != null)
|
||||||
|
action(currentValue)
|
||||||
|
}
|
||||||
|
|
||||||
sealed class Resource<out T> {
|
sealed class Resource<out T> {
|
||||||
data class Success<out T>(val value: T) : Resource<T>()
|
data class Success<out T>(val value: T) : Resource<T>()
|
||||||
data class Failure(
|
data class Failure(
|
||||||
|
|
|
@ -1,29 +1,55 @@
|
||||||
package com.lagradost.cloudstream3.ui.player
|
package com.lagradost.cloudstream3.ui.player
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
|
import android.content.Context.AUDIO_SERVICE
|
||||||
|
import android.content.pm.ActivityInfo
|
||||||
|
import android.database.ContentObserver
|
||||||
|
import android.media.AudioManager
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.view.View.GONE
|
||||||
|
import android.view.View.VISIBLE
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.animation.AlphaAnimation
|
import android.view.animation.AlphaAnimation
|
||||||
|
import android.widget.ProgressBar
|
||||||
|
import android.widget.Toast
|
||||||
|
import android.widget.Toast.LENGTH_LONG
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature
|
import com.fasterxml.jackson.databind.DeserializationFeature
|
||||||
import com.fasterxml.jackson.databind.json.JsonMapper
|
import com.fasterxml.jackson.databind.json.JsonMapper
|
||||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||||
import com.google.android.exoplayer2.SimpleExoPlayer
|
import com.google.android.exoplayer2.*
|
||||||
|
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory
|
||||||
|
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector
|
||||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout
|
||||||
|
import com.google.android.exoplayer2.upstream.DataSource
|
||||||
|
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory
|
||||||
|
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory
|
||||||
|
import com.google.android.exoplayer2.util.MimeTypes
|
||||||
import com.lagradost.cloudstream3.LoadResponse
|
import com.lagradost.cloudstream3.LoadResponse
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
|
import com.lagradost.cloudstream3.USER_AGENT
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
import com.lagradost.cloudstream3.mvvm.observe
|
import com.lagradost.cloudstream3.mvvm.observe
|
||||||
import com.lagradost.cloudstream3.ui.result.ResultEpisode
|
import com.lagradost.cloudstream3.ui.result.ResultEpisode
|
||||||
import com.lagradost.cloudstream3.ui.result.ResultViewModel
|
import com.lagradost.cloudstream3.ui.result.ResultViewModel
|
||||||
import com.lagradost.cloudstream3.utils.DataStore
|
|
||||||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import java.io.FileDescriptor
|
import kotlinx.android.synthetic.main.fragment_player.*
|
||||||
import java.io.PrintWriter
|
import kotlinx.android.synthetic.main.player_custom_layout.*
|
||||||
|
import java.io.File
|
||||||
|
import javax.net.ssl.HttpsURLConnection
|
||||||
|
import javax.net.ssl.SSLContext
|
||||||
|
import javax.net.ssl.SSLSession
|
||||||
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
//http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4
|
||||||
const val STATE_RESUME_WINDOW = "resumeWindow"
|
const val STATE_RESUME_WINDOW = "resumeWindow"
|
||||||
const val STATE_RESUME_POSITION = "resumePosition"
|
const val STATE_RESUME_POSITION = "resumePosition"
|
||||||
const val STATE_PLAYER_FULLSCREEN = "playerFullscreen"
|
const val STATE_PLAYER_FULLSCREEN = "playerFullscreen"
|
||||||
|
@ -75,24 +101,33 @@ class PlayerFragment : Fragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun releasePlayer() {
|
private fun releasePlayer() {
|
||||||
|
val alphaAnimation = AlphaAnimation(0f, 1f)
|
||||||
|
alphaAnimation.duration = 100
|
||||||
|
alphaAnimation.fillAfter = true
|
||||||
|
loading_overlay.startAnimation(alphaAnimation)
|
||||||
|
video_go_back_holder.visibility = VISIBLE
|
||||||
if (this::exoPlayer.isInitialized) {
|
if (this::exoPlayer.isInitialized) {
|
||||||
|
isPlayerPlaying = exoPlayer.playWhenReady
|
||||||
|
playbackPosition = exoPlayer.currentPosition
|
||||||
|
currentWindow = exoPlayer.currentWindowIndex
|
||||||
exoPlayer.release()
|
exoPlayer.release()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
private class SettingsContentObserver(handler: Handler?, val activity: Activity) : ContentObserver(handler) {
|
||||||
if (this::exoPlayer.isInitialized) {
|
private val audioManager = activity.getSystemService(AUDIO_SERVICE) as? AudioManager
|
||||||
outState.putInt(STATE_RESUME_WINDOW, exoPlayer.currentWindowIndex)
|
override fun onChange(selfChange: Boolean) {
|
||||||
outState.putLong(STATE_RESUME_POSITION, exoPlayer.currentPosition)
|
val currentVolume = audioManager?.getStreamVolume(AudioManager.STREAM_MUSIC)
|
||||||
|
val maxVolume = audioManager?.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
|
||||||
|
val progressBarRight = activity.findViewById<ProgressBar>(R.id.progressBarRight)
|
||||||
|
if (currentVolume != null && maxVolume != null) {
|
||||||
|
progressBarRight?.progress = currentVolume * 100 / maxVolume
|
||||||
|
}
|
||||||
}
|
}
|
||||||
outState.putBoolean(STATE_PLAYER_FULLSCREEN, isFullscreen)
|
|
||||||
outState.putBoolean(STATE_PLAYER_PLAYING, isPlayerPlaying)
|
|
||||||
outState.putInt(RESIZE_MODE_KEY, resizeMode)
|
|
||||||
outState.putFloat(PLAYBACK_SPEED, playbackSpeed)
|
|
||||||
savePos()
|
|
||||||
super.onSaveInstanceState(outState)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private lateinit var volumeObserver: SettingsContentObserver
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance(data: PlayerData) =
|
fun newInstance(data: PlayerData) =
|
||||||
PlayerFragment().apply {
|
PlayerFragment().apply {
|
||||||
|
@ -126,16 +161,41 @@ class PlayerFragment : Fragment() {
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
|
||||||
|
if (savedInstanceState != null) {
|
||||||
|
currentWindow = savedInstanceState.getInt(STATE_RESUME_WINDOW)
|
||||||
|
playbackPosition = savedInstanceState.getLong(STATE_RESUME_POSITION)
|
||||||
|
isFullscreen = savedInstanceState.getBoolean(STATE_PLAYER_FULLSCREEN)
|
||||||
|
isPlayerPlaying = savedInstanceState.getBoolean(STATE_PLAYER_PLAYING)
|
||||||
|
resizeMode = savedInstanceState.getInt(RESIZE_MODE_KEY)
|
||||||
|
playbackSpeed = savedInstanceState.getFloat(PLAYBACK_SPEED)
|
||||||
|
}
|
||||||
|
|
||||||
resizeMode = requireContext().getKey(RESIZE_MODE_KEY, 0)!!
|
resizeMode = requireContext().getKey(RESIZE_MODE_KEY, 0)!!
|
||||||
playbackSpeed = requireContext().getKey(PLAYBACK_SPEED_KEY, 1f)!!
|
playbackSpeed = requireContext().getKey(PLAYBACK_SPEED_KEY, 1f)!!
|
||||||
|
|
||||||
|
volumeObserver = SettingsContentObserver(
|
||||||
|
Handler(
|
||||||
|
Looper.getMainLooper()
|
||||||
|
), requireActivity()
|
||||||
|
)
|
||||||
|
|
||||||
|
activity?.contentResolver
|
||||||
|
?.registerContentObserver(
|
||||||
|
android.provider.Settings.System.CONTENT_URI, true, volumeObserver
|
||||||
|
)
|
||||||
|
|
||||||
|
viewModel = ViewModelProvider(requireActivity()).get(ResultViewModel::class.java)
|
||||||
|
arguments?.getString("data")?.let {
|
||||||
|
playerData = mapper.readValue(it, PlayerData::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
observe(viewModel.episodes) { _episodes ->
|
observe(viewModel.episodes) { _episodes ->
|
||||||
episodes = _episodes
|
episodes = _episodes
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
if (playerData.episodeIndex > 0 && playerData.episodeIndex < episodes.size) {
|
if (playerData.episodeIndex > 0 && playerData.episodeIndex < episodes.size) {
|
||||||
|
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// WHAT THE FUCK DID YOU DO
|
// WHAT THE FUCK DID YOU DO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,14 +219,211 @@ class PlayerFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
println(allEpisodes)
|
println(episodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCurrentUrl(): ExtractorLink {
|
||||||
|
return ExtractorLink("",
|
||||||
|
"TEST",
|
||||||
|
"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
|
||||||
|
"",
|
||||||
|
0)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStart() {
|
||||||
|
super.onStart()
|
||||||
|
thread {
|
||||||
|
// initPlayer()
|
||||||
|
if (player_view != null) player_view.onResume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||||
|
thread {
|
||||||
|
initPlayer()
|
||||||
|
if (player_view != null) player_view.onResume()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
// releasePlayer()
|
||||||
|
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
if (player_view != null) player_view.onPause()
|
||||||
|
releasePlayer()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStop() {
|
||||||
|
super.onStop()
|
||||||
|
if (player_view != null) player_view.onPause()
|
||||||
|
releasePlayer()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
|
if (this::exoPlayer.isInitialized) {
|
||||||
|
outState.putInt(STATE_RESUME_WINDOW, exoPlayer.currentWindowIndex)
|
||||||
|
outState.putLong(STATE_RESUME_POSITION, exoPlayer.currentPosition)
|
||||||
|
}
|
||||||
|
outState.putBoolean(STATE_PLAYER_FULLSCREEN, isFullscreen)
|
||||||
|
outState.putBoolean(STATE_PLAYER_PLAYING, isPlayerPlaying)
|
||||||
|
outState.putInt(RESIZE_MODE_KEY, resizeMode)
|
||||||
|
outState.putFloat(PLAYBACK_SPEED, playbackSpeed)
|
||||||
|
savePos()
|
||||||
|
super.onSaveInstanceState(outState)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var currentWindow = 0
|
||||||
|
private var playbackPosition: Long = 0
|
||||||
|
//http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4
|
||||||
|
private fun initPlayer() {
|
||||||
|
println("INIT PLAYER")
|
||||||
|
view?.setOnTouchListener { _, _ -> return@setOnTouchListener true } // VERY IMPORTANT https://stackoverflow.com/questions/28818926/prevent-clicking-on-a-button-in-an-activity-while-showing-a-fragment
|
||||||
|
thread {
|
||||||
|
val currentUrl = getCurrentUrl()
|
||||||
|
if (currentUrl == null) {
|
||||||
|
activity?.runOnUiThread {
|
||||||
|
Toast.makeText(activity, "Error getting link", LENGTH_LONG).show()
|
||||||
|
//MainActivity.popCurrentPage()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(activity)
|
||||||
|
try {
|
||||||
|
activity?.runOnUiThread {
|
||||||
|
val isOnline =
|
||||||
|
currentUrl.url.startsWith("https://") || currentUrl.url.startsWith("http://")
|
||||||
|
|
||||||
|
if (settingsManager?.getBoolean("ignore_ssl", true) == true) {
|
||||||
|
// Disables ssl check
|
||||||
|
val sslContext: SSLContext = SSLContext.getInstance("TLS")
|
||||||
|
sslContext.init(null, arrayOf(SSLTrustManager()), java.security.SecureRandom())
|
||||||
|
sslContext.createSSLEngine()
|
||||||
|
HttpsURLConnection.setDefaultHostnameVerifier { _: String, _: SSLSession ->
|
||||||
|
true
|
||||||
|
}
|
||||||
|
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.socketFactory)
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomFactory : DataSource.Factory {
|
||||||
|
override fun createDataSource(): DataSource {
|
||||||
|
return if (isOnline) {
|
||||||
|
val dataSource = DefaultHttpDataSourceFactory(USER_AGENT).createDataSource()
|
||||||
|
/*FastAniApi.currentHeaders?.forEach {
|
||||||
|
dataSource.setRequestProperty(it.key, it.value)
|
||||||
|
}*/
|
||||||
|
dataSource.setRequestProperty("Referer", currentUrl.referer)
|
||||||
|
dataSource
|
||||||
|
} else {
|
||||||
|
DefaultDataSourceFactory(requireContext(), USER_AGENT).createDataSource()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val mimeType = if (currentUrl.isM3u8) MimeTypes.APPLICATION_M3U8 else MimeTypes.APPLICATION_MP4
|
||||||
|
val _mediaItem = MediaItem.Builder()
|
||||||
|
//Replace needed for android 6.0.0 https://github.com/google/ExoPlayer/issues/5983
|
||||||
|
.setMimeType(mimeType)
|
||||||
|
|
||||||
|
if (isOnline) {
|
||||||
|
_mediaItem.setUri(currentUrl.url)
|
||||||
|
} else {
|
||||||
|
_mediaItem.setUri(Uri.fromFile(File(currentUrl.url)))
|
||||||
|
}
|
||||||
|
|
||||||
|
val mediaItem = _mediaItem.build()
|
||||||
|
val trackSelector = DefaultTrackSelector(requireContext())
|
||||||
|
// Disable subtitles
|
||||||
|
trackSelector.parameters = DefaultTrackSelector.ParametersBuilder(requireContext())
|
||||||
|
.setRendererDisabled(C.TRACK_TYPE_VIDEO, true)
|
||||||
|
.setRendererDisabled(C.TRACK_TYPE_TEXT, true)
|
||||||
|
.setDisabledTextTrackSelectionFlags(C.TRACK_TYPE_TEXT)
|
||||||
|
.clearSelectionOverrides()
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val _exoPlayer =
|
||||||
|
SimpleExoPlayer.Builder(this.requireContext())
|
||||||
|
.setTrackSelector(trackSelector)
|
||||||
|
|
||||||
|
_exoPlayer.setMediaSourceFactory(DefaultMediaSourceFactory(CustomFactory()))
|
||||||
|
exoPlayer = _exoPlayer.build().apply {
|
||||||
|
playWhenReady = isPlayerPlaying
|
||||||
|
seekTo(currentWindow, playbackPosition)
|
||||||
|
setMediaItem(mediaItem, false)
|
||||||
|
prepare()
|
||||||
|
}
|
||||||
|
|
||||||
|
val alphaAnimation = AlphaAnimation(1f, 0f)
|
||||||
|
alphaAnimation.duration = 300
|
||||||
|
alphaAnimation.fillAfter = true
|
||||||
|
loading_overlay.startAnimation(alphaAnimation)
|
||||||
|
video_go_back_holder.visibility = GONE
|
||||||
|
|
||||||
|
exoPlayer.setHandleAudioBecomingNoisy(true) // WHEN HEADPHONES ARE PLUGGED OUT https://github.com/google/ExoPlayer/issues/7288
|
||||||
|
player_view.player = exoPlayer
|
||||||
|
// Sets the speed
|
||||||
|
exoPlayer.setPlaybackParameters(PlaybackParameters(playbackSpeed!!))
|
||||||
|
player_speed_text?.text = "Speed (${playbackSpeed}x)".replace(".0x", "x")
|
||||||
|
|
||||||
|
//https://stackoverflow.com/questions/47731779/detect-pause-resume-in-exoplayer
|
||||||
|
exoPlayer.addListener(object : Player.Listener {
|
||||||
|
// @SuppressLint("NewApi")
|
||||||
|
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
|
||||||
|
// updatePIPModeActions()
|
||||||
|
if (playWhenReady && playbackState == Player.STATE_READY) {
|
||||||
|
// focusRequest?.let { activity?.requestAudioFocus(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPlayerError(error: ExoPlaybackException) {
|
||||||
|
// Lets pray this doesn't spam Toasts :)
|
||||||
|
when (error.type) {
|
||||||
|
ExoPlaybackException.TYPE_SOURCE -> {
|
||||||
|
if (currentUrl.url != "") {
|
||||||
|
Toast.makeText(
|
||||||
|
activity,
|
||||||
|
"Source error\n" + error.sourceException.message,
|
||||||
|
LENGTH_LONG
|
||||||
|
)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ExoPlaybackException.TYPE_REMOTE -> {
|
||||||
|
Toast.makeText(activity, "Remote error", LENGTH_LONG)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
ExoPlaybackException.TYPE_RENDERER -> {
|
||||||
|
Toast.makeText(
|
||||||
|
activity,
|
||||||
|
"Renderer error\n" + error.rendererException.message,
|
||||||
|
LENGTH_LONG
|
||||||
|
)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
ExoPlaybackException.TYPE_UNEXPECTED -> {
|
||||||
|
Toast.makeText(
|
||||||
|
activity,
|
||||||
|
"Unexpected player error\n" + error.unexpectedException.message,
|
||||||
|
LENGTH_LONG
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (e: java.lang.IllegalStateException) {
|
||||||
|
println("Warning: Illegal state exception in PlayerFragment")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//isLoadingNextEpisode = false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
viewModel = ViewModelProvider(requireActivity()).get(ResultViewModel::class.java)
|
|
||||||
arguments?.getString("data")?.let {
|
|
||||||
playerData = mapper.readValue(it, PlayerData::class.java)
|
|
||||||
}
|
|
||||||
return inflater.inflate(R.layout.fragment_player, container, false)
|
return inflater.inflate(R.layout.fragment_player, container, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.lagradost.cloudstream3.ui.player
|
||||||
|
|
||||||
|
import java.security.cert.X509Certificate
|
||||||
|
import javax.net.ssl.X509TrustManager
|
||||||
|
|
||||||
|
class SSLTrustManager : X509TrustManager {
|
||||||
|
override fun checkClientTrusted(p0: Array<out X509Certificate>?, p1: String?) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun checkServerTrusted(p0: Array<out X509Certificate>?, p1: String?) {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getAcceptedIssuers(): Array<X509Certificate> {
|
||||||
|
return arrayOf()
|
||||||
|
}
|
||||||
|
}
|
|
@ -106,12 +106,58 @@ class ResultFragment : Fragment() {
|
||||||
activity?.onBackPressed()
|
activity?.onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>? = activity?.let { it ->
|
||||||
|
EpisodeAdapter(
|
||||||
|
it,
|
||||||
|
ArrayList(),
|
||||||
|
result_episodes,
|
||||||
|
) { episodeClick ->
|
||||||
|
val id = episodeClick.data.id
|
||||||
|
val index = episodeClick.data.index
|
||||||
|
val buildInPlayer = true
|
||||||
|
if (buildInPlayer) {
|
||||||
|
(requireActivity() as AppCompatActivity).supportFragmentManager.beginTransaction()
|
||||||
|
.setCustomAnimations(R.anim.enter_anim,
|
||||||
|
R.anim.exit_anim,
|
||||||
|
R.anim.pop_enter,
|
||||||
|
R.anim.pop_exit)
|
||||||
|
.add(R.id.homeRoot, PlayerFragment.newInstance(PlayerData(index)))
|
||||||
|
.commit()
|
||||||
|
} else {
|
||||||
|
when (episodeClick.action) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
ACTION_PLAY_EPISODE -> {
|
||||||
|
if (allEpisodes.containsKey(id)) {
|
||||||
|
playEpisode(allEpisodes[id], index)
|
||||||
|
} else {
|
||||||
|
viewModel.loadEpisode(episodeClick.data) { res ->
|
||||||
|
if (res is Resource.Success) {
|
||||||
|
playEpisode(allEpisodes[id], index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ACTION_RELOAD_EPISODE -> viewModel.loadEpisode(episodeClick.data) { res ->
|
||||||
|
if (res is Resource.Success) {
|
||||||
|
playEpisode(allEpisodes[id], index)
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result_episodes.adapter = adapter
|
||||||
|
result_episodes.layoutManager = GridLayoutManager(context, 1)
|
||||||
|
|
||||||
observe(viewModel.allEpisodes) {
|
observe(viewModel.allEpisodes) {
|
||||||
allEpisodes = it
|
allEpisodes = it
|
||||||
}
|
}
|
||||||
|
|
||||||
observe(viewModel.episodes) { episodes ->
|
observe(viewModel.episodes) { episodes ->
|
||||||
if(result_episodes == null) return@observe
|
if(result_episodes == null || result_episodes.adapter == null) return@observe
|
||||||
(result_episodes.adapter as EpisodeAdapter).cardList = episodes
|
(result_episodes.adapter as EpisodeAdapter).cardList = episodes
|
||||||
(result_episodes.adapter as EpisodeAdapter).notifyDataSetChanged()
|
(result_episodes.adapter as EpisodeAdapter).notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
@ -203,51 +249,6 @@ activity?.startActivityForResult(vlcIntent, REQUEST_CODE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder>? = activity?.let { it ->
|
|
||||||
EpisodeAdapter(
|
|
||||||
it,
|
|
||||||
ArrayList(),
|
|
||||||
result_episodes,
|
|
||||||
) { episodeClick ->
|
|
||||||
val id = episodeClick.data.id
|
|
||||||
val index = episodeClick.data.index
|
|
||||||
val buildInPlayer = true
|
|
||||||
if (buildInPlayer) {
|
|
||||||
(requireActivity() as AppCompatActivity).supportFragmentManager.beginTransaction()
|
|
||||||
.setCustomAnimations(R.anim.enter_anim,
|
|
||||||
R.anim.exit_anim,
|
|
||||||
R.anim.pop_enter,
|
|
||||||
R.anim.pop_exit)
|
|
||||||
.add(R.id.homeRoot, PlayerFragment.newInstance(PlayerData(index)))
|
|
||||||
.commit()
|
|
||||||
} else {
|
|
||||||
when (episodeClick.action) {
|
|
||||||
|
|
||||||
/*
|
|
||||||
ACTION_PLAY_EPISODE -> {
|
|
||||||
if (allEpisodes.containsKey(id)) {
|
|
||||||
playEpisode(allEpisodes[id], index)
|
|
||||||
} else {
|
|
||||||
viewModel.loadEpisode(episodeClick.data) { res ->
|
|
||||||
if (res is Resource.Success) {
|
|
||||||
playEpisode(allEpisodes[id], index)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ACTION_RELOAD_EPISODE -> viewModel.loadEpisode(episodeClick.data) { res ->
|
|
||||||
if (res is Resource.Success) {
|
|
||||||
playEpisode(allEpisodes[id], index)
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result_episodes.adapter = adapter
|
|
||||||
result_episodes.layoutManager = GridLayoutManager(context, 1)
|
|
||||||
|
|
||||||
if (d.plot != null) {
|
if (d.plot != null) {
|
||||||
var syno = d.plot!!
|
var syno = d.plot!!
|
||||||
if (syno.length > MAX_SYNO_LENGH) {
|
if (syno.length > MAX_SYNO_LENGH) {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import android.view.ViewGroup
|
||||||
import android.widget.ImageView
|
import android.widget.ImageView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
@ -21,6 +22,8 @@ import com.lagradost.cloudstream3.UIHelper.fixPaddingStatusbar
|
||||||
import com.lagradost.cloudstream3.UIHelper.getGridIsCompact
|
import com.lagradost.cloudstream3.UIHelper.getGridIsCompact
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
import com.lagradost.cloudstream3.mvvm.Resource
|
||||||
import com.lagradost.cloudstream3.mvvm.observe
|
import com.lagradost.cloudstream3.mvvm.observe
|
||||||
|
import com.lagradost.cloudstream3.ui.player.PlayerData
|
||||||
|
import com.lagradost.cloudstream3.ui.player.PlayerFragment
|
||||||
import kotlinx.android.synthetic.main.fragment_search.*
|
import kotlinx.android.synthetic.main.fragment_search.*
|
||||||
|
|
||||||
class SearchFragment : Fragment() {
|
class SearchFragment : Fragment() {
|
||||||
|
@ -126,5 +129,14 @@ class SearchFragment : Fragment() {
|
||||||
search_exit_icon.alpha = 1f
|
search_exit_icon.alpha = 1f
|
||||||
search_loading_bar.alpha = 0f
|
search_loading_bar.alpha = 0f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
(requireActivity() as AppCompatActivity).supportFragmentManager.beginTransaction()
|
||||||
|
.setCustomAnimations(R.anim.enter_anim,
|
||||||
|
R.anim.exit_anim,
|
||||||
|
R.anim.pop_enter,
|
||||||
|
R.anim.pop_exit)
|
||||||
|
.add(R.id.homeRoot, PlayerFragment.newInstance(PlayerData(0)))
|
||||||
|
.commit()
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue