From 42774f61835eb58e72094f36c6636f0360ffa687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20Sancak?= Date: Tue, 9 Jan 2024 01:45:53 +0300 Subject: [PATCH 01/14] Extractor: ContentX expanded and fix (#859) * Extractor: ContentX expanded and fix --- .../lagradost/cloudstream3/extractors/ContentXExtractor.kt | 4 ++-- .../lagradost/cloudstream3/extractors/HotlingerExtractor.kt | 5 +++++ .../java/com/lagradost/cloudstream3/utils/ExtractorApi.kt | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt index 61943b70..02b4440d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt @@ -18,7 +18,7 @@ open class ContentX : ExtractorApi() { 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 vid_source = app.get("https://contentx.me/source2.php?v=${i_extract}", referer=ext_ref).text + 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 m3u_link = vid_extract.replace("\\", "") @@ -35,7 +35,7 @@ open class ContentX : ExtractorApi() { val i_dublaj = Regex(""",\"([^']+)\",\"Türkçe""").find(i_source)!!.groups[1]?.value 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_link = dublaj_extract.replace("\\", "") diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/HotlingerExtractor.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/HotlingerExtractor.kt index 4a77cbf3..7389db68 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/HotlingerExtractor.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/HotlingerExtractor.kt @@ -5,4 +5,9 @@ package com.lagradost.cloudstream3.extractors class Hotlinger : ContentX() { override var name = "Hotlinger" override var mainUrl = "https://hotlinger.com" +} + +class FourCX : ContentX() { + override var name = "FourCX" + override var mainUrl = "https://four.contentx.me" } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt index deb0eb3c..2f686a2c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -104,6 +104,7 @@ import com.lagradost.cloudstream3.extractors.TauVideo import com.lagradost.cloudstream3.extractors.SibNet import com.lagradost.cloudstream3.extractors.ContentX import com.lagradost.cloudstream3.extractors.Hotlinger +import com.lagradost.cloudstream3.extractors.FourCX import com.lagradost.cloudstream3.extractors.HDMomPlayer import com.lagradost.cloudstream3.extractors.HDPlayerSystem import com.lagradost.cloudstream3.extractors.VideoSeyred @@ -683,6 +684,7 @@ val extractorApis: MutableList = arrayListOf( SibNet(), ContentX(), Hotlinger(), + FourCX(), HDMomPlayer(), HDPlayerSystem(), VideoSeyred(), From 42fd0b5c76d44b495e4e48dbdd4e27ca0849f4db Mon Sep 17 00:00:00 2001 From: coxju <118901131+coxju@users.noreply.github.com> Date: Tue, 9 Jan 2024 04:16:19 +0530 Subject: [PATCH 02/14] new streamtape extractor (#857) --- .../java/com/lagradost/cloudstream3/extractors/StreamTape.kt | 4 ++++ .../java/com/lagradost/cloudstream3/utils/ExtractorApi.kt | 2 ++ 2 files changed, 6 insertions(+) diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamTape.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamTape.kt index ece8dc4b..2ee98c65 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamTape.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/StreamTape.kt @@ -9,6 +9,10 @@ class StreamTapeNet : StreamTape() { override var mainUrl = "https://streamtape.net" } +class StreamTapeXyz : StreamTape() { + override var mainUrl = "https://streamtape.xyz" +} + class ShaveTape : StreamTape(){ override var mainUrl = "https://shavetape.cash" } diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt index 2f686a2c..1ae1b9b5 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -152,6 +152,7 @@ import com.lagradost.cloudstream3.extractors.StreamSB8 import com.lagradost.cloudstream3.extractors.StreamSB9 import com.lagradost.cloudstream3.extractors.StreamTape import com.lagradost.cloudstream3.extractors.StreamTapeNet +import com.lagradost.cloudstream3.extractors.StreamTapeXyz import com.lagradost.cloudstream3.extractors.StreamhideCom import com.lagradost.cloudstream3.extractors.StreamhideTo import com.lagradost.cloudstream3.extractors.Streamhub2 @@ -620,6 +621,7 @@ val extractorApis: MutableList = arrayListOf( StreamTape(), StreamTapeNet(), ShaveTape(), + StreamTapeXyz(), //mixdrop extractors MixDropBz(), From 97ec98b9e2f4b39552f40c9a5f07b01c7ee85b1f Mon Sep 17 00:00:00 2001 From: coxju <118901131+coxju@users.noreply.github.com> Date: Wed, 10 Jan 2024 23:25:10 +0530 Subject: [PATCH 03/14] feat : show favorite button in bottom dialog (#858) Co-authored-by: coxju --- .../lagradost/cloudstream3/MainActivity.kt | 29 ++++++++++++++ .../res/layout/bottom_resultview_preview.xml | 39 ++++++++++++++----- 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index 71a24ced..63183d73 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -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 resultviewPreviewDescription.setOnClickListener { view -> view.context?.let { ctx -> diff --git a/app/src/main/res/layout/bottom_resultview_preview.xml b/app/src/main/res/layout/bottom_resultview_preview.xml index fe3f9b8d..4a64114e 100644 --- a/app/src/main/res/layout/bottom_resultview_preview.xml +++ b/app/src/main/res/layout/bottom_resultview_preview.xml @@ -41,17 +41,36 @@ android:layout_marginStart="10dp" android:orientation="vertical"> - - android:textStyle="bold" - tools:text="The Perfect Run"> + - + + + + Date: Wed, 10 Jan 2024 19:10:34 +0100 Subject: [PATCH 04/14] fix --- .../cloudstream3/ui/home/HomeParentItemAdapterPreview.kt | 4 ++++ .../lagradost/cloudstream3/ui/result/ResultViewModel2.kt | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt index cc4ab895..b7f601ff 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeParentItemAdapterPreview.kt @@ -216,6 +216,9 @@ class HomeParentItemAdapterPreview( viewModel.click(callback) return@HomeChildItemAdapter } + + (callback.view.context?.getActivity() as? MainActivity)?.loadPopup(callback.card, load = false) + /* callback.view.context?.getActivity()?.showOptionSelectStringRes( callback.view, callback.card.posterUrl, @@ -261,6 +264,7 @@ class HomeParentItemAdapterPreview( } } } + */ } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt index e60c388b..c24efe56 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultViewModel2.kt @@ -1006,6 +1006,7 @@ class ResultViewModel2 : ViewModel() { removeFavoritesData(currentId) statusChangedCallback?.invoke(false) _favoriteStatus.postValue(false) + MainActivity.reloadLibraryEvent(true) } else { checkAndWarnDuplicates( context, @@ -1050,8 +1051,8 @@ class ResultViewModel2 : ViewModel() { ) _favoriteStatus.postValue(true) - statusChangedCallback?.invoke(true) + MainActivity.reloadLibraryEvent(true) } } } @@ -2604,6 +2605,11 @@ class ResultViewModel2 : ViewModel() { this.rating = searchResponse.personalRating?.times(100) ?: searchResponse.rating 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() From 6f1e0bef8027c74cbd93c9584d40669e29c3d005 Mon Sep 17 00:00:00 2001 From: coxju <118901131+coxju@users.noreply.github.com> Date: Thu, 11 Jan 2024 02:35:56 +0530 Subject: [PATCH 05/14] feat: show the episodic range with current selection checked (#851) --- .../cloudstream3/ui/result/ResultFragmentPhone.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt index ad34309c..1c18feaa 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt @@ -247,6 +247,7 @@ open class ResultFragmentPhone : FullScreenPlayer() { } var selectSeason: String? = null + var selectEpisodeRange: String? = null private fun setUrl(url: String?) { if (url == null) { @@ -1027,6 +1028,8 @@ open class ResultFragmentPhone : FullScreenPlayer() { observeNullable(viewModel.selectedRange) { range -> resultBinding?.apply { resultEpisodeSelect.setText(range) + + selectEpisodeRange = range?.asStringNull(resultEpisodeSelect.context) // If Season button is invisible then the bookmark button next focus is episode select if (resultEpisodeSelect.isVisible && !resultSeasonButton.isVisible && resultResumeParent.isVisible) { setFocusUpAndDown(resultResumeSeriesButton, resultEpisodeSelect) @@ -1060,9 +1063,12 @@ open class ResultFragmentPhone : FullScreenPlayer() { r to (text?.asStringNull(ctx) ?: return@mapNotNull null) } - view.popupMenuNoIconsAndNoStringRes(names.mapIndexed { index, (_, name) -> - index to name - }) { + activity?.showDialog( + names.map { it.second }, + names.indexOfFirst { it.second == selectEpisodeRange }, + "", + false, + {}) { itemId -> viewModel.changeRange(names[itemId].first) } } From e5f483b0b29df6435f85a3bfff4a68eb744523d5 Mon Sep 17 00:00:00 2001 From: Yutatsu <126276749+J4zzyB1te7s@users.noreply.github.com> Date: Thu, 11 Jan 2024 03:06:45 +0600 Subject: [PATCH 06/14] Fix vidplay extractor (#866) --- .../java/com/lagradost/cloudstream3/extractors/Vidplay.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Vidplay.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Vidplay.kt index 8653a347..36dad60c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/Vidplay.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Vidplay.kt @@ -10,8 +10,8 @@ import com.lagradost.cloudstream3.utils.M3u8Helper import javax.crypto.Cipher import javax.crypto.spec.SecretKeySpec -// Code found in https://github.com/Claudemirovsky/worstsource-keys -// special credits to @Claudemirovsky for providing key +// Code found in https://github.com/blacksourcellc/vid_keys +// special credits to @blacksourcellc for providing key class MyCloud : Vidplay() { override val name = "MyCloud" @@ -27,7 +27,7 @@ open class Vidplay : ExtractorApi() { override val mainUrl = "https://vidplay.site" override val requiresReferer = true open val key = - "https://raw.githubusercontent.com/Claudemirovsky/worstsource-keys/keys/keys.json" + "https://raw.githubusercontent.com/blacksourcellc/vid_keys/keys/keys.json" override suspend fun getUrl( url: String, From 19b1a40cf860645769bc9df7726e052630f848c4 Mon Sep 17 00:00:00 2001 From: IndusAryan <125901294+IndusAryan@users.noreply.github.com> Date: Thu, 11 Jan 2024 02:50:43 +0530 Subject: [PATCH 07/14] use window insets compat controller (#847) --- .../ui/player/FullScreenPlayer.kt | 2 +- .../cloudstream3/ui/player/GeneratorPlayer.kt | 1 + .../lagradost/cloudstream3/utils/UIHelper.kt | 133 +++++++----------- 3 files changed, 56 insertions(+), 80 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt index 6508721a..19ff3bf1 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt @@ -379,7 +379,6 @@ open class FullScreenPlayer : AbstractPlayerFragment() { } protected fun exitFullscreen() { - activity?.showSystemUI() //if (lockRotation) activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER @@ -391,6 +390,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() { WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT } activity?.window?.attributes = lp + activity?.showSystemUI() } override fun onResume() { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt index 0a626471..386e8df0 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt @@ -1383,6 +1383,7 @@ class GeneratorPlayer : FullScreenPlayer() { } binding?.playerLoadingGoBack?.setOnClickListener { + exitFullscreen() player.release() activity?.popCurrentPage() } diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt index 09ea151d..d0a2e500 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt @@ -35,6 +35,7 @@ import androidx.core.graphics.blue import androidx.core.graphics.drawable.toBitmapOrNull import androidx.core.graphics.green import androidx.core.graphics.red +import androidx.core.view.WindowInsetsCompat import androidx.core.view.marginBottom import androidx.core.view.marginLeft import androidx.core.view.marginRight @@ -401,81 +402,35 @@ object UIHelper { // Enables regular immersive mode. // For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE. // Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY - 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 - // or View.SYSTEM_UI_FLAG_LOW_PROFILE - ) - // window.addFlags(View.KEEP_SCREEN_ON) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + + if (window.insetsController != null) { + + window!!.insetsController?.hide(WindowInsetsCompat.Type.systemBars()) + window!!.insetsController?.systemBarsBehavior = + WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE + } + } + + else { + @Suppress("DEPRECATION") + 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() { 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 { if (isTvSettings()) { @@ -541,14 +496,27 @@ object UIHelper { } fun Activity.changeStatusBarState(hide: Boolean): Int { + @Suppress("DEPRECATION") return if (hide) { - window?.setFlags( - WindowManager.LayoutParams.FLAG_FULLSCREEN, - WindowManager.LayoutParams.FLAG_FULLSCREEN - ) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + window.insetsController?.hide(WindowInsets.Type.statusBars()) + + } else { + window.setFlags( + WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN + ) + } 0 } 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() } } @@ -556,13 +524,20 @@ object UIHelper { // Shows the system bars by removing all the flags // except for the ones that make the content appear under the system bars. 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()) - - // window.clearFlags(View.KEEP_SCREEN_ON) } fun Context.shouldShowPIPMode(isInPlayer: Boolean): Boolean { From d71d3890b52cd745ecb5b556323e09e05155b356 Mon Sep 17 00:00:00 2001 From: coxju <118901131+coxju@users.noreply.github.com> Date: Thu, 11 Jan 2024 02:58:06 +0530 Subject: [PATCH 08/14] feat: show random button on library (#855) --- .../ui/library/LibraryFragment.kt | 141 ++++++++++++------ app/src/main/res/layout/fragment_library.xml | 10 ++ app/src/main/res/values/strings.xml | 2 +- 3 files changed, 105 insertions(+), 48 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/library/LibraryFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/library/LibraryFragment.kt index a37fbcb3..8e9c8521 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/library/LibraryFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/library/LibraryFragment.kt @@ -20,11 +20,12 @@ import android.widget.Toast import androidx.annotation.StringRes import androidx.appcompat.widget.SearchView import androidx.core.view.allViews +import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels +import androidx.preference.PreferenceManager import androidx.recyclerview.widget.RecyclerView -import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayoutMediator 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.MainActivity import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.SearchResponse import com.lagradost.cloudstream3.databinding.FragmentLibraryBinding import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.debugAssert @@ -80,6 +82,8 @@ data class ProviderLibraryData( class LibraryFragment : Fragment() { companion object { + + val listLibraryItems = mutableListOf() fun newInstance() = LibraryFragment() /** @@ -91,6 +95,7 @@ class LibraryFragment : Fragment() { private val libraryViewModel: LibraryViewModel by activityViewModels() var binding: FragmentLibraryBinding? = null + private var toggleRandomButton = false override fun onCreateView( 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 @@ -277,8 +301,10 @@ class LibraryFragment : Fragment() { { isScrollingDown: Boolean -> if (isScrollingDown) { binding?.sortFab?.shrink() + binding?.libraryRandom?.shrink() } else { binding?.sortFab?.extend() + binding?.libraryRandom?.extend() } }) callback@{ searchClickCallback -> // To prevent future accidents @@ -303,52 +329,7 @@ class LibraryFragment : Fragment() { } SEARCH_ACTION_LOAD -> { - // This basically first selects the individual opener and if that is default then - // selects the whole list opener - val savedListSelection = - getKey("$currentAccount/$LIBRARY_FOLDER", syncName.name) - val savedSelection = getKey( - "$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 - ) - } - } + loadLibraryItem(syncName, syncId, searchClickCallback.card) } } } @@ -414,6 +395,16 @@ class LibraryFragment : Fragment() { 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 // Without this there would be a flashing effect: // 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("$currentAccount/$LIBRARY_FOLDER", syncName.name) + + val savedSelection = getKey( + "$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) { (binding?.viewpager?.adapter as? ViewpagerAdapter)?.rebind() super.onConfigurationChanged(newConfig) diff --git a/app/src/main/res/layout/fragment_library.xml b/app/src/main/res/layout/fragment_library.xml index 446c2a81..d49e3d1e 100644 --- a/app/src/main/res/layout/fragment_library.xml +++ b/app/src/main/res/layout/fragment_library.xml @@ -159,6 +159,16 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="40dp"> + Features General Random Button - Show random button on Homepage + Show random button on Homepage and Library Provider languages App Layout Preferred media From 96aa56209b76864c45acbc4b1f5e0a98cda0be80 Mon Sep 17 00:00:00 2001 From: Sir Aguacata <87155550+KillerDogeEmpire@users.noreply.github.com> Date: Wed, 10 Jan 2024 15:47:40 -0800 Subject: [PATCH 09/14] Revert the repo change to get keys (#867) --- .../java/com/lagradost/cloudstream3/extractors/Vidplay.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/Vidplay.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/Vidplay.kt index 36dad60c..8653a347 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/Vidplay.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/Vidplay.kt @@ -10,8 +10,8 @@ import com.lagradost.cloudstream3.utils.M3u8Helper import javax.crypto.Cipher import javax.crypto.spec.SecretKeySpec -// Code found in https://github.com/blacksourcellc/vid_keys -// special credits to @blacksourcellc for providing key +// Code found in https://github.com/Claudemirovsky/worstsource-keys +// special credits to @Claudemirovsky for providing key class MyCloud : Vidplay() { override val name = "MyCloud" @@ -27,7 +27,7 @@ open class Vidplay : ExtractorApi() { override val mainUrl = "https://vidplay.site" override val requiresReferer = true open val key = - "https://raw.githubusercontent.com/blacksourcellc/vid_keys/keys/keys.json" + "https://raw.githubusercontent.com/Claudemirovsky/worstsource-keys/keys/keys.json" override suspend fun getUrl( url: String, From 85a769a89835421b6310ec2a7a865c84dfba8b64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20Sancak?= Date: Thu, 11 Jan 2024 17:52:34 +0300 Subject: [PATCH 10/14] Extractor: ContentX add external subtitle (#869) --- .../cloudstream3/extractors/ContentXExtractor.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/src/main/java/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt b/app/src/main/java/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt index 02b4440d..b7f84af1 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt @@ -18,6 +18,21 @@ open class ContentX : ExtractorApi() { 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 sub_urls = mutableSetOf() + 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 m3u_link = vid_extract.replace("\\", "") From 8c5ab86714c1f050831f291fb7f6222ce3a925a1 Mon Sep 17 00:00:00 2001 From: IndusAryan <125901294+IndusAryan@users.noreply.github.com> Date: Thu, 11 Jan 2024 20:23:31 +0530 Subject: [PATCH 11/14] hotfix window compat bug (#870) --- .../com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt index 19ff3bf1..e6a8591f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt @@ -1482,6 +1482,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() { playerGoBack.setOnClickListener { activity?.popCurrentPage() + activity?.showSystemUI() } playerSourcesBtt.setOnClickListener { @@ -1569,4 +1570,4 @@ open class FullScreenPlayer : AbstractPlayerFragment() { ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE // default orientation } } -} \ No newline at end of file +} From 0eb152c5db3b17b8f70026ee1a2ff103c8cdc75b Mon Sep 17 00:00:00 2001 From: coxju <118901131+coxju@users.noreply.github.com> Date: Thu, 11 Jan 2024 20:24:28 +0530 Subject: [PATCH 12/14] fix: search only if selection changed (#868) --- .../com/lagradost/cloudstream3/ui/search/SearchFragment.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt index 7f33c08d..243d9f4e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchFragment.kt @@ -264,6 +264,9 @@ class SearchFragment : Fragment() { builder.setContentView(selectMainpageBinding.root) builder.show() builder.let { dialog -> + val previousSelectedApis = selectedApis.toSet() + val previousSelectedSearchTypes = selectedSearchTypes.toSet() + val isMultiLang = ctx.getApiProviderLangSettings().let { set -> set.size > 1 || set.contains(AllLanguagesName) } @@ -352,7 +355,9 @@ class SearchFragment : Fragment() { selectedApis = currentSelectedApis // 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()) } From 0c73f5e59ab5aefb1409ef6fb9e8d0614409d0ea Mon Sep 17 00:00:00 2001 From: coxju <118901131+coxju@users.noreply.github.com> Date: Thu, 11 Jan 2024 21:38:37 +0530 Subject: [PATCH 13/14] fix: library not loading in TV (#871) --- app/src/main/res/layout/fragment_library_tv.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/src/main/res/layout/fragment_library_tv.xml b/app/src/main/res/layout/fragment_library_tv.xml index 6d2198e9..3269167a 100644 --- a/app/src/main/res/layout/fragment_library_tv.xml +++ b/app/src/main/res/layout/fragment_library_tv.xml @@ -190,6 +190,16 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="40dp"> + Date: Fri, 12 Jan 2024 21:18:43 +0530 Subject: [PATCH 14/14] feat(ui): long press title to copy (#872) * new feature: hold to copy movie title * remove title copy hint --- .../ui/result/ResultFragmentPhone.kt | 16 +++++++++++++++- app/src/main/res/values/strings.xml | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt index 1c18feaa..e7e50b9d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragmentPhone.kt @@ -2,6 +2,9 @@ package com.lagradost.cloudstream3.ui.result import android.annotation.SuppressLint import android.app.Dialog +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context import android.content.Intent import android.content.res.ColorStateList 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.updateHasTrailers import com.lagradost.cloudstream3.CommonActivity +import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.DubStatus import com.lagradost.cloudstream3.LoadResponse 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.VideoDownloadHelper - open class ResultFragmentPhone : FullScreenPlayer() { private val gestureRegionsListener = object : PanelsChildGestureRegionObserver.GestureRegionsListener { override fun onGestureRegionsUpdate(gestureRegions: List) { @@ -752,6 +755,17 @@ open class ResultFragmentPhone : FullScreenPlayer() { resultLoadingError.isVisible = data is Resource.Failure resultErrorText.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 + } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 06fa449d..678bc568 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -171,6 +171,7 @@ Close Clear Save + Title copied! Player Speed Subtitle Settings Text Color