Merge remote-tracking branch 'origin/master'

This commit is contained in:
Blatzar 2022-07-17 22:08:54 +02:00
commit e78e068214
19 changed files with 591 additions and 534 deletions

View file

@ -36,7 +36,7 @@ android {
targetSdkVersion 30 targetSdkVersion 30
versionCode 48 versionCode 48
versionName "2.10.30" versionName "2.10.31"
resValue "string", "app_version", resValue "string", "app_version",
"${defaultConfig.versionName}${versionNameSuffix ?: ""}" "${defaultConfig.versionName}${versionNameSuffix ?: ""}"

View file

@ -8,7 +8,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor
import org.jsoup.Jsoup import org.jsoup.Jsoup
class HDMovie5 : MainAPI() { class HDMovie5 : MainAPI() {
override var mainUrl = "https://hdmovie2.biz" override var mainUrl = "https://Hdmovie2.biz"
override var name = "HDMovie" override var name = "HDMovie"
override var lang = "hi" override var lang = "hi"

View file

@ -2,8 +2,11 @@ package com.lagradost.cloudstream3.movieproviders
import android.util.Log import android.util.Log
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.getCaptchaToken import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.TvType
import com.lagradost.cloudstream3.apmap
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.metaproviders.TmdbLink import com.lagradost.cloudstream3.metaproviders.TmdbLink
import com.lagradost.cloudstream3.metaproviders.TmdbProvider import com.lagradost.cloudstream3.metaproviders.TmdbProvider
import com.lagradost.cloudstream3.movieproviders.SflixProvider.Companion.extractRabbitStream import com.lagradost.cloudstream3.movieproviders.SflixProvider.Companion.extractRabbitStream
@ -15,7 +18,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor
class TwoEmbedProvider : TmdbProvider() { class TwoEmbedProvider : TmdbProvider() {
override val apiName = "2Embed" override val apiName = "2Embed"
override var name = "2Embed" override var name = "2Embed"
override var mainUrl = "https://www.2embed.to" override var mainUrl = "https://2embed.org"
override val useMetaLoadResponse = true override val useMetaLoadResponse = true
override val instantLinkLoading = false override val instantLinkLoading = false
override val supportedTypes = setOf( override val supportedTypes = setOf(
@ -43,10 +46,10 @@ class TwoEmbedProvider : TmdbProvider() {
) else listOf(mappedData.tmdbID.toString(), "tmdb") ) else listOf(mappedData.tmdbID.toString(), "tmdb")
val isMovie = mappedData.episode == null && mappedData.season == null val isMovie = mappedData.episode == null && mappedData.season == null
val embedUrl = if (isMovie) { val embedUrl = if (isMovie) {
"$mainUrl/embed/$site/movie?id=$id" "$mainUrl/embed/movie?$site=$id"
} else { } else {
val suffix = "$id&s=${mappedData.season ?: 1}&e=${mappedData.episode ?: 1}" val suffix = "$id&sea=${mappedData.season ?: 1}&epi=${mappedData.episode ?: 1}"
"$mainUrl/embed/$site/tv?id=$suffix" "$mainUrl/embed/series?$site=$suffix"
} }
val document = app.get(embedUrl).document val document = app.get(embedUrl).document

View file

@ -12,21 +12,40 @@ import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.utils.UIHelper.adjustAlpha import com.lagradost.cloudstream3.utils.UIHelper.adjustAlpha
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
import com.lagradost.cloudstream3.utils.UIHelper.toPx import com.lagradost.cloudstream3.utils.UIHelper.toPx
import java.lang.ref.WeakReference
class MyMiniControllerFragment : MiniControllerFragment() { class MyMiniControllerFragment : MiniControllerFragment() {
var currentColor: Int = 0 var currentColor: Int = 0
// I KNOW, KINDA SPAGHETTI SOLUTION, BUT IT WORKS override fun onDestroy() {
override fun onInflate(context: Context, attributeSet: AttributeSet, bundle: Bundle?) { currentColor = 0
val obtainStyledAttributes = context.obtainStyledAttributes(attributeSet, R.styleable.CustomCast, 0, 0) super.onDestroy()
if (obtainStyledAttributes.hasValue(R.styleable.CustomCast_customCastBackgroundColor)) {
currentColor = obtainStyledAttributes.getColor(R.styleable.CustomCast_customCastBackgroundColor, 0)
}
obtainStyledAttributes.recycle()
super.onInflate(context, attributeSet, bundle)
} }
// I KNOW, KINDA SPAGHETTI SOLUTION, BUT IT WORKS
override fun onInflate(context: Context, attributeSet: AttributeSet, bundle: Bundle?) {
super.onInflate(context, attributeSet, bundle)
// somehow this leaks and I really dont know why, it seams like if you go back to a fragment with this, it leaks????
if (currentColor == 0) {
WeakReference(
context.obtainStyledAttributes(
attributeSet,
R.styleable.CustomCast
)
).apply {
if (get()
?.hasValue(R.styleable.CustomCast_customCastBackgroundColor) == true
) {
currentColor =
get()
?.getColor(R.styleable.CustomCast_customCastBackgroundColor, 0) ?: 0
}
get()?.recycle()
}.clear()
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
@ -38,18 +57,24 @@ class MyMiniControllerFragment : MiniControllerFragment() {
val containerCurrent: RelativeLayout? = view.findViewById(R.id.container_current) val containerCurrent: RelativeLayout? = view.findViewById(R.id.container_current)
context?.let { ctx -> context?.let { ctx ->
progressBar?.setBackgroundColor(adjustAlpha(ctx.colorFromAttribute(R.attr.colorPrimary), 0.35f)) progressBar?.setBackgroundColor(
val params = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 2.toPx) adjustAlpha(
ctx.colorFromAttribute(R.attr.colorPrimary),
0.35f
)
)
val params = RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT,
2.toPx
)
progressBar?.layoutParams = params progressBar?.layoutParams = params
val color = currentColor
if (currentColor != 0) { if (color != 0)
containerCurrent?.setBackgroundColor(currentColor) containerCurrent?.setBackgroundColor(color)
}
} }
val child = containerAll?.getChildAt(0) val child = containerAll?.getChildAt(0)
child?.alpha = 0f // REMOVE GRADIENT child?.alpha = 0f // REMOVE GRADIENT
} catch (e: Exception) { } catch (e: Exception) {
// JUST IN CASE // JUST IN CASE
} }

View file

@ -31,12 +31,8 @@ class DownloadChildFragment : Fragment() {
override fun onDestroyView() { override fun onDestroyView() {
(download_child_list?.adapter as DownloadChildAdapter?)?.killAdapter() (download_child_list?.adapter as DownloadChildAdapter?)?.killAdapter()
super.onDestroyView()
}
override fun onDestroy() {
downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent -= it } downloadDeleteEventListener?.let { VideoDownloadManager.downloadDeleteEvent -= it }
super.onDestroy() super.onDestroyView()
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {

View file

@ -65,16 +65,12 @@ class DownloadFragment : Fragment() {
} }
override fun onDestroyView() { override fun onDestroyView() {
(download_list?.adapter as DownloadHeaderAdapter?)?.killAdapter()
super.onDestroyView()
}
override fun onDestroy() {
if (downloadDeleteEventListener != null) { if (downloadDeleteEventListener != null) {
VideoDownloadManager.downloadDeleteEvent -= downloadDeleteEventListener!! VideoDownloadManager.downloadDeleteEvent -= downloadDeleteEventListener!!
downloadDeleteEventListener = null downloadDeleteEventListener = null
} }
super.onDestroy() (download_list?.adapter as DownloadHeaderAdapter?)?.killAdapter()
super.onDestroyView()
} }
override fun onCreateView( override fun onCreateView(
@ -83,7 +79,17 @@ class DownloadFragment : Fragment() {
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View? { ): View? {
downloadsViewModel = downloadsViewModel =
ViewModelProvider(this).get(DownloadViewModel::class.java) ViewModelProvider(this)[DownloadViewModel::class.java]
return inflater.inflate(R.layout.fragment_downloads, container, false)
}
private var downloadDeleteEventListener: ((Int) -> Unit)? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
hideKeyboard()
observe(downloadsViewModel.noDownloadsText) { observe(downloadsViewModel.noDownloadsText) {
text_no_downloads.text = it text_no_downloads.text = it
} }
@ -114,16 +120,8 @@ class DownloadFragment : Fragment() {
getBytesAsText(it) getBytesAsText(it)
) )
download_app?.setLayoutWidth(it) download_app?.setLayoutWidth(it)
download_storage_appbar?.visibility = View.VISIBLE download_storage_appbar?.isVisible = it > 0
} }
return inflater.inflate(R.layout.fragment_downloads, container, false)
}
private var downloadDeleteEventListener: ((Int) -> Unit)? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
hideKeyboard()
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> = val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> =
DownloadHeaderAdapter( DownloadHeaderAdapter(

View file

@ -8,6 +8,7 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.lagradost.cloudstream3.isMovieType import com.lagradost.cloudstream3.isMovieType
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE import com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE
import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE
import com.lagradost.cloudstream3.utils.DataStore.getFolderName import com.lagradost.cloudstream3.utils.DataStore.getFolderName
@ -100,7 +101,7 @@ class DownloadViewModel : ViewModel() {
(it.child?.episode ?: 0) + (it.child?.season?.times(10000) ?: 0) (it.child?.episode ?: 0) + (it.child?.season?.times(10000) ?: 0)
} // episode sorting by episode, lowest to highest } // episode sorting by episode, lowest to highest
} }
try {
val stat = StatFs(Environment.getExternalStorageDirectory().path) val stat = StatFs(Environment.getExternalStorageDirectory().path)
val localBytesAvailable = stat.availableBytes//stat.blockSizeLong * stat.blockCountLong val localBytesAvailable = stat.availableBytes//stat.blockSizeLong * stat.blockCountLong
@ -110,6 +111,10 @@ class DownloadViewModel : ViewModel() {
_usedBytes.postValue(localTotalBytes - localBytesAvailable - localDownloadedBytes) _usedBytes.postValue(localTotalBytes - localBytesAvailable - localDownloadedBytes)
_availableBytes.postValue(localBytesAvailable) _availableBytes.postValue(localBytesAvailable)
_downloadBytes.postValue(localDownloadedBytes) _downloadBytes.postValue(localDownloadedBytes)
} catch (e : Exception) {
_downloadBytes.postValue(0)
logError(e)
}
_headerCards.postValue(visual) _headerCards.postValue(visual)
} }

View file

@ -20,8 +20,13 @@ class EasyDownloadButton : IDisposable {
val id: Int val id: Int
} }
private var _clickCallback: ((DownloadClickEvent) -> Unit)? = null
private var _imageChangeCallback: ((Pair<Int, String>) -> Unit)? = null
override fun dispose() { override fun dispose() {
try { try {
_clickCallback = null
_imageChangeCallback = null
downloadProgressEventListener?.let { VideoDownloadManager.downloadProgressEvent -= it } downloadProgressEventListener?.let { VideoDownloadManager.downloadProgressEvent -= it }
downloadStatusEventListener?.let { VideoDownloadManager.downloadStatusEvent -= it } downloadStatusEventListener?.let { VideoDownloadManager.downloadStatusEvent -= it }
} catch (e: Exception) { } catch (e: Exception) {
@ -119,6 +124,8 @@ class EasyDownloadButton : IDisposable {
clickCallback: (DownloadClickEvent) -> Unit, clickCallback: (DownloadClickEvent) -> Unit,
isTextPercentage: Boolean = false isTextPercentage: Boolean = false
) { ) {
_clickCallback = clickCallback
_imageChangeCallback = downloadImageChangeCallback
var lastState: VideoDownloadManager.DownloadType? = null var lastState: VideoDownloadManager.DownloadType? = null
var currentBytes = setupCurrentBytes ?: 0 var currentBytes = setupCurrentBytes ?: 0
var totalBytes = setupTotalBytes ?: 0 var totalBytes = setupTotalBytes ?: 0
@ -142,7 +149,7 @@ class EasyDownloadButton : IDisposable {
} else { } else {
Pair(R.drawable.netflix_download, R.string.download) Pair(R.drawable.netflix_download, R.string.download)
} }
downloadImageChangeCallback.invoke( _imageChangeCallback?.invoke(
Pair( Pair(
img.first, img.first,
downloadView.context.getString(img.second) downloadView.context.getString(img.second)
@ -223,7 +230,7 @@ class EasyDownloadButton : IDisposable {
downloadView.setOnClickListener { downloadView.setOnClickListener {
if (currentBytes <= 0) { if (currentBytes <= 0) {
clickCallback.invoke(DownloadClickEvent(DOWNLOAD_ACTION_DOWNLOAD, data)) _clickCallback?.invoke(DownloadClickEvent(DOWNLOAD_ACTION_DOWNLOAD, data))
} else { } else {
val list = arrayListOf( val list = arrayListOf(
Pair(DOWNLOAD_ACTION_PLAY_FILE, R.string.popup_play_file), Pair(DOWNLOAD_ACTION_PLAY_FILE, R.string.popup_play_file),
@ -243,7 +250,7 @@ class EasyDownloadButton : IDisposable {
it.popupMenuNoIcons( it.popupMenuNoIcons(
list list
) { ) {
clickCallback.invoke(DownloadClickEvent(itemId, data)) _clickCallback?.invoke(DownloadClickEvent(itemId, data))
} }
} }
} }

View file

@ -350,6 +350,7 @@ abstract class AbstractPlayerFragment(
resizeMode = getKey(RESIZE_MODE_KEY) ?: 0 resizeMode = getKey(RESIZE_MODE_KEY) ?: 0
resize(resizeMode, false) resize(resizeMode, false)
player.releaseCallbacks()
player.initCallbacks( player.initCallbacks(
playerUpdated = ::playerUpdated, playerUpdated = ::playerUpdated,
updateIsPlaying = ::updateIsPlaying, updateIsPlaying = ::updateIsPlaying,

View file

@ -108,6 +108,21 @@ class CS3IPlayer : IPlayer {
private var playerUpdated: ((Any?) -> Unit)? = null private var playerUpdated: ((Any?) -> Unit)? = null
private var embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)? = null private var embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)? = null
override fun releaseCallbacks() {
playerUpdated = null
updateIsPlaying = null
requestAutoFocus = null
playerError = null
playerDimensionsLoaded = null
requestedListeningPercentages = null
playerPositionChanged = null
nextEpisode = null
prevEpisode = null
subtitlesUpdates = null
embeddedSubtitlesFetched = null
requestSubtitleUpdate = null
}
override fun initCallbacks( override fun initCallbacks(
playerUpdated: (Any?) -> Unit, playerUpdated: (Any?) -> Unit,
updateIsPlaying: ((Pair<CSPlayerLoading, CSPlayerLoading>) -> Unit)?, updateIsPlaying: ((Pair<CSPlayerLoading, CSPlayerLoading>) -> Unit)?,

View file

@ -315,6 +315,8 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
override fun onDestroy() { override fun onDestroy() {
exitFullscreen() exitFullscreen()
player.release()
player.releaseCallbacks()
super.onDestroy() super.onDestroy()
} }
@ -1104,7 +1106,6 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
// init variables // init variables
setPlayBackSpeed(getKey(PLAYBACK_SPEED_KEY) ?: 1.0f) setPlayBackSpeed(getKey(PLAYBACK_SPEED_KEY) ?: 1.0f)

View file

@ -359,12 +359,12 @@ class GeneratorPlayer : FullScreenPlayer() {
} }
}) })
dialog.search_filter.setOnClickListener { dialog.search_filter.setOnClickListener { view ->
val lang639_1 = languages.map { it.ISO_639_1 } val lang639_1 = languages.map { it.ISO_639_1 }
activity?.showDialog( activity?.showDialog(
languages.map { it.languageName }, languages.map { it.languageName },
lang639_1.indexOf(currentLanguageTwoLetters), lang639_1.indexOf(currentLanguageTwoLetters),
context.getString(R.string.subs_subtitle_languages), view?.context?.getString(R.string.subs_subtitle_languages) ?: return@setOnClickListener,
true, true,
{ } { }
) { index -> ) { index ->
@ -609,7 +609,7 @@ class GeneratorPlayer : FullScreenPlayer() {
val currentPrefMedia = val currentPrefMedia =
settingsManager.getString( settingsManager.getString(
getString(R.string.subtitles_encoding_key), ctx.getString(R.string.subtitles_encoding_key),
null null
) )

View file

@ -88,6 +88,7 @@ interface IPlayer {
subtitlesUpdates: (() -> Unit)? = null, // callback from player to inform that subtitles have updated in some way subtitlesUpdates: (() -> Unit)? = null, // callback from player to inform that subtitles have updated in some way
embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)? = null, // callback from player to give all embedded subtitles embeddedSubtitlesFetched: ((List<SubtitleData>) -> Unit)? = null, // callback from player to give all embedded subtitles
) )
fun releaseCallbacks()
fun updateSubtitleStyle(style: SaveCaptionStyle) fun updateSubtitleStyle(style: SaveCaptionStyle)
fun saveData() fun saveData()

View file

@ -30,8 +30,6 @@ import androidx.core.widget.NestedScrollView
import androidx.core.widget.doOnTextChanged import androidx.core.widget.doOnTextChanged
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.discord.panels.OverlappingPanelsLayout import com.discord.panels.OverlappingPanelsLayout
import com.discord.panels.PanelsChildGestureRegionObserver import com.discord.panels.PanelsChildGestureRegionObserver
import com.google.android.gms.cast.framework.CastButtonFactory import com.google.android.gms.cast.framework.CastButtonFactory
@ -49,10 +47,8 @@ import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.mvvm.* import com.lagradost.cloudstream3.mvvm.*
import com.lagradost.cloudstream3.syncproviders.providers.Kitsu import com.lagradost.cloudstream3.syncproviders.providers.Kitsu
import com.lagradost.cloudstream3.ui.WatchType import com.lagradost.cloudstream3.ui.WatchType
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DOWNLOAD import com.lagradost.cloudstream3.ui.download.*
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick
import com.lagradost.cloudstream3.ui.download.EasyDownloadButton
import com.lagradost.cloudstream3.ui.player.CSPlayerEvent import com.lagradost.cloudstream3.ui.player.CSPlayerEvent
import com.lagradost.cloudstream3.ui.player.GeneratorPlayer import com.lagradost.cloudstream3.ui.player.GeneratorPlayer
import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator import com.lagradost.cloudstream3.ui.player.RepoLinkGenerator
@ -478,17 +474,21 @@ class ResultFragment : ResultTrailerPlayer() {
} }
override fun onDestroyView() { override fun onDestroyView() {
updateUIListener = null
(result_episodes?.adapter as EpisodeAdapter?)?.killAdapter() (result_episodes?.adapter as EpisodeAdapter?)?.killAdapter()
downloadButton?.dispose()
//somehow this still leaks and I dont know why????
// todo look at https://github.com/discord/OverlappingPanels/blob/70b4a7cf43c6771873b1e091029d332896d41a1a/sample_app/src/main/java/com/discord/sampleapp/MainActivity.kt
PanelsChildGestureRegionObserver.Provider.get().removeGestureRegionsUpdateListener(this)
result_cast_items?.let {
PanelsChildGestureRegionObserver.Provider.get().unregister(it)
}
super.onDestroyView() super.onDestroyView()
} }
override fun onDestroy() { override fun onDestroy() {
//requireActivity().viewModelStore.clear() // REMEMBER THE CLEAR //requireActivity().viewModelStore.clear() // REMEMBER THE CLEAR
downloadButton?.dispose()
updateUIListener = null
result_cast_items?.let {
PanelsChildGestureRegionObserver.Provider.get().unregister(it)
}
super.onDestroy() super.onDestroy()
} }
@ -625,6 +625,42 @@ class ResultFragment : ResultTrailerPlayer() {
} }
} }
private fun handleDownloadButton(downloadClickEvent: DownloadClickEvent) {
if (downloadClickEvent.action == DOWNLOAD_ACTION_DOWNLOAD) {
currentEpisodes?.firstOrNull()?.let { episode ->
handleAction(
EpisodeClickEvent(
ACTION_DOWNLOAD_EPISODE,
ResultEpisode(
currentHeaderName ?: return@let,
currentHeaderName,
null,
0,
null,
episode.data,
apiName,
currentId ?: return@let,
0,
0L,
0L,
null,
null,
null,
currentType ?: return@let,
currentId ?: return@let,
)
)
)
}
} else {
DownloadButtonSetup.handleDownloadClick(
activity,
currentHeaderName,
downloadClickEvent
)
}
}
private fun loadTrailer(index: Int? = null) { private fun loadTrailer(index: Int? = null) {
val isSuccess = val isSuccess =
currentTrailers.getOrNull(index ?: currentTrailerIndex)?.let { trailer -> currentTrailers.getOrNull(index ?: currentTrailerIndex)?.let { trailer ->
@ -810,109 +846,8 @@ class ResultFragment : ResultTrailerPlayer() {
viewModel.reloadEpisodes() viewModel.reloadEpisodes()
} }
@SuppressLint("SetTextI18n") var apiName: String = ""
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { private fun handleAction(episodeClick: EpisodeClickEvent): Job = main {
super.onViewCreated(view, savedInstanceState)
result_cast_items?.let {
PanelsChildGestureRegionObserver.Provider.get().register(it)
}
result_cast_items?.adapter = ActorAdaptor()
fixGrid()
result_recommendations?.spanCount = 3
result_overlapping_panels?.setStartPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
result_overlapping_panels?.setEndPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
player_open_source?.setOnClickListener {
currentTrailers.getOrNull(currentTrailerIndex)?.let {
context?.openBrowser(it.url)
}
}
updateUIListener = ::updateUI
val restart = arguments?.getBoolean(RESTART_BUNDLE) ?: false
if (restart) {
arguments?.putBoolean(RESTART_BUNDLE, false)
}
activity?.window?.decorView?.clearFocus()
hideKeyboard()
context?.updateHasTrailers()
activity?.loadCache()
activity?.fixPaddingStatusbar(result_top_bar)
//activity?.fixPaddingStatusbar(result_barstatus)
/* val backParameter = result_back.layoutParams as FrameLayout.LayoutParams
backParameter.setMargins(
backParameter.leftMargin,
backParameter.topMargin + requireContext().getStatusBarHeight(),
backParameter.rightMargin,
backParameter.bottomMargin
)
result_back.layoutParams = backParameter*/
// activity?.fixPaddingStatusbar(result_toolbar)
url = arguments?.getString(URL_BUNDLE)
val apiName = arguments?.getString(API_NAME_BUNDLE) ?: return
startAction = arguments?.getInt(START_ACTION_BUNDLE) ?: START_ACTION_NORMAL
startValue = arguments?.getInt(START_VALUE_BUNDLE)
val resumeEpisode = arguments?.getInt(EPISODE_BUNDLE)
val resumeSeason = arguments?.getInt(SEASON_BUNDLE)
syncModel.addFromUrl(url)
val api = getApiFromName(apiName)
if (media_route_button != null) {
val chromecastSupport = api.hasChromecastSupport
media_route_button?.alpha = if (chromecastSupport) 1f else 0.3f
if (!chromecastSupport) {
media_route_button?.setOnClickListener {
showToast(activity, R.string.no_chromecast_support_toast, Toast.LENGTH_LONG)
}
}
activity?.let { act ->
if (act.isCastApiAvailable()) {
try {
CastButtonFactory.setUpMediaRouteButton(act, media_route_button)
val castContext = CastContext.getSharedInstance(act.applicationContext)
media_route_button?.isGone =
castContext.castState == CastState.NO_DEVICES_AVAILABLE
castContext.addCastStateListener { state ->
media_route_button?.isGone = state == CastState.NO_DEVICES_AVAILABLE
}
} catch (e: Exception) {
logError(e)
}
}
}
}
result_scroll.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
val dy = scrollY - oldScrollY
if (dy > 0) { //check for scroll down
result_bookmark_fab?.shrink()
} else if (dy < -5) {
result_bookmark_fab?.extend()
}
if (!isFullScreenPlayer && player.getIsPlaying()) {
if (scrollY > (player_background?.height ?: scrollY)) {
player.handleEvent(CSPlayerEvent.Pause)
}
}
//result_poster_blur_holder?.translationY = -scrollY.toFloat()
})
result_back.setOnClickListener {
activity?.popCurrentPage()
}
fun handleAction(episodeClick: EpisodeClickEvent): Job = main {
if (episodeClick.action == ACTION_DOWNLOAD_EPISODE) { if (episodeClick.action == ACTION_DOWNLOAD_EPISODE) {
val isMovie = currentIsMovie ?: return@main val isMovie = currentIsMovie ?: return@main
val headerName = currentHeaderName ?: return@main val headerName = currentHeaderName ?: return@main
@ -1126,7 +1061,7 @@ class ResultFragment : ResultTrailerPlayer() {
val verifiedOptions = ArrayList<String>() val verifiedOptions = ArrayList<String>()
val verifiedOptionsValues = ArrayList<Int>() val verifiedOptionsValues = ArrayList<Int>()
val hasDownloadSupport = api.hasDownloadSupport val hasDownloadSupport = getApiFromName(apiName).hasDownloadSupport
for (i in options.indices) { for (i in options.indices) {
val opv = optionsValues[i] val opv = optionsValues[i]
@ -1309,7 +1244,106 @@ class ResultFragment : ResultTrailerPlayer() {
} }
} }
val adapter: RecyclerView.Adapter<RecyclerView.ViewHolder> = @SuppressLint("SetTextI18n")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
result_cast_items?.let {
PanelsChildGestureRegionObserver.Provider.get().register(it)
}
//result_cast_items?.adapter = ActorAdaptor()
fixGrid()
result_recommendations?.spanCount = 3
result_overlapping_panels?.setStartPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
result_overlapping_panels?.setEndPanelLockState(OverlappingPanelsLayout.LockState.CLOSE)
player_open_source?.setOnClickListener {
currentTrailers.getOrNull(currentTrailerIndex)?.let {
context?.openBrowser(it.url)
}
}
updateUIListener = ::updateUI
val restart = arguments?.getBoolean(RESTART_BUNDLE) ?: false
if (restart) {
arguments?.putBoolean(RESTART_BUNDLE, false)
}
activity?.window?.decorView?.clearFocus()
hideKeyboard()
context?.updateHasTrailers()
activity?.loadCache()
activity?.fixPaddingStatusbar(result_top_bar)
//activity?.fixPaddingStatusbar(result_barstatus)
/* val backParameter = result_back.layoutParams as FrameLayout.LayoutParams
backParameter.setMargins(
backParameter.leftMargin,
backParameter.topMargin + requireContext().getStatusBarHeight(),
backParameter.rightMargin,
backParameter.bottomMargin
)
result_back.layoutParams = backParameter*/
// activity?.fixPaddingStatusbar(result_toolbar)
url = arguments?.getString(URL_BUNDLE)
apiName = arguments?.getString(API_NAME_BUNDLE) ?: return
startAction = arguments?.getInt(START_ACTION_BUNDLE) ?: START_ACTION_NORMAL
startValue = arguments?.getInt(START_VALUE_BUNDLE)
val resumeEpisode = arguments?.getInt(EPISODE_BUNDLE)
val resumeSeason = arguments?.getInt(SEASON_BUNDLE)
syncModel.addFromUrl(url)
val api = getApiFromName(apiName)
if (media_route_button != null) {
val chromecastSupport = api.hasChromecastSupport
media_route_button?.alpha = if (chromecastSupport) 1f else 0.3f
if (!chromecastSupport) {
media_route_button?.setOnClickListener {
showToast(activity, R.string.no_chromecast_support_toast, Toast.LENGTH_LONG)
}
}
activity?.let { act ->
if (act.isCastApiAvailable()) {
try {
CastButtonFactory.setUpMediaRouteButton(act, media_route_button)
val castContext = CastContext.getSharedInstance(act.applicationContext)
media_route_button?.isGone =
castContext.castState == CastState.NO_DEVICES_AVAILABLE
// this shit leaks for some reason
//castContext.addCastStateListener { state ->
// media_route_button?.isGone = state == CastState.NO_DEVICES_AVAILABLE
//}
} catch (e: Exception) {
logError(e)
}
}
}
}
result_scroll.setOnScrollChangeListener(NestedScrollView.OnScrollChangeListener { _, _, scrollY, _, oldScrollY ->
val dy = scrollY - oldScrollY
if (dy > 0) { //check for scroll down
result_bookmark_fab?.shrink()
} else if (dy < -5) {
result_bookmark_fab?.extend()
}
if (!isFullScreenPlayer && player.getIsPlaying()) {
if (scrollY > (player_background?.height ?: scrollY)) {
player.handleEvent(CSPlayerEvent.Pause)
}
}
//result_poster_blur_holder?.translationY = -scrollY.toFloat()
})
result_back.setOnClickListener {
activity?.popCurrentPage()
}
result_episodes.adapter =
EpisodeAdapter( EpisodeAdapter(
ArrayList(), ArrayList(),
api.hasDownloadSupport, api.hasDownloadSupport,
@ -1321,9 +1355,6 @@ class ResultFragment : ResultTrailerPlayer() {
} }
) )
result_episodes.adapter = adapter
result_episodes.layoutManager = GridLayoutManager(context, 1)
result_bookmark_button.setOnClickListener { result_bookmark_button.setOnClickListener {
it.popupMenuNoIcons( it.popupMenuNoIcons(
items = WatchType.values() items = WatchType.values()
@ -1467,7 +1498,8 @@ class ResultFragment : ResultTrailerPlayer() {
} }
} }
} }
val imgAdapter = ImageAdapter(
result_mini_sync?.adapter = ImageAdapter(
R.layout.result_mini_image, R.layout.result_mini_image,
nextFocusDown = R.id.result_sync_set_score, nextFocusDown = R.id.result_sync_set_score,
clickCallback = { action -> clickCallback = { action ->
@ -1479,7 +1511,6 @@ class ResultFragment : ResultTrailerPlayer() {
} }
} }
}) })
result_mini_sync?.adapter = imgAdapter
observe(syncModel.synced) { list -> observe(syncModel.synced) { list ->
result_sync_names?.text = result_sync_names?.text =
@ -1638,7 +1669,7 @@ class ResultFragment : ResultTrailerPlayer() {
?.let { ?.let {
result_play_movie?.text = it result_play_movie?.text = it
} }
println("startAction = $startAction") //println("startAction = $startAction")
when (startAction) { when (startAction) {
START_ACTION_RESUME_LATEST -> { START_ACTION_RESUME_LATEST -> {
@ -1738,7 +1769,7 @@ class ResultFragment : ResultTrailerPlayer() {
} }
} }
result_cast_items?.setOnFocusChangeListener { v, hasFocus -> result_cast_items?.setOnFocusChangeListener { _, hasFocus ->
// Always escape focus // Always escape focus
if (hasFocus) result_bookmark_button?.requestFocus() if (hasFocus) result_bookmark_button?.requestFocus()
} }
@ -1992,6 +2023,7 @@ class ResultFragment : ResultTrailerPlayer() {
result_movie_progress_downloaded_holder?.isVisible = hasDownloadSupport result_movie_progress_downloaded_holder?.isVisible = hasDownloadSupport
if (hasDownloadSupport) { if (hasDownloadSupport) {
val localId = d.getId() val localId = d.getId()
val file = val file =
VideoDownloadManager.getDownloadFileInfoAndUpdateSettings( VideoDownloadManager.getDownloadFileInfoAndUpdateSettings(
requireContext(), requireContext(),
@ -2018,42 +2050,9 @@ class ResultFragment : ResultTrailerPlayer() {
d.rating, d.rating,
d.plot, d.plot,
System.currentTimeMillis(), System.currentTimeMillis(),
),
::handleDownloadButton
) )
) { downloadClickEvent ->
if (downloadClickEvent.action == DOWNLOAD_ACTION_DOWNLOAD) {
currentEpisodes?.firstOrNull()?.let { episode ->
handleAction(
EpisodeClickEvent(
ACTION_DOWNLOAD_EPISODE,
ResultEpisode(
d.name,
d.name,
null,
0,
null,
episode.data,
d.apiName,
localId,
0,
0L,
0L,
null,
null,
null,
d.type,
localId,
)
)
)
}
} else {
handleDownloadClick(
activity,
currentHeaderName,
downloadClickEvent
)
}
}
result_download_movie?.setOnLongClickListener { result_download_movie?.setOnLongClickListener {
val card = val card =
@ -2158,16 +2157,14 @@ class ResultFragment : ResultTrailerPlayer() {
} }
} }
val recAdapter: RecyclerView.Adapter<RecyclerView.ViewHolder>? = activity?.let { result_recommendations?.adapter =
SearchAdapter( SearchAdapter(
ArrayList(), ArrayList(),
result_recommendations, result_recommendations,
) { callback -> ) { callback ->
SearchHelper.handleSearchClickCallback(activity, callback) SearchHelper.handleSearchClickCallback(activity, callback)
} }
}
result_recommendations?.adapter = recAdapter
context?.let { ctx -> context?.let { ctx ->
result_bookmark_button?.isVisible = ctx.isTvSettings() result_bookmark_button?.isVisible = ctx.isTvSettings()

View file

@ -129,11 +129,15 @@ object UIHelper {
} }
fun Activity?.navigate(@IdRes navigation: Int, arguments: Bundle? = null) { fun Activity?.navigate(@IdRes navigation: Int, arguments: Bundle? = null) {
try {
if (this is FragmentActivity) { if (this is FragmentActivity) {
(supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as? NavHostFragment?)?.navController?.navigate( (supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as? NavHostFragment?)?.navController?.navigate(
navigation, arguments navigation, arguments
) )
} }
} catch (e : Exception) {
logError(e)
}
} }
@ColorInt @ColorInt

View file

@ -20,6 +20,7 @@
--> -->
<LinearLayout <LinearLayout
android:id="@+id/download_storage_appbar" android:id="@+id/download_storage_appbar"
tools:visibility="visible"
android:visibility="gone" android:visibility="gone"
android:layout_margin="10dp" android:layout_margin="10dp"
android:orientation="vertical" android:orientation="vertical"

View file

@ -368,6 +368,7 @@ The focus outline now settles between the poster and text.
android:layout_marginHorizontal="5dp" android:layout_marginHorizontal="5dp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView <TextView
android:padding="5dp" android:padding="5dp"
android:maxLength="1000" android:maxLength="1000"
@ -848,9 +849,10 @@ The focus outline now settles between the poster and text.
android:textColor="?attr/grayTextColor" android:textColor="?attr/grayTextColor"
android:textSize="17sp" android:textSize="17sp"
android:textStyle="normal" android:textStyle="normal"
android:text="Episode 1022 will be released in" /> tools:text="Episode 1022 will be released in" />
<TextView <TextView
android:paddingEnd="5dp"
android:paddingStart="5dp" android:paddingStart="5dp"
android:gravity="center" android:gravity="center"
android:id="@+id/result_next_airing_time" android:id="@+id/result_next_airing_time"
@ -903,6 +905,7 @@ The focus outline now settles between the poster and text.
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="0dp" android:layout_marginTop="0dp"
android:clipToPadding="false" android:clipToPadding="false"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:descendantFocusability="afterDescendants" android:descendantFocusability="afterDescendants"
android:paddingBottom="100dp" android:paddingBottom="100dp"
tools:listitem="@layout/result_episode" /> tools:listitem="@layout/result_episode" />

View file

@ -497,7 +497,7 @@
"language": "en", "language": "en",
"name": "2Embed", "name": "2Embed",
"status": 1, "status": 1,
"url": "https://www.2embed.to" "url": "https://2embed.org"
}, },
"UakinoProvider": { "UakinoProvider": {
"language": "uk", "language": "uk",

View file

@ -241,8 +241,8 @@
}, },
"TwoEmbedProvider": { "TwoEmbedProvider": {
"name": "2Embed", "name": "2Embed",
"url": "https://www.2embed.ru", "url": "https://2embed.org",
"status": 0 "status": 1
}, },
"VMoveeProvider": { "VMoveeProvider": {
"name": "VMovee", "name": "VMovee",