Merge remote-tracking branch 'origin/master' into exotime

This commit is contained in:
IndusAryan 2024-01-13 13:44:47 +05:30
commit 4cc33146e3
17 changed files with 304 additions and 146 deletions

View file

@ -1374,6 +1374,35 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
} }
} }
observeNullable(viewModel.favoriteStatus) observeFavoriteStatus@{ isFavorite ->
resultviewPreviewFavorite.isVisible = isFavorite != null
if (isFavorite == null) return@observeFavoriteStatus
val drawable = if (isFavorite) {
R.drawable.ic_baseline_favorite_24
} else {
R.drawable.ic_baseline_favorite_border_24
}
resultviewPreviewFavorite.setImageResource(drawable)
}
resultviewPreviewFavorite.setOnClickListener{
viewModel.toggleFavoriteStatus(this@MainActivity) { newStatus: Boolean? ->
if (newStatus == null) return@toggleFavoriteStatus
val message = if (newStatus) {
R.string.favorite_added
} else {
R.string.favorite_removed
}
val name = (viewModel.page.value as? Resource.Success)?.value?.title
?: txt(R.string.no_data).asStringNull(this@MainActivity) ?: ""
showToast(txt(message, name), Toast.LENGTH_SHORT)
}
}
if (!isTvSettings()) // dont want this clickable on tv layout if (!isTvSettings()) // dont want this clickable on tv layout
resultviewPreviewDescription.setOnClickListener { view -> resultviewPreviewDescription.setOnClickListener { view ->
view.context?.let { ctx -> view.context?.let { ctx ->

View file

@ -18,7 +18,22 @@ open class ContentX : ExtractorApi() {
val i_source = app.get(url, referer=ext_ref).text val i_source = app.get(url, referer=ext_ref).text
val i_extract = Regex("""window\.openPlayer\('([^']+)'""").find(i_source)!!.groups[1]?.value ?: throw ErrorLoadingException("i_extract is null") val i_extract = Regex("""window\.openPlayer\('([^']+)'""").find(i_source)!!.groups[1]?.value ?: throw ErrorLoadingException("i_extract is null")
val vid_source = app.get("https://contentx.me/source2.php?v=${i_extract}", referer=ext_ref).text val sub_urls = mutableSetOf<String>()
Regex("""\"file\":\"([^\"]+)\",\"label\":\"([^\"]+)\"""").findAll(i_source).forEach {
val (sub_url, sub_lang) = it.destructured
if (sub_url in sub_urls) { return@forEach }
sub_urls.add(sub_url)
subtitleCallback.invoke(
SubtitleFile(
lang = sub_lang.replace("\\u0131", "ı").replace("\\u0130", "İ").replace("\\u00fc", "ü").replace("\\u00e7", "ç"),
url = fixUrl(sub_url.replace("\\", ""))
)
)
}
val vid_source = app.get("${mainUrl}/source2.php?v=${i_extract}", referer=ext_ref).text
val vid_extract = Regex("""file\":\"([^\"]+)""").find(vid_source)!!.groups[1]?.value ?: throw ErrorLoadingException("vid_extract is null") val vid_extract = Regex("""file\":\"([^\"]+)""").find(vid_source)!!.groups[1]?.value ?: throw ErrorLoadingException("vid_extract is null")
val m3u_link = vid_extract.replace("\\", "") val m3u_link = vid_extract.replace("\\", "")
@ -35,7 +50,7 @@ open class ContentX : ExtractorApi() {
val i_dublaj = Regex(""",\"([^']+)\",\"Türkçe""").find(i_source)!!.groups[1]?.value val i_dublaj = Regex(""",\"([^']+)\",\"Türkçe""").find(i_source)!!.groups[1]?.value
if (i_dublaj != null) { if (i_dublaj != null) {
val dublaj_source = app.get("https://contentx.me/source2.php?v=${i_dublaj}", referer=ext_ref).text val dublaj_source = app.get("${mainUrl}/source2.php?v=${i_dublaj}", referer=ext_ref).text
val dublaj_extract = Regex("""file\":\"([^\"]+)""").find(dublaj_source)!!.groups[1]?.value ?: throw ErrorLoadingException("dublaj_extract is null") val dublaj_extract = Regex("""file\":\"([^\"]+)""").find(dublaj_source)!!.groups[1]?.value ?: throw ErrorLoadingException("dublaj_extract is null")
val dublaj_link = dublaj_extract.replace("\\", "") val dublaj_link = dublaj_extract.replace("\\", "")

View file

@ -6,3 +6,8 @@ class Hotlinger : ContentX() {
override var name = "Hotlinger" override var name = "Hotlinger"
override var mainUrl = "https://hotlinger.com" override var mainUrl = "https://hotlinger.com"
} }
class FourCX : ContentX() {
override var name = "FourCX"
override var mainUrl = "https://four.contentx.me"
}

View file

@ -9,6 +9,10 @@ class StreamTapeNet : StreamTape() {
override var mainUrl = "https://streamtape.net" override var mainUrl = "https://streamtape.net"
} }
class StreamTapeXyz : StreamTape() {
override var mainUrl = "https://streamtape.xyz"
}
class ShaveTape : StreamTape(){ class ShaveTape : StreamTape(){
override var mainUrl = "https://shavetape.cash" override var mainUrl = "https://shavetape.cash"
} }

View file

@ -216,6 +216,9 @@ class HomeParentItemAdapterPreview(
viewModel.click(callback) viewModel.click(callback)
return@HomeChildItemAdapter return@HomeChildItemAdapter
} }
(callback.view.context?.getActivity() as? MainActivity)?.loadPopup(callback.card, load = false)
/*
callback.view.context?.getActivity()?.showOptionSelectStringRes( callback.view.context?.getActivity()?.showOptionSelectStringRes(
callback.view, callback.view,
callback.card.posterUrl, callback.card.posterUrl,
@ -261,6 +264,7 @@ class HomeParentItemAdapterPreview(
} }
} }
} }
*/
} }

View file

@ -20,11 +20,12 @@ import android.widget.Toast
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.core.view.allViews import androidx.core.view.allViews
import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.tabs.TabLayoutMediator
import com.lagradost.cloudstream3.APIHolder import com.lagradost.cloudstream3.APIHolder
@ -35,6 +36,7 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import com.lagradost.cloudstream3.CommonActivity import com.lagradost.cloudstream3.CommonActivity
import com.lagradost.cloudstream3.MainActivity import com.lagradost.cloudstream3.MainActivity
import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.SearchResponse
import com.lagradost.cloudstream3.databinding.FragmentLibraryBinding import com.lagradost.cloudstream3.databinding.FragmentLibraryBinding
import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.Resource
import com.lagradost.cloudstream3.mvvm.debugAssert import com.lagradost.cloudstream3.mvvm.debugAssert
@ -80,6 +82,8 @@ data class ProviderLibraryData(
class LibraryFragment : Fragment() { class LibraryFragment : Fragment() {
companion object { companion object {
val listLibraryItems = mutableListOf<SyncAPI.LibraryItem>()
fun newInstance() = LibraryFragment() fun newInstance() = LibraryFragment()
/** /**
@ -91,6 +95,7 @@ class LibraryFragment : Fragment() {
private val libraryViewModel: LibraryViewModel by activityViewModels() private val libraryViewModel: LibraryViewModel by activityViewModels()
var binding: FragmentLibraryBinding? = null var binding: FragmentLibraryBinding? = null
private var toggleRandomButton = false
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
@ -196,6 +201,25 @@ class LibraryFragment : Fragment() {
} }
} }
//Load value for toggling Random button. Hide at startup
context?.let {
val settingsManager = PreferenceManager.getDefaultSharedPreferences(it)
toggleRandomButton =
settingsManager.getBoolean(
getString(R.string.random_button_key),
false
) && !SettingsFragment.isTvSettings()
binding?.libraryRandom?.visibility = View.GONE
}
binding?.libraryRandom?.setOnClickListener {
if (listLibraryItems.isNotEmpty()) {
val listLibraryItem = listLibraryItems.random()
libraryViewModel.currentSyncApi?.syncIdName?.let {
loadLibraryItem(it, listLibraryItem.syncId,listLibraryItem)
}
}
}
/** /**
* Shows a plugin selection dialogue and saves the response * Shows a plugin selection dialogue and saves the response
@ -277,8 +301,10 @@ class LibraryFragment : Fragment() {
{ isScrollingDown: Boolean -> { isScrollingDown: Boolean ->
if (isScrollingDown) { if (isScrollingDown) {
binding?.sortFab?.shrink() binding?.sortFab?.shrink()
binding?.libraryRandom?.shrink()
} else { } else {
binding?.sortFab?.extend() binding?.sortFab?.extend()
binding?.libraryRandom?.extend()
} }
}) callback@{ searchClickCallback -> }) callback@{ searchClickCallback ->
// To prevent future accidents // To prevent future accidents
@ -303,52 +329,7 @@ class LibraryFragment : Fragment() {
} }
SEARCH_ACTION_LOAD -> { SEARCH_ACTION_LOAD -> {
// This basically first selects the individual opener and if that is default then loadLibraryItem(syncName, syncId, searchClickCallback.card)
// selects the whole list opener
val savedListSelection =
getKey<LibraryOpener>("$currentAccount/$LIBRARY_FOLDER", syncName.name)
val savedSelection = getKey<LibraryOpener>(
"$currentAccount/$LIBRARY_FOLDER",
syncId
).takeIf {
it?.openType != LibraryOpenerType.Default
} ?: savedListSelection
when (savedSelection?.openType) {
null, LibraryOpenerType.Default -> {
// Prevents opening MAL/AniList as a provider
if (APIHolder.getApiFromNameNull(searchClickCallback.card.apiName) != null) {
activity?.loadSearchResult(
searchClickCallback.card
)
} else {
// Search when no provider can open
QuickSearchFragment.pushSearch(
activity,
searchClickCallback.card.name
)
}
}
LibraryOpenerType.None -> {}
LibraryOpenerType.Provider ->
savedSelection.providerData?.apiName?.let { apiName ->
activity?.loadResult(
searchClickCallback.card.url,
apiName,
)
}
LibraryOpenerType.Browser ->
openBrowser(searchClickCallback.card.url)
LibraryOpenerType.Search -> {
QuickSearchFragment.pushSearch(
activity,
searchClickCallback.card.name
)
}
}
} }
} }
} }
@ -414,6 +395,16 @@ class LibraryFragment : Fragment() {
binding?.viewpager?.setCurrentItem(page, false) binding?.viewpager?.setCurrentItem(page, false)
} }
observe(libraryViewModel.currentPage){
if (toggleRandomButton) {
listLibraryItems.clear()
listLibraryItems.addAll(pages[it].items)
libraryRandom.isVisible = listLibraryItems.isNotEmpty()
} else {
libraryRandom.isGone = true
}
}
// Only stop loading after 300ms to hide the fade effect the viewpager produces when updating // Only stop loading after 300ms to hide the fade effect the viewpager produces when updating
// Without this there would be a flashing effect: // Without this there would be a flashing effect:
// loading -> show old viewpager -> black screen -> show new viewpager // loading -> show old viewpager -> black screen -> show new viewpager
@ -512,6 +503,62 @@ class LibraryFragment : Fragment() {
} }
})*/ })*/
} }
private fun loadLibraryItem(
syncName: SyncIdName,
syncId: String,
card: SearchResponse
) {
// This basically first selects the individual opener and if that is default then
// selects the whole list opener
val savedListSelection =
getKey<LibraryOpener>("$currentAccount/$LIBRARY_FOLDER", syncName.name)
val savedSelection = getKey<LibraryOpener>(
"$currentAccount/$LIBRARY_FOLDER",
syncId
).takeIf {
it?.openType != LibraryOpenerType.Default
} ?: savedListSelection
when (savedSelection?.openType) {
null, LibraryOpenerType.Default -> {
// Prevents opening MAL/AniList as a provider
if (APIHolder.getApiFromNameNull(card.apiName) != null) {
activity?.loadSearchResult(
card
)
} else {
// Search when no provider can open
QuickSearchFragment.pushSearch(
activity,
card.name
)
}
}
LibraryOpenerType.None -> {}
LibraryOpenerType.Provider ->
savedSelection.providerData?.apiName?.let { apiName ->
activity?.loadResult(
card.url,
apiName,
)
}
LibraryOpenerType.Browser ->
openBrowser(card.url)
LibraryOpenerType.Search -> {
QuickSearchFragment.pushSearch(
activity,
card.name
)
}
}
}
override fun onConfigurationChanged(newConfig: Configuration) { override fun onConfigurationChanged(newConfig: Configuration) {
(binding?.viewpager?.adapter as? ViewpagerAdapter)?.rebind() (binding?.viewpager?.adapter as? ViewpagerAdapter)?.rebind()
super.onConfigurationChanged(newConfig) super.onConfigurationChanged(newConfig)

View file

@ -377,7 +377,6 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
} }
protected fun exitFullscreen() { protected fun exitFullscreen() {
activity?.showSystemUI()
//if (lockRotation) //if (lockRotation)
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER
@ -389,6 +388,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT
} }
activity?.window?.attributes = lp activity?.window?.attributes = lp
activity?.showSystemUI()
} }
override fun onResume() { override fun onResume() {
@ -1481,6 +1481,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
playerGoBack.setOnClickListener { playerGoBack.setOnClickListener {
activity?.popCurrentPage() activity?.popCurrentPage()
activity?.showSystemUI()
} }
playerSourcesBtt.setOnClickListener { playerSourcesBtt.setOnClickListener {

View file

@ -1383,6 +1383,7 @@ class GeneratorPlayer : FullScreenPlayer() {
} }
binding?.playerLoadingGoBack?.setOnClickListener { binding?.playerLoadingGoBack?.setOnClickListener {
exitFullscreen()
player.release() player.release()
activity?.popCurrentPage() activity?.popCurrentPage()
} }

View file

@ -2,6 +2,9 @@ package com.lagradost.cloudstream3.ui.result
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Dialog import android.app.Dialog
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.Rect import android.graphics.Rect
@ -31,6 +34,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
import com.lagradost.cloudstream3.APIHolder import com.lagradost.cloudstream3.APIHolder
import com.lagradost.cloudstream3.APIHolder.updateHasTrailers import com.lagradost.cloudstream3.APIHolder.updateHasTrailers
import com.lagradost.cloudstream3.CommonActivity import com.lagradost.cloudstream3.CommonActivity
import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.DubStatus import com.lagradost.cloudstream3.DubStatus
import com.lagradost.cloudstream3.LoadResponse import com.lagradost.cloudstream3.LoadResponse
import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
@ -77,7 +81,6 @@ import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes
import com.lagradost.cloudstream3.utils.UIHelper.setImage import com.lagradost.cloudstream3.utils.UIHelper.setImage
import com.lagradost.cloudstream3.utils.VideoDownloadHelper import com.lagradost.cloudstream3.utils.VideoDownloadHelper
open class ResultFragmentPhone : FullScreenPlayer() { open class ResultFragmentPhone : FullScreenPlayer() {
private val gestureRegionsListener = object : PanelsChildGestureRegionObserver.GestureRegionsListener { private val gestureRegionsListener = object : PanelsChildGestureRegionObserver.GestureRegionsListener {
override fun onGestureRegionsUpdate(gestureRegions: List<Rect>) { override fun onGestureRegionsUpdate(gestureRegions: List<Rect>) {
@ -247,6 +250,7 @@ open class ResultFragmentPhone : FullScreenPlayer() {
} }
var selectSeason: String? = null var selectSeason: String? = null
var selectEpisodeRange: String? = null
private fun setUrl(url: String?) { private fun setUrl(url: String?) {
if (url == null) { if (url == null) {
@ -751,6 +755,17 @@ open class ResultFragmentPhone : FullScreenPlayer() {
resultLoadingError.isVisible = data is Resource.Failure resultLoadingError.isVisible = data is Resource.Failure
resultErrorText.isVisible = data is Resource.Failure resultErrorText.isVisible = data is Resource.Failure
resultReloadConnectionOpenInBrowser.isVisible = data is Resource.Failure resultReloadConnectionOpenInBrowser.isVisible = data is Resource.Failure
resultTitle.setOnLongClickListener {
val titleToCopy = resultTitle.text
val clipboardManager =
activity?.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager?
clipboardManager?.setPrimaryClip(ClipData.newPlainText("Title", titleToCopy))
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
showToast(R.string.copyTitle, Toast.LENGTH_SHORT)
}
return@setOnLongClickListener true
}
} }
} }
@ -1027,6 +1042,8 @@ open class ResultFragmentPhone : FullScreenPlayer() {
observeNullable(viewModel.selectedRange) { range -> observeNullable(viewModel.selectedRange) { range ->
resultBinding?.apply { resultBinding?.apply {
resultEpisodeSelect.setText(range) resultEpisodeSelect.setText(range)
selectEpisodeRange = range?.asStringNull(resultEpisodeSelect.context)
// If Season button is invisible then the bookmark button next focus is episode select // If Season button is invisible then the bookmark button next focus is episode select
if (resultEpisodeSelect.isVisible && !resultSeasonButton.isVisible && resultResumeParent.isVisible) { if (resultEpisodeSelect.isVisible && !resultSeasonButton.isVisible && resultResumeParent.isVisible) {
setFocusUpAndDown(resultResumeSeriesButton, resultEpisodeSelect) setFocusUpAndDown(resultResumeSeriesButton, resultEpisodeSelect)
@ -1060,9 +1077,12 @@ open class ResultFragmentPhone : FullScreenPlayer() {
r to (text?.asStringNull(ctx) ?: return@mapNotNull null) r to (text?.asStringNull(ctx) ?: return@mapNotNull null)
} }
view.popupMenuNoIconsAndNoStringRes(names.mapIndexed { index, (_, name) -> activity?.showDialog(
index to name names.map { it.second },
}) { names.indexOfFirst { it.second == selectEpisodeRange },
"",
false,
{}) { itemId ->
viewModel.changeRange(names[itemId].first) viewModel.changeRange(names[itemId].first)
} }
} }

View file

@ -1006,6 +1006,7 @@ class ResultViewModel2 : ViewModel() {
removeFavoritesData(currentId) removeFavoritesData(currentId)
statusChangedCallback?.invoke(false) statusChangedCallback?.invoke(false)
_favoriteStatus.postValue(false) _favoriteStatus.postValue(false)
MainActivity.reloadLibraryEvent(true)
} else { } else {
checkAndWarnDuplicates( checkAndWarnDuplicates(
context, context,
@ -1050,8 +1051,8 @@ class ResultViewModel2 : ViewModel() {
) )
_favoriteStatus.postValue(true) _favoriteStatus.postValue(true)
statusChangedCallback?.invoke(true) statusChangedCallback?.invoke(true)
MainActivity.reloadLibraryEvent(true)
} }
} }
} }
@ -2604,6 +2605,11 @@ class ResultViewModel2 : ViewModel() {
this.rating = searchResponse.personalRating?.times(100) ?: searchResponse.rating this.rating = searchResponse.personalRating?.times(100) ?: searchResponse.rating
this.tags = searchResponse.tags this.tags = searchResponse.tags
} }
if (searchResponse is DataStoreHelper.BookmarkedData) {
this.plot = searchResponse.plot
this.rating = searchResponse.rating
this.tags = searchResponse.tags
}
} }
val mainId = searchResponse.id ?: response.getId() val mainId = searchResponse.id ?: response.getId()

View file

@ -264,6 +264,9 @@ class SearchFragment : Fragment() {
builder.setContentView(selectMainpageBinding.root) builder.setContentView(selectMainpageBinding.root)
builder.show() builder.show()
builder.let { dialog -> builder.let { dialog ->
val previousSelectedApis = selectedApis.toSet()
val previousSelectedSearchTypes = selectedSearchTypes.toSet()
val isMultiLang = ctx.getApiProviderLangSettings().let { set -> val isMultiLang = ctx.getApiProviderLangSettings().let { set ->
set.size > 1 || set.contains(AllLanguagesName) set.size > 1 || set.contains(AllLanguagesName)
} }
@ -352,7 +355,9 @@ class SearchFragment : Fragment() {
selectedApis = currentSelectedApis selectedApis = currentSelectedApis
// run search when dialog is close // run search when dialog is close
search(binding?.mainSearch?.query?.toString()) if(previousSelectedApis != selectedApis.toSet() || previousSelectedSearchTypes != selectedSearchTypes.toSet()) {
search(binding?.mainSearch?.query?.toString())
}
} }
updateList(selectedSearchTypes.toList()) updateList(selectedSearchTypes.toList())
} }

View file

@ -104,6 +104,7 @@ import com.lagradost.cloudstream3.extractors.TauVideo
import com.lagradost.cloudstream3.extractors.SibNet import com.lagradost.cloudstream3.extractors.SibNet
import com.lagradost.cloudstream3.extractors.ContentX import com.lagradost.cloudstream3.extractors.ContentX
import com.lagradost.cloudstream3.extractors.Hotlinger import com.lagradost.cloudstream3.extractors.Hotlinger
import com.lagradost.cloudstream3.extractors.FourCX
import com.lagradost.cloudstream3.extractors.HDMomPlayer import com.lagradost.cloudstream3.extractors.HDMomPlayer
import com.lagradost.cloudstream3.extractors.HDPlayerSystem import com.lagradost.cloudstream3.extractors.HDPlayerSystem
import com.lagradost.cloudstream3.extractors.VideoSeyred import com.lagradost.cloudstream3.extractors.VideoSeyred
@ -151,6 +152,7 @@ import com.lagradost.cloudstream3.extractors.StreamSB8
import com.lagradost.cloudstream3.extractors.StreamSB9 import com.lagradost.cloudstream3.extractors.StreamSB9
import com.lagradost.cloudstream3.extractors.StreamTape import com.lagradost.cloudstream3.extractors.StreamTape
import com.lagradost.cloudstream3.extractors.StreamTapeNet import com.lagradost.cloudstream3.extractors.StreamTapeNet
import com.lagradost.cloudstream3.extractors.StreamTapeXyz
import com.lagradost.cloudstream3.extractors.StreamhideCom import com.lagradost.cloudstream3.extractors.StreamhideCom
import com.lagradost.cloudstream3.extractors.StreamhideTo import com.lagradost.cloudstream3.extractors.StreamhideTo
import com.lagradost.cloudstream3.extractors.Streamhub2 import com.lagradost.cloudstream3.extractors.Streamhub2
@ -619,6 +621,7 @@ val extractorApis: MutableList<ExtractorApi> = arrayListOf(
StreamTape(), StreamTape(),
StreamTapeNet(), StreamTapeNet(),
ShaveTape(), ShaveTape(),
StreamTapeXyz(),
//mixdrop extractors //mixdrop extractors
MixDropBz(), MixDropBz(),
@ -683,6 +686,7 @@ val extractorApis: MutableList<ExtractorApi> = arrayListOf(
SibNet(), SibNet(),
ContentX(), ContentX(),
Hotlinger(), Hotlinger(),
FourCX(),
HDMomPlayer(), HDMomPlayer(),
HDPlayerSystem(), HDPlayerSystem(),
VideoSeyred(), VideoSeyred(),

View file

@ -35,6 +35,7 @@ import androidx.core.graphics.blue
import androidx.core.graphics.drawable.toBitmapOrNull import androidx.core.graphics.drawable.toBitmapOrNull
import androidx.core.graphics.green import androidx.core.graphics.green
import androidx.core.graphics.red import androidx.core.graphics.red
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.marginBottom import androidx.core.view.marginBottom
import androidx.core.view.marginLeft import androidx.core.view.marginLeft
import androidx.core.view.marginRight import androidx.core.view.marginRight
@ -401,81 +402,35 @@ object UIHelper {
// Enables regular immersive mode. // Enables regular immersive mode.
// For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE. // For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE.
// Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY // Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY
window.decorView.systemUiVisibility = ( if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
// Set the content to appear under the system bars so that the if (window.insetsController != null) {
// content doesn't resize when the system bars hide and show.
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE window!!.insetsController?.hide(WindowInsetsCompat.Type.systemBars())
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION window!!.insetsController?.systemBarsBehavior =
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
// Hide the nav bar and status bar }
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION }
or View.SYSTEM_UI_FLAG_FULLSCREEN
// or View.SYSTEM_UI_FLAG_LOW_PROFILE else {
) @Suppress("DEPRECATION")
// window.addFlags(View.KEEP_SCREEN_ON) window.decorView.systemUiVisibility = (
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
// Set the content to appear under the system bars so that the
// content doesn't resize when the system bars hide and show.
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
// Hide the nav bar and status bar
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_FULLSCREEN
)
}
} }
fun FragmentActivity.popCurrentPage() { fun FragmentActivity.popCurrentPage() {
this.onBackPressedDispatcher.onBackPressed() this.onBackPressedDispatcher.onBackPressed()
/*val currentFragment = supportFragmentManager.fragments.lastOrNull {
it.isVisible
} ?: return
supportFragmentManager.beginTransaction()
.setCustomAnimations(
R.anim.enter_anim,
R.anim.exit_anim,
R.anim.pop_enter,
R.anim.pop_exit
)
.remove(currentFragment)
.commitAllowingStateLoss()*/
} }
/*
fun FragmentActivity.popCurrentPage(isInPlayer: Boolean, isInExpandedView: Boolean, isInResults: Boolean) {
val currentFragment = supportFragmentManager.fragments.lastOrNull {
it.isVisible
}
?: //this.onBackPressedDispatcher.onBackPressed()
return
/*
if (tvActivity == null) {
requestedOrientation = if (settingsManager?.getBoolean("force_landscape", false) == true) {
ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
} else {
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
}*/
// No fucked animations leaving the player :)
when {
isInPlayer -> {
supportFragmentManager.beginTransaction()
//.setCustomAnimations(R.anim.enter, R.anim.exit, R.anim.pop_enter, R.anim.pop_exit)
.remove(currentFragment)
.commitAllowingStateLoss()
}
isInExpandedView && !isInResults -> {
supportFragmentManager.beginTransaction()
.setCustomAnimations(
R.anim.enter_anim,//R.anim.enter_from_right,
R.anim.exit_anim,//R.anim.exit_to_right,
R.anim.pop_enter,
R.anim.pop_exit
)
.remove(currentFragment)
.commitAllowingStateLoss()
}
else -> {
supportFragmentManager.beginTransaction()
.setCustomAnimations(R.anim.enter_anim, R.anim.exit_anim, R.anim.pop_enter, R.anim.pop_exit)
.remove(currentFragment)
.commitAllowingStateLoss()
}
}
}*/
fun Context.getStatusBarHeight(): Int { fun Context.getStatusBarHeight(): Int {
if (isTvSettings()) { if (isTvSettings()) {
@ -541,14 +496,27 @@ object UIHelper {
} }
fun Activity.changeStatusBarState(hide: Boolean): Int { fun Activity.changeStatusBarState(hide: Boolean): Int {
@Suppress("DEPRECATION")
return if (hide) { return if (hide) {
window?.setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN, if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
WindowManager.LayoutParams.FLAG_FULLSCREEN window.insetsController?.hide(WindowInsets.Type.statusBars())
)
} else {
window.setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN
)
}
0 0
} else { } else {
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
window.insetsController?.show(WindowInsets.Type.statusBars())
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
}
this.getStatusBarHeight() this.getStatusBarHeight()
} }
} }
@ -556,13 +524,20 @@ object UIHelper {
// Shows the system bars by removing all the flags // Shows the system bars by removing all the flags
// except for the ones that make the content appear under the system bars. // except for the ones that make the content appear under the system bars.
fun Activity.showSystemUI() { fun Activity.showSystemUI() {
window.decorView.systemUiVisibility =
(View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (window.insetsController != null) {
window!!.insetsController?.show(WindowInsetsCompat.Type.systemBars())
}
} else {
@Suppress("DEPRECATION")
window.decorView.systemUiVisibility =
(View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
}
changeStatusBarState(isEmulatorSettings()) changeStatusBarState(isEmulatorSettings())
// window.clearFlags(View.KEEP_SCREEN_ON)
} }
fun Context.shouldShowPIPMode(isInPlayer: Boolean): Boolean { fun Context.shouldShowPIPMode(isInPlayer: Boolean): Boolean {

View file

@ -41,17 +41,36 @@
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
android:orientation="vertical"> android:orientation="vertical">
<TextView <FrameLayout
android:id="@+id/resultview_preview_title" android:layout_width="match_parent"
android:layout_width="wrap_content" android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:textColor="?attr/textColor"
android:textSize="16sp"
android:textStyle="bold" <TextView
tools:text="The Perfect Run"> android:id="@+id/resultview_preview_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/textColor"
android:textSize="16sp"
android:layout_gravity="start|center_vertical"
android:textStyle="bold"
android:layout_marginEnd="25dp"
tools:text="The Perfect Run">
</TextView> </TextView>
<ImageView
android:id="@+id/resultview_preview_favorite"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_gravity="end|center_vertical"
android:layout_margin="5dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:elevation="10dp"
android:nextFocusDown="@id/resultview_preview_bookmark"
android:src="@drawable/ic_baseline_favorite_border_24"
app:tint="?attr/textColor" />
</FrameLayout>
<com.lagradost.cloudstream3.widget.FlowLayout <com.lagradost.cloudstream3.widget.FlowLayout
android:layout_width="match_parent" android:layout_width="match_parent"
@ -123,6 +142,7 @@
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/resultview_preview_bookmark" android:id="@+id/resultview_preview_bookmark"
android:layout_weight="1" android:layout_weight="1"
android:nextFocusUp="@id/resultview_preview_favorite"
android:nextFocusRight="@id/resultview_preview_more_info" android:nextFocusRight="@id/resultview_preview_more_info"
tools:visibility="visible" tools:visibility="visible"
@ -136,6 +156,7 @@
<com.google.android.material.button.MaterialButton <com.google.android.material.button.MaterialButton
android:id="@+id/resultview_preview_more_info" android:id="@+id/resultview_preview_more_info"
android:layout_weight="1" android:layout_weight="1"
android:nextFocusUp="@id/resultview_preview_favorite"
android:nextFocusLeft="@id/resultview_preview_bookmark" android:nextFocusLeft="@id/resultview_preview_bookmark"
tools:visibility="visible" tools:visibility="visible"

View file

@ -159,6 +159,16 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginBottom="40dp"> android:layout_marginBottom="40dp">
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/library_random"
style="@style/ExtendedFloatingActionButton"
android:layout_gravity="bottom|start"
android:text="@string/home_random"
android:textColor="?attr/textColor"
android:visibility="gone"
app:icon="@drawable/ic_baseline_play_arrow_24"
tools:ignore="ContentDescription"
tools:visibility="visible" />
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/sort_fab" android:id="@+id/sort_fab"

View file

@ -190,6 +190,16 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_marginBottom="40dp"> android:layout_marginBottom="40dp">
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/library_random"
style="@style/ExtendedFloatingActionButton"
android:layout_gravity="bottom|start"
android:text="@string/home_random"
android:textColor="?attr/textColor"
android:visibility="gone"
app:icon="@drawable/ic_baseline_play_arrow_24"
tools:ignore="ContentDescription"
tools:visibility="visible" />
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/sort_fab" android:id="@+id/sort_fab"

View file

@ -171,6 +171,7 @@
<string name="sort_close">Close</string> <string name="sort_close">Close</string>
<string name="sort_clear">Clear</string> <string name="sort_clear">Clear</string>
<string name="sort_save">Save</string> <string name="sort_save">Save</string>
<string name="copyTitle">Title copied!</string>
<string name="player_speed">Player Speed</string> <string name="player_speed">Player Speed</string>
<string name="subtitles_settings">Subtitle Settings</string> <string name="subtitles_settings">Subtitle Settings</string>
<string name="subs_text_color">Text Color</string> <string name="subs_text_color">Text Color</string>
@ -435,7 +436,7 @@
<string name="pref_category_ui_features">Features</string> <string name="pref_category_ui_features">Features</string>
<string name="category_general">General</string> <string name="category_general">General</string>
<string name="random_button_settings">Random Button</string> <string name="random_button_settings">Random Button</string>
<string name="random_button_settings_desc">Show random button on Homepage</string> <string name="random_button_settings_desc">Show random button on Homepage and Library</string>
<string name="provider_lang_settings">Provider languages</string> <string name="provider_lang_settings">Provider languages</string>
<string name="app_layout">App Layout</string> <string name="app_layout">App Layout</string>
<string name="preferred_media_settings">Preferred media</string> <string name="preferred_media_settings">Preferred media</string>