From 2bfee2e4a3656edf5ccb2bdf19bdda2202899401 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 15 Oct 2025 17:18:15 -0600 Subject: [PATCH 001/513] Fix library crash (#2006) --- .../com/lagradost/cloudstream3/ui/library/ViewpagerAdapter.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/library/ViewpagerAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/library/ViewpagerAdapter.kt index 392bf9cb3..f868612d2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/library/ViewpagerAdapter.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/library/ViewpagerAdapter.kt @@ -100,7 +100,7 @@ class ViewpagerAdapter( //Expand the top Appbar based on scroll direction up/down, simulate phone behavior if (isLayout(TV or EMULATOR)) { binding.root.rootView.findViewById(R.id.search_bar) - .apply { + ?.apply { if (diff <= 0) setExpanded(true) else From e113cee4344e876d102eee77f05d075f10fbc8c6 Mon Sep 17 00:00:00 2001 From: rockhero1234 <149141736+rockhero1234@users.noreply.github.com> Date: Thu, 16 Oct 2025 19:06:22 +0530 Subject: [PATCH 002/513] fix(tv):not show rotate btn (#2010) * fix(tv):not show rotate btn * also emulator --- .../com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt | 2 +- 1 file changed, 1 insertion(+), 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 f6f68eaf2..bc51775cc 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 @@ -1861,7 +1861,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() { playerBinding?.apply { playerSpeedBtt.isVisible = playBackSpeedEnabled playerResizeBtt.isVisible = playerResizeEnabled - playerRotateBtt.isVisible = playerRotateEnabled + playerRotateBtt.isVisible = if(isLayout(TV or EMULATOR)) false else playerRotateEnabled if (hideControlsNames) { hideControlsNames() } From 505f869dbfe80ea19d0a90d7577657c2db80302d Mon Sep 17 00:00:00 2001 From: rockhero1234 <149141736+rockhero1234@users.noreply.github.com> Date: Thu, 16 Oct 2025 19:22:19 +0530 Subject: [PATCH 003/513] feat:resume btn with circular progress (#1998) --- .../ui/result/ResultFragmentPhone.kt | 40 +++- app/src/main/res/layout/fragment_result.xml | 209 ++++++++---------- 2 files changed, 129 insertions(+), 120 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 e170dc645..6030b5dc2 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 @@ -595,10 +595,12 @@ open class ResultFragmentPhone : FullScreenPlayer() { resultBinding?.apply { if (resume == null) { resultResumeParent.isVisible = false + resultResumeProgressHolder.isVisible = false return@observeNullable } resultResumeParent.isVisible = true resume.progress?.let { progress -> + resultNextSeriesButton.isVisible = false resultResumeSeriesTitle.apply { isVisible = !resume.isMovie text = @@ -608,8 +610,11 @@ open class ResultFragmentPhone : FullScreenPlayer() { resume.result.season ) } - if (resume.isMovie) resultResumeSeriesProgressText.maxLines = 1 - resultResumeSeriesProgressText.setText(progress.progressLeft) + if (resume.isMovie){ + resultPlayMovie.isGone = true + resultResumeSeriesProgressText.isVisible = true + resultResumeSeriesProgressText.setText(progress.progressLeft) + } resultResumeSeriesProgress.apply { isVisible = true this.max = progress.maxProgress @@ -618,19 +623,24 @@ open class ResultFragmentPhone : FullScreenPlayer() { resultResumeProgressHolder.isVisible = true } ?: run { resultResumeProgressHolder.isVisible = false + if(!resume.isMovie){ + resultNextSeriesButton.isVisible = true + resultNextSeriesButton.text =context?.getNameFull( + resume.result.name, + resume.result.episode, + resume.result.season + ) + } resultResumeSeriesProgress.isVisible = false resultResumeSeriesTitle.isVisible = false resultResumeSeriesProgressText.isVisible = false } - resultResumeSeriesButton.isVisible = !resume.isMovie resultResumeSeriesButton.setOnClickListener { - viewModel.handleAction( - EpisodeClickEvent( - storedData.playerAction, //?: ACTION_PLAY_EPISODE_IN_PLAYER, - resume.result - ) - ) + resumeAction(storedData, resume) + } + resultNextSeriesButton.setOnClickListener { + resumeAction(storedData, resume) } } } @@ -1216,6 +1226,18 @@ open class ResultFragmentPhone : FullScreenPlayer() { } } + private fun resumeAction( + storedData: ResultFragment.StoredData, + resume: ResumeWatchingStatus + ) { + viewModel.handleAction( + EpisodeClickEvent( + storedData.playerAction, //?: ACTION_PLAY_EPISODE_IN_PLAYER, + resume.result + ) + ) + } + override fun onPause() { super.onPause() PanelsChildGestureRegionObserver.Provider.get() diff --git a/app/src/main/res/layout/fragment_result.xml b/app/src/main/res/layout/fragment_result.xml index 79f89af25..5b2eb262e 100644 --- a/app/src/main/res/layout/fragment_result.xml +++ b/app/src/main/res/layout/fragment_result.xml @@ -563,11 +563,108 @@ android:visibility="gone" app:icon="@drawable/ic_baseline_add_24" /> + + + + + + + + + + + + + + + + @@ -639,116 +736,6 @@ android:layout_height="match_parent" />--> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Date: Thu, 16 Oct 2025 07:54:37 -0600 Subject: [PATCH 004/513] Make constructor for UpdatedMatroskaExtractor private (#1999) `'internal' declaration exposes 'public/*package*/' type 'EbmlReader'. This will become an error in language version 2.4.` --- .../cloudstream3/ui/player/UpdatedMatroskaExtractor.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/UpdatedMatroskaExtractor.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/UpdatedMatroskaExtractor.kt index 016e7d203..b510491e7 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/UpdatedMatroskaExtractor.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/UpdatedMatroskaExtractor.kt @@ -69,7 +69,7 @@ import kotlin.math.min /** Extracts data from the Matroska and WebM container formats. */ @UnstableApi -class UpdatedMatroskaExtractor internal constructor( +class UpdatedMatroskaExtractor private constructor( private val reader: EbmlReader, flags: @Flags Int, subtitleParserFactory: SubtitleParser.Factory From d84a241026fbd16e66b575611cfedddf3f79cd93 Mon Sep 17 00:00:00 2001 From: firelight <147925818+fire-light42@users.noreply.github.com> Date: Thu, 16 Oct 2025 16:34:27 +0200 Subject: [PATCH 005/513] Feat: Added subtitle alignment setting, and added 400dp elevation closes #2009 --- .../ui/player/CustomSubtitleDecoderFactory.kt | 88 ++++++++++--------- .../ui/subtitles/SubtitlesFragment.kt | 42 +++++++-- app/src/main/res/layout/subtitle_settings.xml | 14 ++- app/src/main/res/values/strings.xml | 11 +++ 4 files changed, 106 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomSubtitleDecoderFactory.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomSubtitleDecoderFactory.kt index dfef0de00..40aff83e1 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomSubtitleDecoderFactory.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomSubtitleDecoderFactory.kt @@ -53,15 +53,15 @@ class CustomDecoder(private val fallbackFormat: Format?) : SubtitleParser { } private const val DEFAULT_MARGIN: Float = 0.05f - private const val SSA_ALIGNMENT_BOTTOM_LEFT = 1 - private const val SSA_ALIGNMENT_BOTTOM_CENTER = 2 - private const val SSA_ALIGNMENT_BOTTOM_RIGHT = 3 - private const val SSA_ALIGNMENT_MIDDLE_LEFT = 4 - private const val SSA_ALIGNMENT_MIDDLE_CENTER = 5 - private const val SSA_ALIGNMENT_MIDDLE_RIGHT = 6 - private const val SSA_ALIGNMENT_TOP_LEFT = 7 - private const val SSA_ALIGNMENT_TOP_CENTER = 8 - private const val SSA_ALIGNMENT_TOP_RIGHT = 9 + const val SSA_ALIGNMENT_BOTTOM_LEFT = 1 + const val SSA_ALIGNMENT_BOTTOM_CENTER = 2 + const val SSA_ALIGNMENT_BOTTOM_RIGHT = 3 + const val SSA_ALIGNMENT_MIDDLE_LEFT = 4 + const val SSA_ALIGNMENT_MIDDLE_CENTER = 5 + const val SSA_ALIGNMENT_MIDDLE_RIGHT = 6 + const val SSA_ALIGNMENT_TOP_LEFT = 7 + const val SSA_ALIGNMENT_TOP_CENTER = 8 + const val SSA_ALIGNMENT_TOP_RIGHT = 9 /** Subtitle offset in milliseconds */ var subtitleOffset: Long = 0 @@ -108,7 +108,7 @@ class CustomDecoder(private val fallbackFormat: Format?) : SubtitleParser { } /** - * Fixes alignment for cues with {\anX}, + * Fixes alignment for cues with {\anX}, * this is common for .vtt that should be parsed as .srt * * ``` @@ -148,37 +148,7 @@ class CustomDecoder(private val fallbackFormat: Format?) : SubtitleParser { // exoplayer can already parse this, however for eg webvtt it fails locationRegex.find(trimmed)?.groupValues?.get(1)?.toIntOrNull()?.let { alignment -> // toLineAnchor - when (alignment) { - SSA_ALIGNMENT_BOTTOM_LEFT, SSA_ALIGNMENT_BOTTOM_CENTER, SSA_ALIGNMENT_BOTTOM_RIGHT -> Cue.ANCHOR_TYPE_END - SSA_ALIGNMENT_MIDDLE_LEFT, SSA_ALIGNMENT_MIDDLE_CENTER, SSA_ALIGNMENT_MIDDLE_RIGHT -> Cue.ANCHOR_TYPE_MIDDLE - SSA_ALIGNMENT_TOP_LEFT, SSA_ALIGNMENT_TOP_CENTER, SSA_ALIGNMENT_TOP_RIGHT -> Cue.ANCHOR_TYPE_START - else -> null - }?.let { anchor -> - setLineAnchor(anchor) - setLine( - computeDefaultLineOrPosition(anchor), Cue.LINE_TYPE_FRACTION - ) - } - // toPositionAnchor - when (alignment) { - SSA_ALIGNMENT_BOTTOM_LEFT, SSA_ALIGNMENT_MIDDLE_LEFT, SSA_ALIGNMENT_TOP_LEFT -> Cue.ANCHOR_TYPE_START - SSA_ALIGNMENT_BOTTOM_CENTER, SSA_ALIGNMENT_MIDDLE_CENTER, SSA_ALIGNMENT_TOP_CENTER -> Cue.ANCHOR_TYPE_MIDDLE - SSA_ALIGNMENT_BOTTOM_RIGHT, SSA_ALIGNMENT_MIDDLE_RIGHT, SSA_ALIGNMENT_TOP_RIGHT -> Cue.ANCHOR_TYPE_END - else -> null - }?.let { anchor -> - setPositionAnchor(anchor) - setPosition(computeDefaultLineOrPosition(anchor)) - } - - // toTextAlignment - when (alignment) { - SSA_ALIGNMENT_BOTTOM_LEFT, SSA_ALIGNMENT_MIDDLE_LEFT, SSA_ALIGNMENT_TOP_LEFT -> Layout.Alignment.ALIGN_NORMAL - SSA_ALIGNMENT_BOTTOM_CENTER, SSA_ALIGNMENT_MIDDLE_CENTER, SSA_ALIGNMENT_TOP_CENTER -> Layout.Alignment.ALIGN_CENTER - SSA_ALIGNMENT_BOTTOM_RIGHT, SSA_ALIGNMENT_MIDDLE_RIGHT, SSA_ALIGNMENT_TOP_RIGHT -> Layout.Alignment.ALIGN_OPPOSITE - else -> null - }?.let { anchor -> - setTextAlignment(anchor) - } + this.setSubtitleAlignment(alignment) } // remove all matches, so we do not display \anx @@ -186,6 +156,42 @@ class CustomDecoder(private val fallbackFormat: Format?) : SubtitleParser { setText(trimmed) return this } + + fun Cue.Builder.setSubtitleAlignment(alignment: Int?): Cue.Builder { + if (alignment == null) return this + when (alignment) { + SSA_ALIGNMENT_BOTTOM_LEFT, SSA_ALIGNMENT_BOTTOM_CENTER, SSA_ALIGNMENT_BOTTOM_RIGHT -> Cue.ANCHOR_TYPE_END + SSA_ALIGNMENT_MIDDLE_LEFT, SSA_ALIGNMENT_MIDDLE_CENTER, SSA_ALIGNMENT_MIDDLE_RIGHT -> Cue.ANCHOR_TYPE_MIDDLE + SSA_ALIGNMENT_TOP_LEFT, SSA_ALIGNMENT_TOP_CENTER, SSA_ALIGNMENT_TOP_RIGHT -> Cue.ANCHOR_TYPE_START + else -> null + }?.let { anchor -> + setLineAnchor(anchor) + setLine( + computeDefaultLineOrPosition(anchor), Cue.LINE_TYPE_FRACTION + ) + } + // toPositionAnchor + when (alignment) { + SSA_ALIGNMENT_BOTTOM_LEFT, SSA_ALIGNMENT_MIDDLE_LEFT, SSA_ALIGNMENT_TOP_LEFT -> Cue.ANCHOR_TYPE_START + SSA_ALIGNMENT_BOTTOM_CENTER, SSA_ALIGNMENT_MIDDLE_CENTER, SSA_ALIGNMENT_TOP_CENTER -> Cue.ANCHOR_TYPE_MIDDLE + SSA_ALIGNMENT_BOTTOM_RIGHT, SSA_ALIGNMENT_MIDDLE_RIGHT, SSA_ALIGNMENT_TOP_RIGHT -> Cue.ANCHOR_TYPE_END + else -> null + }?.let { anchor -> + setPositionAnchor(anchor) + setPosition(computeDefaultLineOrPosition(anchor)) + } + + // toTextAlignment + when (alignment) { + SSA_ALIGNMENT_BOTTOM_LEFT, SSA_ALIGNMENT_MIDDLE_LEFT, SSA_ALIGNMENT_TOP_LEFT -> Layout.Alignment.ALIGN_NORMAL + SSA_ALIGNMENT_BOTTOM_CENTER, SSA_ALIGNMENT_MIDDLE_CENTER, SSA_ALIGNMENT_TOP_CENTER -> Layout.Alignment.ALIGN_CENTER + SSA_ALIGNMENT_BOTTOM_RIGHT, SSA_ALIGNMENT_MIDDLE_RIGHT, SSA_ALIGNMENT_TOP_RIGHT -> Layout.Alignment.ALIGN_OPPOSITE + else -> null + }?.let { anchor -> + setTextAlignment(anchor) + } + return this + } } private var realDecoder: SubtitleParser? = null diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt index b59dd63b6..11303d52b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt @@ -34,18 +34,18 @@ import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent import com.lagradost.cloudstream3.CommonActivity.showToast -import com.lagradost.cloudstream3.databinding.SubtitleSettingsBinding import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.databinding.SubtitleSettingsBinding +import com.lagradost.cloudstream3.ui.player.CustomDecoder +import com.lagradost.cloudstream3.ui.player.CustomDecoder.Companion.setSubtitleAlignment import com.lagradost.cloudstream3.ui.player.OutlineSpan import com.lagradost.cloudstream3.ui.player.RoundedBackgroundColorSpan -import com.lagradost.cloudstream3.ui.settings.Globals.isLayout import com.lagradost.cloudstream3.ui.settings.Globals.TV -import com.lagradost.cloudstream3.ui.settings.nameNextToFlagEmoji +import com.lagradost.cloudstream3.ui.settings.Globals.isLayout import com.lagradost.cloudstream3.utils.DataStore.setKey import com.lagradost.cloudstream3.utils.Event import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog -import com.lagradost.cloudstream3.utils.SubtitleHelper.fromCodeToLangTagIETF import com.lagradost.cloudstream3.utils.SubtitleHelper.languages import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar import com.lagradost.cloudstream3.utils.UIHelper.hideSystemUI @@ -83,6 +83,8 @@ data class SaveCaptionStyle @OptIn(UnstableApi::class) constructor( @JsonProperty("italic") var italic: Boolean = false, /** in px, background radius, aka how round the background (backgroundColor) on each row is **/ @JsonProperty("backgroundRadius") var backgroundRadius: Float? = null, + /** The SSA_ALIGNMENT */ + @JsonProperty("alignment") var alignment: Int? = null, ) const val DEF_SUBS_ELEVATION = 20 @@ -194,7 +196,8 @@ class SubtitlesFragment : DialogFragment() { } } - return this + // 6. set alignment + return this.setSubtitleAlignment(style.alignment) } private fun Context.fromSaveToStyle(data: SaveCaptionStyle): CaptionStyleCompat { @@ -429,7 +432,7 @@ class SubtitlesFragment : DialogFragment() { // tbh this should not be a dialog if it has so many values val elevationTypes = listOf( 0 to textView.context.getString(R.string.none) - ) + (1..30).map { x -> + ) + (1..40).map { x -> val i = x * 10 i to "${i}dp" } @@ -485,6 +488,33 @@ class SubtitlesFragment : DialogFragment() { return@setOnLongClickListener true } + subsSubtitleAlignment.setFocusableInTv() + subsSubtitleAlignment.setOnClickListener { textView -> + val alignmentTypes = listOf( + null to R.string.automatic, + CustomDecoder.SSA_ALIGNMENT_BOTTOM_LEFT to R.string.bottom_left, + CustomDecoder.SSA_ALIGNMENT_BOTTOM_CENTER to R.string.bottom_center, + CustomDecoder.SSA_ALIGNMENT_BOTTOM_RIGHT to R.string.bottom_right, + CustomDecoder.SSA_ALIGNMENT_MIDDLE_LEFT to R.string.middle_left, + CustomDecoder.SSA_ALIGNMENT_MIDDLE_CENTER to R.string.middle_center, + CustomDecoder.SSA_ALIGNMENT_MIDDLE_RIGHT to R.string.middle_right, + CustomDecoder.SSA_ALIGNMENT_TOP_LEFT to R.string.top_left, + CustomDecoder.SSA_ALIGNMENT_TOP_CENTER to R.string.top_center, + CustomDecoder.SSA_ALIGNMENT_TOP_RIGHT to R.string.top_right, + ) + + activity?.showDialog( + alignmentTypes.map { textView.context.getString(it.second) }, + alignmentTypes.map { it.first }.indexOf(state.alignment), + (textView as TextView).text.toString(), + false, + dismissCallback + ) { index -> + state.alignment = alignmentTypes.map { it.first }[index] + textView.context.updateState() + } + } + subsEdgeType.setFocusableInTv() subsEdgeType.setOnClickListener { textView -> val edgeTypes = listOf( diff --git a/app/src/main/res/layout/subtitle_settings.xml b/app/src/main/res/layout/subtitle_settings.xml index ec6709241..bf01e1fab 100644 --- a/app/src/main/res/layout/subtitle_settings.xml +++ b/app/src/main/res/layout/subtitle_settings.xml @@ -130,16 +130,26 @@ android:nextFocusRight="@id/cancel_btt" android:nextFocusUp="@id/subs_edge_type" - android:nextFocusDown="@id/subs_subtitle_elevation" + android:nextFocusDown="@id/subs_subtitle_alignment" android:text="@string/subs_edge_size" /> + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0874e6a12..0ba5599f0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -896,4 +896,15 @@ Reload Provider Name Resolution and name + Subtitle Alignment + + Bottom left + Bottom center + Bottom right + Middle left + Middle center + Middle right + Top left + Top center + Top right From 2e255e6586c2f1d5fe841b1caddbb4d7bf582edc Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Fri, 17 Oct 2025 16:11:38 -0600 Subject: [PATCH 006/513] Use DeprecationLevel.ERROR for some methods (#2017) --- .../kotlin/com/lagradost/cloudstream3/MainAPI.kt | 10 +++++----- .../lagradost/cloudstream3/mvvm/ArchComponentExt.kt | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt index dc208a040..70446fd57 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt @@ -403,7 +403,7 @@ fun newHomePageResponse( list: List, hasNext: Boolean? = null, ): HomePageResponse { - @Suppress("DEPRECATION") + @Suppress("DEPRECATION_ERROR") return HomePageResponse( listOf(HomePageList(name, list)), hasNext = hasNext ?: list.isNotEmpty() @@ -415,7 +415,7 @@ fun newHomePageResponse( list: List, hasNext: Boolean? = null, ): HomePageResponse { - @Suppress("DEPRECATION") + @Suppress("DEPRECATION_ERROR") return HomePageResponse( listOf(HomePageList(data.name, list, data.horizontalImages)), hasNext = hasNext ?: list.isNotEmpty() @@ -423,12 +423,12 @@ fun newHomePageResponse( } fun newHomePageResponse(list: HomePageList, hasNext: Boolean? = null): HomePageResponse { - @Suppress("DEPRECATION") + @Suppress("DEPRECATION_ERROR") return HomePageResponse(listOf(list), hasNext = hasNext ?: list.list.isNotEmpty()) } fun newHomePageResponse(list: List, hasNext: Boolean? = null): HomePageResponse { - @Suppress("DEPRECATION") + @Suppress("DEPRECATION_ERROR") return HomePageResponse(list, hasNext = hasNext ?: list.any { it.list.isNotEmpty() }) } @@ -1139,7 +1139,7 @@ suspend fun newSubtitleFile( * @property hasNext if there is a next page or not. * */ data class HomePageResponse -@Deprecated("Use newHomePageResponse method", level = DeprecationLevel.WARNING) +@Deprecated("Use newHomePageResponse method", level = DeprecationLevel.ERROR) constructor( val items: List, val hasNext: Boolean = false diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt index 04f43dc40..7220393f0 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt @@ -77,9 +77,9 @@ fun logError(throwable: Throwable) { } @Deprecated( - "Outdated function, use `safe` instead when the new stable is released", + "Outdated function, use `safe` instead", ReplaceWith("safe"), - level = DeprecationLevel.WARNING + level = DeprecationLevel.ERROR ) fun normalSafeApiCall(apiCall: () -> T): T? { return try { @@ -113,9 +113,9 @@ suspend fun safeAsync(apiCall: suspend () -> T): T? { } @Deprecated( - "Outdated function, use `safeAsync` instead when the new stable is released", + "Outdated function, use `safeAsync` instead", ReplaceWith("safeAsync"), - level = DeprecationLevel.WARNING + level = DeprecationLevel.ERROR ) suspend fun suspendSafeApiCall(apiCall: suspend () -> T): T? { return try { From 760dea2b4f398860cbefd4fadf18d4822ad2598b Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Fri, 17 Oct 2025 16:12:34 -0600 Subject: [PATCH 007/513] Provider tests: handle if implementing paginated search (#2016) --- .../java/com/lagradost/cloudstream3/utils/TestingUtils.kt | 2 +- app/src/test/java/com/lagradost/cloudstream3/ProviderTests.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/TestingUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/TestingUtils.kt index 049f92fb4..91c8a2fc1 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/TestingUtils.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/TestingUtils.kt @@ -112,7 +112,7 @@ object TestingUtils { val searchResults = testQueries.firstNotNullOfOrNull { query -> try { logger.log("Searching for: $query") - api.search(query).takeIf { !it.isNullOrEmpty() } + api.search(query, 1)?.items?.takeIf { it.isNotEmpty() } } catch (e: Throwable) { if (e is NotImplementedError) { Assert.fail("Provider has not implemented search()") diff --git a/app/src/test/java/com/lagradost/cloudstream3/ProviderTests.kt b/app/src/test/java/com/lagradost/cloudstream3/ProviderTests.kt index 91bdbaf3e..e09e194ef 100644 --- a/app/src/test/java/com/lagradost/cloudstream3/ProviderTests.kt +++ b/app/src/test/java/com/lagradost/cloudstream3/ProviderTests.kt @@ -48,14 +48,14 @@ class ProviderTests { // var searchResult: List? = null // for (query in searchQueries) { // val response = try { -// api.search(query) +// api.search(query, 1) // } catch (e: Exception) { // if (e.cause is NotImplementedError) { // Assert.fail("Provider has not implemented .search") // } // logError(e) // null -// } +// }?.items // if (!response.isNullOrEmpty()) { // correctResponses++ // if (searchResult == null) { From 5bcf4578146482365911842185e408d55e5a7081 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Fri, 17 Oct 2025 16:13:37 -0600 Subject: [PATCH 008/513] Enable auto rotate preference by default (#2014) * Enable auto rotate preference by default It makes sense to adjust the screen orientation based on the orientation of the video by default. * Update callsite also --- .../com/lagradost/cloudstream3/ui/player/FullScreenPlayer.kt | 2 +- app/src/main/res/xml/settings_player.xml | 2 +- 2 files changed, 2 insertions(+), 2 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 bc51775cc..88e136ea5 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 @@ -1812,7 +1812,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() { ) autoPlayerRotateEnabled = settingsManager.getBoolean( ctx.getString(R.string.auto_rotate_video_key), - false + true ) playerResizeEnabled = settingsManager.getBoolean( diff --git a/app/src/main/res/xml/settings_player.xml b/app/src/main/res/xml/settings_player.xml index c953d6d3b..b94e3bb3a 100644 --- a/app/src/main/res/xml/settings_player.xml +++ b/app/src/main/res/xml/settings_player.xml @@ -103,7 +103,7 @@ android:icon="@drawable/screen_rotation" android:summary="@string/auto_rotate_video_desc" android:title="@string/auto_rotate_video" - app:defaultValue="false" + app:defaultValue="true" app:key="@string/auto_rotate_video_key" /> Date: Sat, 18 Oct 2025 18:56:04 +0200 Subject: [PATCH 009/513] Fix: Next player episode and episode list progress issue, Closes #2025 --- .../java/com/lagradost/cloudstream3/ui/player/GeneratorPlayer.kt | 1 + 1 file changed, 1 insertion(+) 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 7a5325afa..282863f53 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 @@ -1996,6 +1996,7 @@ class GeneratorPlayer : FullScreenPlayer() { false, { episodeClick -> if (episodeClick.action == ACTION_CLICK_DEFAULT) { + isNextEpisode = false player.release() playerEpisodeOverlay.isGone = true episodeClick.position?.let { viewModel.loadThisEpisode(it) } From 6dc0d6ed73c2ae9d058211d3297f80c961983f1b Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 18 Oct 2025 12:04:07 -0600 Subject: [PATCH 010/513] Replace use of deprecated Util.SDK_INT (#2030) --- .../lagradost/cloudstream3/ui/player/GeneratorPlayer.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) 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 282863f53..199ed8b97 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 @@ -38,7 +38,6 @@ import androidx.media3.common.Format.NO_VALUE import androidx.media3.common.MimeTypes import androidx.media3.common.Player import androidx.media3.common.util.UnstableApi -import androidx.media3.common.util.Util import androidx.media3.exoplayer.ExoPlayer import androidx.media3.ui.PlayerNotificationManager import androidx.media3.ui.PlayerNotificationManager.EXTRA_INSTANCE_ID @@ -257,11 +256,9 @@ class GeneratorPlayer : FullScreenPlayer() { ): PendingIntent { val intent: Intent = Intent(action).setPackage(context.packageName) intent.putExtra(EXTRA_INSTANCE_ID, instanceId) - val pendingFlags = if (Util.SDK_INT >= 23) { + val pendingFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - } else { - PendingIntent.FLAG_UPDATE_CURRENT - } + } else PendingIntent.FLAG_UPDATE_CURRENT return PendingIntent.getBroadcast(context, instanceId, intent, pendingFlags) } From 7dd650b2360d49fc2ff859791dd726f7c188f340 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 18 Oct 2025 12:06:21 -0600 Subject: [PATCH 011/513] Update some depreciations (#2028) --- .../com/lagradost/cloudstream3/MainAPI.kt | 29 +++++++++++++++---- .../lagradost/cloudstream3/ParCollections.kt | 12 +++++--- .../cloudstream3/mvvm/ArchComponentExt.kt | 4 +-- .../cloudstream3/plugins/BasePlugin.kt | 3 +- .../cloudstream3/utils/SubtitleHelper.kt | 13 +++++---- 5 files changed, 43 insertions(+), 18 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt index 70446fd57..be1412843 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt @@ -1743,7 +1743,8 @@ interface LoadResponse { @Deprecated( "`rating` is the old scoring system, use score instead", - replaceWith = ReplaceWith("score") + replaceWith = ReplaceWith("score"), + level = DeprecationLevel.WARNING ) var rating: Int? set(value) { @@ -1938,12 +1939,20 @@ interface LoadResponse { this.addSimklId(SimklSyncServices.Imdb, id) } - @Deprecated("Outdated API due to misspelling", ReplaceWith("addTraktId(id)")) + @Deprecated( + "Outdated API due to misspelling", + replaceWith = ReplaceWith("addTraktId(id)"), + level = DeprecationLevel.ERROR + ) fun LoadResponse.addTrackId(id: String?) { this.addTraktId(id) } - @Deprecated("Outdated API due to missing capitalization", ReplaceWith("addKitsuId(id)")) + @Deprecated( + "Outdated API due to missing capitalization", + replaceWith = ReplaceWith("addKitsuId(id)"), + level = DeprecationLevel.ERROR + ) fun LoadResponse.addkitsuId(id: String?) { this.addKitsuId(id) } @@ -1971,11 +1980,20 @@ interface LoadResponse { this.score = score } + @Deprecated( + "Use addScore", + replaceWith = ReplaceWith("addScore"), + level = DeprecationLevel.WARNING + ) fun LoadResponse.addRating(text: String?) { this.score = Score.from10(text) } - @Deprecated("Use addScore", replaceWith = ReplaceWith("addScore")) + @Deprecated( + "Use addScore", + replaceWith = ReplaceWith("addScore"), + level = DeprecationLevel.WARNING + ) fun LoadResponse.addRating(value: Int?) { this.score = Score.fromOld(value) } @@ -2677,7 +2695,8 @@ constructor( ) { @Deprecated( "`rating` is the old scoring system, use score instead", - replaceWith = ReplaceWith("score") + replaceWith = ReplaceWith("score"), + level = DeprecationLevel.WARNING ) var rating: Int? set(value) { diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/ParCollections.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/ParCollections.kt index d210708fc..9e6cb99e5 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/ParCollections.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/ParCollections.kt @@ -20,7 +20,8 @@ suspend fun Map.amap(f: suspend (Map.Entry) -> R): Lis */ @Deprecated( "This blocks with runBlocking, and should not be used inside a suspended context", - replaceWith = ReplaceWith("amap(f)", "com.lagradost.cloudstream3.amap") + replaceWith = ReplaceWith("amap(f)", "com.lagradost.cloudstream3.amap"), + level = DeprecationLevel.ERROR ) @Throws(CancellationException::class) fun Map.apmap(f: suspend (Map.Entry) -> R): List = runBlocking { @@ -43,7 +44,8 @@ suspend fun List.amap(f: suspend (A) -> B): List = */ @Deprecated( "This blocks with runBlocking, and should not be used inside a suspended context", - replaceWith = ReplaceWith("amap(f)", "com.lagradost.cloudstream3.amap") + replaceWith = ReplaceWith("amap(f)", "com.lagradost.cloudstream3.amap"), + level = DeprecationLevel.ERROR ) @Throws(CancellationException::class) fun List.apmap(f: suspend (A) -> B): List = runBlocking { @@ -55,7 +57,8 @@ fun List.apmap(f: suspend (A) -> B): List = runBlocking { */ @Deprecated( "This blocks with runBlocking, and should not be used inside a suspended context", - replaceWith = ReplaceWith("amapIndexed(f)", "com.lagradost.cloudstream3.amapIndexed") + replaceWith = ReplaceWith("amapIndexed(f)", "com.lagradost.cloudstream3.amapIndexed"), + level = DeprecationLevel.ERROR ) @Throws(CancellationException::class) fun List.apmapIndexed(f: suspend (index: Int, A) -> B): List = runBlocking { @@ -81,7 +84,8 @@ suspend fun List.amapIndexed(f: suspend (index: Int, A) -> B): List */ @Deprecated( "This blocks with runBlocking, and should not be used inside a suspended context", - replaceWith = ReplaceWith("runAllAsync(transforms)", "com.lagradost.cloudstream3.runAllAsync") + replaceWith = ReplaceWith("runAllAsync(transforms)", "com.lagradost.cloudstream3.runAllAsync"), + level = DeprecationLevel.ERROR ) @Throws(CancellationException::class) fun argamap( diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt index 7220393f0..97aaf357d 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/mvvm/ArchComponentExt.kt @@ -78,7 +78,7 @@ fun logError(throwable: Throwable) { @Deprecated( "Outdated function, use `safe` instead", - ReplaceWith("safe"), + replaceWith = ReplaceWith("safe"), level = DeprecationLevel.ERROR ) fun normalSafeApiCall(apiCall: () -> T): T? { @@ -114,7 +114,7 @@ suspend fun safeAsync(apiCall: suspend () -> T): T? { @Deprecated( "Outdated function, use `safeAsync` instead", - ReplaceWith("safeAsync"), + replaceWith = ReplaceWith("safeAsync"), level = DeprecationLevel.ERROR ) suspend fun suspendSafeApiCall(apiCall: suspend () -> T): T? { diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/plugins/BasePlugin.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/plugins/BasePlugin.kt index c7c0bb82f..c917a55ae 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/plugins/BasePlugin.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/plugins/BasePlugin.kt @@ -51,7 +51,8 @@ abstract class BasePlugin { /** Full file path to the plugin. */ @Deprecated( "Renamed to `filename` to follow conventions", - replaceWith = ReplaceWith("filename") + replaceWith = ReplaceWith("filename"), + level = DeprecationLevel.ERROR ) var __filename: String? get() = filename diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/SubtitleHelper.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/SubtitleHelper.kt index e00337cb1..ddd51891a 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/SubtitleHelper.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/SubtitleHelper.kt @@ -1,6 +1,5 @@ package com.lagradost.cloudstream3.utils -import com.lagradost.cloudstream3.Prerelease import java.util.Locale // If you find a way to use SettingsGeneral getCurrentLocale() @@ -16,7 +15,9 @@ fun getCurrentLocale(): String { object SubtitleHelper { @Deprecated( "Default language code changed to IETF BCP 47 tag", - ReplaceWith("LanguageMetadata(languageName, nativeName, ISO_639_1.ifBlank { ISO_639_2_B }), ISO_639_1, ISO_639_2_B, ISO_639_3, ISO_639_1")) + replaceWith = ReplaceWith("LanguageMetadata(languageName, nativeName, ISO_639_1.ifBlank { ISO_639_2_B }), ISO_639_1, ISO_639_2_B, ISO_639_3, ISO_639_1"), + level = DeprecationLevel.WARNING + ) data class Language639( val languageName: String, val nativeName: String, @@ -104,7 +105,7 @@ object SubtitleHelper { // @Deprecated( // "Default language code changed to IETF BCP 47 tag", - // ReplaceWith("fromLanguageToTagIETF(input, looseCheck)")) + // replaceWith = ReplaceWith("fromLanguageToTagIETF(input, looseCheck)")) /** * Language name (english or native) -> ISO_639_1 * @param input language name @@ -117,7 +118,7 @@ object SubtitleHelper { // @Deprecated( // "Default language code changed to IETF BCP 47 tag", - // ReplaceWith("fromLanguageToTagIETF(input)")) + // replaceWith = ReplaceWith("fromLanguageToTagIETF(input)")) /** * Language name (english or native) -> ISO_639_3 */ @@ -155,7 +156,7 @@ object SubtitleHelper { // @Deprecated( // "Default language code changed to IETF BCP 47 tag", - // ReplaceWith("fromTagToLanguageName(input)")) + // replaceWith = ReplaceWith("fromTagToLanguageName(input)")) /** * Language code -> language english name */ @@ -165,7 +166,7 @@ object SubtitleHelper { // @Deprecated( // "Default language code changed to IETF BCP 47 tag", - // ReplaceWith("fromTagToLanguageName(input)")) + // replaceWith = ReplaceWith("fromTagToLanguageName(input)")) /** * Language code -> language english name */ From 98e6572bab110c016f459033495c3a0ea1a11965 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 18 Oct 2025 12:08:31 -0600 Subject: [PATCH 012/513] Replace deprecated StaticLayout constructor (#2020) --- .../ui/player/RoundedBackgroundColorSpan.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/RoundedBackgroundColorSpan.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/RoundedBackgroundColorSpan.kt index fcc5d8589..824b5d1a2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/RoundedBackgroundColorSpan.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/RoundedBackgroundColorSpan.kt @@ -23,6 +23,7 @@ package com.lagradost.cloudstream3.ui.player import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint +import android.os.Build import android.text.Layout.Alignment import android.text.StaticLayout import android.text.TextPaint @@ -58,9 +59,16 @@ class RoundedBackgroundColorSpan( return } - // we cant use StaticLayout.Builder() due to API val width = p.measureText(text, start, end) - val textLayout = + val textLayout: StaticLayout = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + StaticLayout.Builder + .obtain(text, 0, text.length, TextPaint(p), width.toInt()) + .setAlignment(alignment) + .setLineSpacing(0.0f, 1.0f) + .setIncludePad(true) + .build() + } else { + @Suppress("DEPRECATION") StaticLayout( text, TextPaint(p), @@ -70,6 +78,7 @@ class RoundedBackgroundColorSpan( 0.0f, true ) + } val center = (left + right).toFloat() * 0.5f From 34833d23d06e6b76934cebd5f196c211e324f52d Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 18 Oct 2025 12:10:11 -0600 Subject: [PATCH 013/513] Remove usage of deprecated unsafeCheckOpNoThrow (#2018) --- .../com/lagradost/cloudstream3/utils/UIHelper.kt | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) 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 557bb1ea5..06cdb34b4 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt @@ -495,22 +495,13 @@ object UIHelper { fun Context.hasPIPPermission(): Boolean { val appOps = getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - appOps.unsafeCheckOpNoThrow( - AppOpsManager.OPSTR_PICTURE_IN_PICTURE, - android.os.Process.myUid(), - packageName - ) == AppOpsManager.MODE_ALLOWED - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - @Suppress("DEPRECATION") + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { appOps.checkOpNoThrow( AppOpsManager.OPSTR_PICTURE_IN_PICTURE, android.os.Process.myUid(), packageName ) == AppOpsManager.MODE_ALLOWED - } else { - return true - } + } else true } fun hideKeyboard(view: View?) { From 50e746c51d807f34df1102b44f2d7a0a1944487e Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 18 Oct 2025 12:10:56 -0600 Subject: [PATCH 014/513] Suppress some internal deprecations (#2019) --- .../java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt index 6ea7e6b42..e50c207ce 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt @@ -254,6 +254,7 @@ abstract class AuthAPI { else -> throw NotImplementedError("Unknown inheritance from AuthAPI") } + @Suppress("DEPRECATION") @Deprecated("Please the the new api for AuthAPI", level = DeprecationLevel.WARNING) fun loginInfo(): LoginInfo? { return this.toRepo().authUser()?.let { user -> @@ -267,6 +268,7 @@ abstract class AuthAPI { @Deprecated("Please the the new api for AuthAPI", level = DeprecationLevel.WARNING) suspend fun getPersonalLibrary(): SyncAPI.LibraryMetadata? { + @Suppress("DEPRECATION") return (this.toRepo() as? SyncRepo)?.library()?.getOrThrow() } From fe0475f441c619df4947b00a9ebd124d66d1e5c4 Mon Sep 17 00:00:00 2001 From: firelight <147925818+fire-light42@users.noreply.github.com> Date: Sat, 18 Oct 2025 20:34:05 +0200 Subject: [PATCH 015/513] Fix(UI): Varius highlight/color changes for better accessibility, Closes #2024 --- .../ui/search/SearchResultBuilder.kt | 5 ++ .../main/res/color/black_button_ripple.xml | 5 ++ app/src/main/res/layout/fragment_library.xml | 10 ++-- .../main/res/layout/fragment_library_tv.xml | 52 ++++++++++--------- app/src/main/res/values/styles.xml | 5 +- 5 files changed, 47 insertions(+), 30 deletions(-) create mode 100644 app/src/main/res/color/black_button_ripple.xml diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchResultBuilder.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchResultBuilder.kt index 574481e62..c8f9fbcc1 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchResultBuilder.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchResultBuilder.kt @@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.ui.search import android.annotation.SuppressLint import android.content.Context +import android.content.res.ColorStateList import android.view.View import android.widget.ImageView import android.widget.ProgressBar @@ -25,6 +26,7 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper import com.lagradost.cloudstream3.utils.DataStoreHelper.fixVisual import com.lagradost.cloudstream3.utils.ImageLoader.loadImage import com.lagradost.cloudstream3.utils.SubtitleHelper +import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute import com.lagradost.cloudstream3.utils.getImageFromDrawable object SearchResultBuilder { @@ -324,5 +326,8 @@ object SearchResultBuilder { } boxes[boxes.size - 1].setBackgroundResource(R.drawable.bg_color_bottom) } + textIsDub?.apply { + backgroundTintList = ColorStateList.valueOf(context.colorFromAttribute(R.attr.textColor)) + } } } \ No newline at end of file diff --git a/app/src/main/res/color/black_button_ripple.xml b/app/src/main/res/color/black_button_ripple.xml new file mode 100644 index 000000000..d2a6b6c4d --- /dev/null +++ b/app/src/main/res/color/black_button_ripple.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_library.xml b/app/src/main/res/layout/fragment_library.xml index d49e3d1e7..905cac34a 100644 --- a/app/src/main/res/layout/fragment_library.xml +++ b/app/src/main/res/layout/fragment_library.xml @@ -50,10 +50,10 @@ android:background="?selectableItemBackgroundBorderless" android:contentDescription="@string/change_providers_img_des" android:padding="5dp" - android:visibility="gone" - tools:visibility="visible" android:src="@drawable/ic_baseline_sort_24" - app:tint="?attr/textColor" /> + android:visibility="gone" + app:tint="?attr/textColor" + tools:visibility="visible" /> @@ -159,6 +159,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="40dp"> + diff --git a/app/src/main/res/layout/fragment_library_tv.xml b/app/src/main/res/layout/fragment_library_tv.xml index fcca74bb7..87390284e 100644 --- a/app/src/main/res/layout/fragment_library_tv.xml +++ b/app/src/main/res/layout/fragment_library_tv.xml @@ -36,14 +36,14 @@ android:layout_height="25dp" android:layout_gravity="end|center_vertical" android:layout_marginStart="10dp" - android:padding="2dp" android:background="?selectableItemBackgroundBorderless" android:contentDescription="@string/change_providers_img_des" android:focusable="true" android:nextFocusLeft="@id/navigation_library" android:nextFocusRight="@id/library_sort" - android:tag="@string/tv_no_focus_tag" + android:padding="2dp" android:src="@drawable/ic_baseline_extension_24" + android:tag="@string/tv_no_focus_tag" app:tint="?attr/textColor" /> @@ -116,16 +116,17 @@ android:layout_width="match_parent" android:layout_height="40dp" android:layout_gravity="top" - android:nextFocusDown="@id/search_result_root" android:background="?attr/primaryGrayBackground" - android:paddingHorizontal="5dp" android:focusable="true" + android:nextFocusDown="@id/search_result_root" + android:paddingHorizontal="5dp" app:tabGravity="center" app:tabIndicator="@drawable/indicator_background" app:tabIndicatorColor="?attr/white" app:tabIndicatorGravity="center" app:tabIndicatorHeight="30dp" app:tabMode="scrollable" + app:tabRippleColor="?attr/textColor" app:tabSelectedTextColor="?attr/primaryBlackBackground" app:tabTextAppearance="@style/TabNoCaps" app:tabTextColor="?attr/textColor" /> @@ -136,23 +137,23 @@ android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> - + @@ -162,10 +163,10 @@ android:layout_height="match_parent" android:layout_gravity="center" android:layout_margin="2dp" - app:shimmer_auto_start="true" - app:shimmer_base_alpha="0.2" android:focusable="false" android:tag="@string/tv_no_focus_tag" + app:shimmer_auto_start="true" + app:shimmer_base_alpha="0.2" app:shimmer_duration="@integer/loading_time" app:shimmer_highlight_alpha="0.3"> @@ -174,11 +175,11 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" + android:focusable="false" android:gravity="center" android:horizontalSpacing="10dp" android:numColumns="3" android:paddingBottom="120dp" - android:focusable="false" android:tag="@string/tv_no_focus_tag" android:verticalSpacing="10dp" tools:listitem="@layout/loading_poster_dynamic" /> @@ -190,6 +191,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginBottom="40dp"> + + tools:ignore="ContentDescription" + tools:visibility="visible" /> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 29ab0fcac..6e18c6ed8 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -140,6 +140,9 @@ + + + + + + + + + + + + + + From a95d8ddc781f4e7d99c18d9f05b1e9e227849896 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Mon, 24 Nov 2025 09:53:55 -0700 Subject: [PATCH 154/513] Remove unnecessary overrideLibrary for torrServer (#2235) --- app/src/main/AndroidManifest.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f0ad909f8..2a1709320 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,8 +2,6 @@ - - From 3be396216f659b30823b0d977ffb884a3f5666e9 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Mon, 24 Nov 2025 10:04:51 -0700 Subject: [PATCH 155/513] Remove acra and replace AcraApplication with CloudStreamApp (#2207) --- app/build.gradle.kts | 4 - app/src/main/AndroidManifest.xml | 2 +- .../lagradost/cloudstream3/AcraApplication.kt | 300 ++++-------------- .../lagradost/cloudstream3/CloudStreamApp.kt | 178 +++++++++++ .../lagradost/cloudstream3/CommonActivity.kt | 4 +- .../lagradost/cloudstream3/MainActivity.kt | 6 +- .../cloudstream3/actions/OpenInAppAction.kt | 4 +- .../cloudstream3/actions/temp/VlcPackage.kt | 2 +- .../actions/temp/fcast/FcastAction.kt | 2 +- .../cloudstream3/plugins/PluginManager.kt | 6 +- .../cloudstream3/plugins/RepositoryManager.kt | 6 +- .../cloudstream3/plugins/VotingApi.kt | 6 +- .../syncproviders/AccountManager.kt | 4 +- .../cloudstream3/syncproviders/AuthAPI.kt | 6 +- .../cloudstream3/syncproviders/AuthRepo.kt | 2 +- .../syncproviders/providers/AniListApi.kt | 4 +- .../syncproviders/providers/MALApi.kt | 4 +- .../syncproviders/providers/SimklApi.kt | 12 +- .../cloudstream3/ui/account/AccountHelper.kt | 2 +- .../ui/account/AccountViewModel.kt | 4 +- .../ui/download/DownloadButtonSetup.kt | 4 +- .../ui/download/button/PieFetchButton.kt | 2 +- .../ui/home/HomeParentItemAdapterPreview.kt | 2 +- .../cloudstream3/ui/home/HomeViewModel.kt | 4 +- .../ui/library/LibraryFragment.kt | 6 +- .../ui/library/LibraryViewModel.kt | 4 +- .../cloudstream3/ui/player/CS3IPlayer.kt | 4 +- .../ui/player/DownloadFileGenerator.kt | 2 +- .../cloudstream3/ui/player/GeneratorPlayer.kt | 6 +- .../ui/player/PreviewGenerator.kt | 4 +- .../source_priority/QualityDataHelper.kt | 6 +- .../ui/result/ResultViewModel2.kt | 6 +- .../cloudstream3/ui/search/SearchFragment.kt | 4 +- .../cloudstream3/ui/search/SearchViewModel.kt | 6 +- .../ui/settings/SettingsAccount.kt | 2 +- .../ui/settings/SettingsGeneral.kt | 10 +- .../ui/settings/SettingsProviders.kt | 2 +- .../cloudstream3/ui/settings/SettingsUI.kt | 2 +- .../ui/settings/SettingsUpdates.kt | 8 +- .../extensions/ExtensionsViewModel.kt | 2 +- .../ui/settings/extensions/PluginAdapter.kt | 2 +- .../extensions/PluginDetailsFragment.kt | 2 +- .../ui/settings/utils/DirectoryPicker.kt | 4 +- .../ui/setup/SetupFragmentLanguage.kt | 2 +- .../ui/setup/SetupFragmentLayout.kt | 2 +- .../subtitles/ChromecastSubtitlesFragment.kt | 2 +- .../ui/subtitles/SubtitlesFragment.kt | 4 +- .../cloudstream3/utils/AppContextUtils.kt | 2 +- .../cloudstream3/utils/BackupUtils.kt | 2 +- .../lagradost/cloudstream3/utils/DataStore.kt | 6 +- .../cloudstream3/utils/DataStoreHelper.kt | 19 +- .../utils/DownloadFileWorkManager.kt | 2 +- .../cloudstream3/utils/PackageInstaller.kt | 2 +- .../lagradost/cloudstream3/utils/UIHelper.kt | 2 +- .../utils/VideoDownloadManager.kt | 4 +- .../drawable/ic_baseline_bug_report_24.xml | 5 - .../main/res/layout/fragment_setup_layout.xml | 41 --- app/src/main/res/values-b+af/strings.xml | 1 - app/src/main/res/values-b+am/strings.xml | 1 - app/src/main/res/values-b+apc/strings.xml | 5 - app/src/main/res/values-b+ar/strings.xml | 5 - app/src/main/res/values-b+ars/strings.xml | 4 - app/src/main/res/values-b+as/strings.xml | 5 - app/src/main/res/values-b+az/strings.xml | 2 - app/src/main/res/values-b+bg/strings.xml | 5 - app/src/main/res/values-b+bn/strings.xml | 4 - app/src/main/res/values-b+ckb/strings.xml | 1 - app/src/main/res/values-b+cs/strings.xml | 5 - app/src/main/res/values-b+de/strings.xml | 5 - app/src/main/res/values-b+el/strings.xml | 5 - app/src/main/res/values-b+es/strings.xml | 5 - app/src/main/res/values-b+fa/strings.xml | 4 - app/src/main/res/values-b+fil/strings.xml | 3 - app/src/main/res/values-b+fr/strings.xml | 5 - app/src/main/res/values-b+gl/strings.xml | 4 - app/src/main/res/values-b+hi/strings.xml | 4 - app/src/main/res/values-b+hr/strings.xml | 5 - app/src/main/res/values-b+hu/strings.xml | 5 - app/src/main/res/values-b+in/strings.xml | 5 - app/src/main/res/values-b+it/strings.xml | 5 - app/src/main/res/values-b+iw/strings.xml | 5 - app/src/main/res/values-b+ja/strings.xml | 5 - app/src/main/res/values-b+kn/strings.xml | 1 - app/src/main/res/values-b+ko/strings.xml | 5 - app/src/main/res/values-b+lt/strings.xml | 1 - app/src/main/res/values-b+lv/strings.xml | 5 - app/src/main/res/values-b+mk/strings.xml | 5 - app/src/main/res/values-b+ml/strings.xml | 4 - app/src/main/res/values-b+ms/strings.xml | 5 - app/src/main/res/values-b+mt/strings.xml | 1 - app/src/main/res/values-b+my/strings.xml | 5 - app/src/main/res/values-b+ne/strings.xml | 1 - app/src/main/res/values-b+nl/strings.xml | 5 - app/src/main/res/values-b+nn/strings.xml | 2 - app/src/main/res/values-b+no/strings.xml | 5 - app/src/main/res/values-b+pl/strings.xml | 5 - app/src/main/res/values-b+pt+BR/strings.xml | 5 - app/src/main/res/values-b+pt/strings.xml | 5 - app/src/main/res/values-b+qt/strings.xml | 5 - app/src/main/res/values-b+ro/strings.xml | 5 - app/src/main/res/values-b+ru/strings.xml | 5 - app/src/main/res/values-b+sk/strings.xml | 5 - app/src/main/res/values-b+so/strings.xml | 5 - app/src/main/res/values-b+sv/strings.xml | 5 - app/src/main/res/values-b+ta/strings.xml | 5 - app/src/main/res/values-b+tl/strings.xml | 4 - app/src/main/res/values-b+tr/strings.xml | 5 - app/src/main/res/values-b+uk/strings.xml | 5 - app/src/main/res/values-b+ur/strings.xml | 5 - app/src/main/res/values-b+vi/strings.xml | 5 - app/src/main/res/values-b+zh+TW/strings.xml | 5 - app/src/main/res/values-b+zh/strings.xml | 5 - app/src/main/res/values-ca/strings.xml | 2 - app/src/main/res/values/strings.xml | 7 - app/src/main/res/xml/settings_updates.xml | 7 - gradle/libs.versions.toml | 3 - 116 files changed, 354 insertions(+), 644 deletions(-) create mode 100644 app/src/main/java/com/lagradost/cloudstream3/CloudStreamApp.kt delete mode 100644 app/src/main/res/drawable/ic_baseline_bug_report_24.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 198524374..1a98ac2f3 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -199,10 +199,6 @@ dependencies { // FFmpeg Decoding implementation(libs.bundles.nextlibMedia3) - // Crash Reports (AcraApplication.kt) - implementation(libs.acra.core) - implementation(libs.acra.toast) - // UI Stuff implementation(libs.shimmer) // Shimmering Effect (Loading Skeleton) implementation(libs.palette.ktx) // Palette for Images -> Colors diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2a1709320..9e1bc9ac9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -33,7 +33,7 @@ setKey(path: String, value: T) = + CloudStreamApp.setKey(path, value) - runOnMainThread { // to run it on main looper - safe { - Toast.makeText(context, R.string.acra_report_toast, Toast.LENGTH_SHORT).show() - } - }*/ - } + /*@Deprecated( + message = "AcraApplication is deprecated, use CloudStreamApp instead", + replaceWith = ReplaceWith("com.lagradost.cloudstream3.CloudStreamApp.setKey(folder, path, value)"), + level = DeprecationLevel.WARNING + )*/ + fun setKey(folder: String, path: String, value: T) = + CloudStreamApp.setKey(folder, path, value) + + /*@Deprecated( + message = "AcraApplication is deprecated, use CloudStreamApp instead", + replaceWith = ReplaceWith("com.lagradost.cloudstream3.CloudStreamApp.getKey(path, defVal)"), + level = DeprecationLevel.WARNING + )*/ + inline fun getKey(path: String, defVal: T?): T? = + CloudStreamApp.getKey(path, defVal) + + /*@Deprecated( + message = "AcraApplication is deprecated, use CloudStreamApp instead", + replaceWith = ReplaceWith("com.lagradost.cloudstream3.CloudStreamApp.getKey(path)"), + level = DeprecationLevel.WARNING + )*/ + inline fun getKey(path: String): T? = + CloudStreamApp.getKey(path) + + /*@Deprecated( + message = "AcraApplication is deprecated, use CloudStreamApp instead", + replaceWith = ReplaceWith("com.lagradost.cloudstream3.CloudStreamApp.getKey(folder, path)"), + level = DeprecationLevel.WARNING + )*/ + inline fun getKey(folder: String, path: String): T? = + CloudStreamApp.getKey(folder, path) + + /*@Deprecated( + message = "AcraApplication is deprecated, use CloudStreamApp instead", + replaceWith = ReplaceWith("com.lagradost.cloudstream3.CloudStreamApp.getKey(folder, path, defVal)"), + level = DeprecationLevel.WARNING + )*/ + inline fun getKey(folder: String, path: String, defVal: T?): T? = + CloudStreamApp.getKey(folder, path, defVal) + } } - -class CustomSenderFactory : ReportSenderFactory { - override fun create(context: Context, config: CoreConfiguration): ReportSender { - return CustomReportSender() - } - - override fun enabled(config: CoreConfiguration): Boolean { - return true - } -} - -class ExceptionHandler(val errorFile: File, val onError: (() -> Unit)) : - Thread.UncaughtExceptionHandler { - override fun uncaughtException(thread: Thread, error: Throwable) { - ACRA.errorReporter.handleException(error) - try { - val threadId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) { - thread.threadId() - } else { - @Suppress("DEPRECATION") - thread.id - } - - PrintStream(errorFile).use { ps -> - ps.println("Currently loading extension: ${PluginManager.currentlyLoading ?: "none"}") - ps.println("Fatal exception on thread ${thread.name} (${threadId})") - error.printStackTrace(ps) - } - } catch (ignored: FileNotFoundException) { - } - try { - onError.invoke() - } catch (ignored: Exception) { - } - exitProcess(1) - } -} - -class AcraApplication : Application(), SingletonImageLoader.Factory { - - override fun onCreate() { - super.onCreate() - // if we want to initialise coil at earliest - // (maybe when loading an image or gif using in splash screen activity) - //ImageLoader.buildImageLoader(applicationContext) - - ExceptionHandler(filesDir.resolve("last_error")) { - val intent = context!!.packageManager.getLaunchIntentForPackage(context!!.packageName) - startActivity(Intent.makeRestartActivityTask(intent!!.component)) - }.also { - exceptionHandler = it - Thread.setDefaultUncaughtExceptionHandler(it) - } - } - - override fun attachBaseContext(base: Context?) { - super.attachBaseContext(base) - context = base - - initAcra { - //core configuration: - buildConfigClass = BuildConfig::class.java - reportFormat = StringFormat.JSON - - reportContent = listOf( - ReportField.BUILD_CONFIG, ReportField.USER_CRASH_DATE, - ReportField.ANDROID_VERSION, ReportField.PHONE_MODEL, - ReportField.STACK_TRACE, - ) - - // removed this due to bug when starting the app, moved it to when it actually crashes - //each plugin you chose above can be configured in a block like this: - /*toast { - text = getString(R.string.acra_report_toast) - //opening this block automatically enables the plugin. - }*/ - } - } - - override fun newImageLoader(context: PlatformContext): coil3.ImageLoader { - // Coil Module will be initialized & setSafe globally when first loadImage() is invoked - return ImageLoader.buildImageLoader(applicationContext) - } - - companion object { - var exceptionHandler: ExceptionHandler? = null - - /** Use to get activity from Context */ - tailrec fun Context.getActivity(): Activity? { - return when (this) { - is Activity -> this - is ContextWrapper -> baseContext.getActivity() - else -> null - } - } - - private var _context: WeakReference? = null - var context - get() = _context?.get() - private set(value) { - _context = WeakReference(value) - setContext(WeakReference(value)) - } - - fun getKeyClass(path: String, valueType: Class): T? { - return context?.getKey(path, valueType) - } - - fun setKeyClass(path: String, value: T) { - context?.setKey(path, value) - } - - fun removeKeys(folder: String): Int? { - return context?.removeKeys(folder) - } - - fun setKey(path: String, value: T) { - context?.setKey(path, value) - } - - fun setKey(folder: String, path: String, value: T) { - context?.setKey(folder, path, value) - } - - inline fun getKey(path: String, defVal: T?): T? { - return context?.getKey(path, defVal) - } - - inline fun getKey(path: String): T? { - return context?.getKey(path) - } - - inline fun getKey(folder: String, path: String): T? { - return context?.getKey(folder, path) - } - - inline fun getKey(folder: String, path: String, defVal: T?): T? { - return context?.getKey(folder, path, defVal) - } - - fun getKeys(folder: String): List? { - return context?.getKeys(folder) - } - - fun removeKey(folder: String, path: String) { - context?.removeKey(folder, path) - } - - fun removeKey(path: String) { - context?.removeKey(path) - } - - /** - * If fallbackWebview is true and a fragment is supplied then it will open a webview with the url if the browser fails. - * */ - fun openBrowser(url: String, fallbackWebview: Boolean = false, fragment: Fragment? = null) { - context?.openBrowser(url, fallbackWebview, fragment) - } - - /** Will fallback to webview if in TV layout */ - fun openBrowser(url: String, activity: FragmentActivity?) { - openBrowser( - url, - isLayout(TV or EMULATOR), - activity?.supportFragmentManager?.fragments?.lastOrNull() - ) - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/CloudStreamApp.kt b/app/src/main/java/com/lagradost/cloudstream3/CloudStreamApp.kt new file mode 100644 index 000000000..6421f38c2 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/CloudStreamApp.kt @@ -0,0 +1,178 @@ +package com.lagradost.cloudstream3 + +import android.app.Activity +import android.app.Application +import android.content.Context +import android.content.ContextWrapper +import android.content.Intent +import android.os.Build +import android.widget.Toast +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentActivity +import coil3.ImageLoader +import coil3.PlatformContext +import coil3.SingletonImageLoader +import com.lagradost.api.setContext +import com.lagradost.cloudstream3.mvvm.safe +import com.lagradost.cloudstream3.mvvm.safeAsync +import com.lagradost.cloudstream3.plugins.PluginManager +import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR +import com.lagradost.cloudstream3.ui.settings.Globals.TV +import com.lagradost.cloudstream3.ui.settings.Globals.isLayout +import com.lagradost.cloudstream3.utils.AppContextUtils.openBrowser +import com.lagradost.cloudstream3.utils.Coroutines.runOnMainThread +import com.lagradost.cloudstream3.utils.DataStore.getKey +import com.lagradost.cloudstream3.utils.DataStore.getKeys +import com.lagradost.cloudstream3.utils.DataStore.removeKey +import com.lagradost.cloudstream3.utils.DataStore.removeKeys +import com.lagradost.cloudstream3.utils.DataStore.setKey +import com.lagradost.cloudstream3.utils.ImageLoader.buildImageLoader +import kotlinx.coroutines.runBlocking +import java.io.File +import java.io.FileNotFoundException +import java.io.PrintStream +import java.lang.ref.WeakReference +import java.util.Locale +import kotlin.concurrent.thread +import kotlin.system.exitProcess + +class ExceptionHandler( + val errorFile: File, + val onError: (() -> Unit) +) : Thread.UncaughtExceptionHandler { + + override fun uncaughtException(thread: Thread, error: Throwable) { + try { + val threadId = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA) { + thread.threadId() + } else { + @Suppress("DEPRECATION") + thread.id + } + + PrintStream(errorFile).use { ps -> + ps.println("Currently loading extension: ${PluginManager.currentlyLoading ?: "none"}") + ps.println("Fatal exception on thread ${thread.name} ($threadId)") + error.printStackTrace(ps) + } + } catch (_: FileNotFoundException) { + } + try { + onError() + } catch (_: Exception) { + } + exitProcess(1) + } +} + +@Prerelease +class CloudStreamApp : Application(), SingletonImageLoader.Factory { + + override fun onCreate() { + super.onCreate() + // If we want to initialize Coil as early as possible, maybe when + // loading an image or GIF in a splash screen activity. + // buildImageLoader(applicationContext) + + ExceptionHandler(filesDir.resolve("last_error")) { + val intent = context!!.packageManager.getLaunchIntentForPackage(context!!.packageName) + startActivity(Intent.makeRestartActivityTask(intent!!.component)) + }.also { + exceptionHandler = it + Thread.setDefaultUncaughtExceptionHandler(it) + } + } + + override fun attachBaseContext(base: Context?) { + super.attachBaseContext(base) + context = base + } + + override fun newImageLoader(context: PlatformContext): ImageLoader { + // Coil module will be initialized globally when first loadImage() is invoked. + return buildImageLoader(applicationContext) + } + + companion object { + var exceptionHandler: ExceptionHandler? = null + + /** Use to get Activity from Context. */ + tailrec fun Context.getActivity(): Activity? { + return when (this) { + is Activity -> this + is ContextWrapper -> baseContext.getActivity() + else -> null + } + } + + private var _context: WeakReference? = null + var context + get() = _context?.get() + private set(value) { + _context = WeakReference(value) + setContext(WeakReference(value)) + } + + fun getKeyClass(path: String, valueType: Class): T? { + return context?.getKey(path, valueType) + } + + fun setKeyClass(path: String, value: T) { + context?.setKey(path, value) + } + + fun removeKeys(folder: String): Int? { + return context?.removeKeys(folder) + } + + fun setKey(path: String, value: T) { + context?.setKey(path, value) + } + + fun setKey(folder: String, path: String, value: T) { + context?.setKey(folder, path, value) + } + + inline fun getKey(path: String, defVal: T?): T? { + return context?.getKey(path, defVal) + } + + inline fun getKey(path: String): T? { + return context?.getKey(path) + } + + inline fun getKey(folder: String, path: String): T? { + return context?.getKey(folder, path) + } + + inline fun getKey(folder: String, path: String, defVal: T?): T? { + return context?.getKey(folder, path, defVal) + } + + fun getKeys(folder: String): List? { + return context?.getKeys(folder) + } + + fun removeKey(folder: String, path: String) { + context?.removeKey(folder, path) + } + + fun removeKey(path: String) { + context?.removeKey(path) + } + + /** If fallbackWebView is true and a fragment is supplied then it will open a WebView with the URL if the browser fails. */ + fun openBrowser(url: String, fallbackWebView: Boolean = false, fragment: Fragment? = null) { + context?.openBrowser(url, fallbackWebView, fragment) + } + + /** Will fall back to WebView if in TV or emulator layout. */ + fun openBrowser(url: String, activity: FragmentActivity?) { + openBrowser( + url, + isLayout(TV or EMULATOR), + activity?.supportFragmentManager?.fragments?.lastOrNull() + ) + } + } +} diff --git a/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt index 1e4754869..e4e7c69f4 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt @@ -28,8 +28,8 @@ import androidx.preference.PreferenceManager import com.google.android.gms.cast.framework.CastSession import com.google.android.material.chip.ChipGroup import com.google.android.material.navigationrail.NavigationRailView -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey import com.lagradost.cloudstream3.actions.OpenInAppAction import com.lagradost.cloudstream3.actions.VideoClickActionHolder import com.lagradost.cloudstream3.databinding.ToastBinding diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index cd3fde7f9..42d9c1869 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -65,9 +65,9 @@ import com.jaredrummler.android.colorpicker.ColorPickerDialogListener import com.lagradost.cloudstream3.APIHolder.allProviders import com.lagradost.cloudstream3.APIHolder.apis import com.lagradost.cloudstream3.APIHolder.initAll -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.CommonActivity.loadThemes import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/OpenInAppAction.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/OpenInAppAction.kt index eb6b1f936..ac912cbeb 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/actions/OpenInAppAction.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/OpenInAppAction.kt @@ -6,8 +6,8 @@ import android.content.Context import android.content.Intent import androidx.core.content.FileProvider import androidx.core.net.toUri -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.ui.result.LinkLoadingResult diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/VlcPackage.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/VlcPackage.kt index e1fc22d3c..46b46a2c2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/VlcPackage.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/VlcPackage.kt @@ -6,7 +6,7 @@ import android.content.Intent import android.os.Build import androidx.core.net.toUri import com.lagradost.api.Log -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey import com.lagradost.cloudstream3.actions.OpenInAppAction import com.lagradost.cloudstream3.actions.makeTempM3U8Intent import com.lagradost.cloudstream3.actions.updateDurationAndPosition diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/FcastAction.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/FcastAction.kt index e3916df01..1036a7055 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/FcastAction.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/fcast/FcastAction.kt @@ -1,7 +1,7 @@ package com.lagradost.cloudstream3.actions.temp.fcast import android.content.Context -import com.lagradost.cloudstream3.AcraApplication.Companion.getActivity +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.USER_AGENT import com.lagradost.cloudstream3.actions.VideoClickAction diff --git a/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt b/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt index 1cffa7c1b..1b5d2909c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt @@ -20,11 +20,11 @@ import androidx.fragment.app.FragmentActivity import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.APIHolder import com.lagradost.cloudstream3.APIHolder.removePluginMapping -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.AllLanguagesName import com.lagradost.cloudstream3.AutoDownloadMode +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.MainAPI import com.lagradost.cloudstream3.MainAPI.Companion.settingsForProvider diff --git a/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt b/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt index f8f0ccd7f..45ed65611 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt @@ -2,9 +2,9 @@ package com.lagradost.cloudstream3.plugins import android.content.Context import com.fasterxml.jackson.annotation.JsonProperty -import com.lagradost.cloudstream3.AcraApplication.Companion.context -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.context +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.amap import com.lagradost.cloudstream3.app diff --git a/app/src/main/java/com/lagradost/cloudstream3/plugins/VotingApi.kt b/app/src/main/java/com/lagradost/cloudstream3/plugins/VotingApi.kt index d1b702f4c..930106644 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/plugins/VotingApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/plugins/VotingApi.kt @@ -2,9 +2,9 @@ package com.lagradost.cloudstream3.plugins import android.util.Log import android.widget.Toast -import com.lagradost.cloudstream3.AcraApplication.Companion.context -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.context +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.R import java.security.MessageDigest import com.lagradost.cloudstream3.app diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AccountManager.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AccountManager.kt index 7e796fbd0..93df0fd26 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AccountManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AccountManager.kt @@ -1,7 +1,7 @@ package com.lagradost.cloudstream3.syncproviders -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.LoadResponse import com.lagradost.cloudstream3.syncproviders.providers.Addic7ed import com.lagradost.cloudstream3.syncproviders.providers.AniListApi diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt index e6b155a05..0303e03c6 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt @@ -4,10 +4,10 @@ import android.util.Base64 import androidx.annotation.WorkerThread import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.APIHolder.unixTime -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.ActorData +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.openBrowser +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.ErrorLoadingException import com.lagradost.cloudstream3.LoadResponse diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthRepo.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthRepo.kt index 9444c6367..4ae629ab9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthRepo.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthRepo.kt @@ -1,6 +1,6 @@ package com.lagradost.cloudstream3.syncproviders -import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser +import com.lagradost.cloudstream3.CloudStreamApp.Companion.openBrowser import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.ErrorLoadingException import com.lagradost.cloudstream3.R diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt index a4cd42848..7a46b4113 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt @@ -2,11 +2,11 @@ package com.lagradost.cloudstream3.syncproviders.providers import androidx.annotation.StringRes import com.fasterxml.jackson.annotation.JsonProperty -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.Actor import com.lagradost.cloudstream3.ActorData import com.lagradost.cloudstream3.ActorRole +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.ErrorLoadingException import com.lagradost.cloudstream3.NextAiring import com.lagradost.cloudstream3.R diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt index e8c343519..ba0195be6 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt @@ -2,8 +2,8 @@ package com.lagradost.cloudstream3.syncproviders.providers import androidx.annotation.StringRes import com.fasterxml.jackson.annotation.JsonProperty -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.Score import com.lagradost.cloudstream3.ShowStatus diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt index 9518f5a20..c4095e2d8 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt @@ -4,12 +4,12 @@ import androidx.annotation.StringRes import androidx.core.net.toUri import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.annotation.JsonProperty -import com.lagradost.cloudstream3.AcraApplication -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.getKeys -import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.BuildConfig +import com.lagradost.cloudstream3.CloudStreamApp +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeys +import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.LoadResponse.Companion.readIdFromString import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.Score @@ -96,7 +96,7 @@ class SimklApi : SyncAPI() { fun cleanOldCache() { getKeys(SIMKL_CACHE_KEY)?.forEach { - val isOld = AcraApplication.getKey>(it)?.isFresh() == false + val isOld = CloudStreamApp.getKey>(it)?.isFresh() == false if (isOld) { removeKey(it) } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountHelper.kt index 05253f987..1d6b41e5b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountHelper.kt @@ -21,7 +21,7 @@ import coil3.ImageLoader import coil3.request.ImageRequest import coil3.request.allowHardware import com.google.android.material.bottomsheet.BottomSheetDialog -import com.lagradost.cloudstream3.AcraApplication.Companion.getActivity +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.MainActivity import com.lagradost.cloudstream3.R diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountViewModel.kt index af62a2b08..96eaf52a7 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/account/AccountViewModel.kt @@ -4,8 +4,8 @@ import android.content.Context import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import com.lagradost.cloudstream3.AcraApplication.Companion.context -import com.lagradost.cloudstream3.AcraApplication.Companion.removeKeys +import com.lagradost.cloudstream3.CloudStreamApp.Companion.context +import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKeys import com.lagradost.cloudstream3.MainActivity import com.lagradost.cloudstream3.ui.account.AccountHelper.showPinInputDialog import com.lagradost.cloudstream3.utils.DataStoreHelper diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadButtonSetup.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadButtonSetup.kt index 83e0d0167..e9855ef3a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadButtonSetup.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadButtonSetup.kt @@ -4,8 +4,8 @@ import android.content.DialogInterface import android.net.Uri import androidx.appcompat.app.AlertDialog import com.google.android.material.snackbar.Snackbar -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.getKeys +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeys import com.lagradost.cloudstream3.CommonActivity.activity import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.mvvm.logError diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/button/PieFetchButton.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/button/PieFetchButton.kt index 29c2daa2c..3181a1bcd 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/button/PieFetchButton.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/button/PieFetchButton.kt @@ -12,7 +12,7 @@ import androidx.annotation.MainThread import androidx.core.content.ContextCompat import androidx.core.view.isGone import androidx.core.view.isVisible -import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.ui.download.DOWNLOAD_ACTION_DELETE_FILE 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 042b05f98..e6b82e473 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 @@ -20,7 +20,7 @@ import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.chip.Chip import com.google.android.material.chip.ChipGroup import com.google.android.material.navigation.NavigationBarItemView -import com.lagradost.cloudstream3.AcraApplication.Companion.getActivity +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity import com.lagradost.cloudstream3.CommonActivity.activity import com.lagradost.cloudstream3.HomePageList import com.lagradost.cloudstream3.LoadResponse diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt index bb82ec1a3..b7a322a84 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt @@ -7,8 +7,8 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.lagradost.cloudstream3.APIHolder.apis import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull -import com.lagradost.cloudstream3.AcraApplication.Companion.context -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.context +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey import com.lagradost.cloudstream3.CommonActivity.activity import com.lagradost.cloudstream3.HomePageList import com.lagradost.cloudstream3.LoadResponse 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 c2c226051..c9be2ed5c 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 @@ -24,9 +24,9 @@ import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayoutMediator import com.lagradost.cloudstream3.APIHolder import com.lagradost.cloudstream3.APIHolder.allProviders -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.openBrowser +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.MainActivity import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.SearchResponse diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/library/LibraryViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/library/LibraryViewModel.kt index f7713e9b2..38f7fcf9d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/library/LibraryViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/library/LibraryViewModel.kt @@ -4,8 +4,8 @@ import androidx.annotation.StringRes import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.MainActivity import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.mvvm.Resource diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt index 8a1756e52..b7712cd79 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt @@ -63,8 +63,8 @@ import androidx.media3.exoplayer.trackselection.TrackSelector import androidx.media3.ui.SubtitleView import androidx.preference.PreferenceManager import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.CommonActivity.activity import com.lagradost.cloudstream3.ErrorLoadingException import com.lagradost.cloudstream3.MainActivity.Companion.deleteFileOnExit diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadFileGenerator.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadFileGenerator.kt index 7aac845a5..4c27dbc97 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadFileGenerator.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/DownloadFileGenerator.kt @@ -1,7 +1,7 @@ package com.lagradost.cloudstream3.ui.player import android.net.Uri -import com.lagradost.cloudstream3.AcraApplication.Companion.context +import com.lagradost.cloudstream3.CloudStreamApp.Companion.context import com.lagradost.cloudstream3.CommonActivity.activity import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.ui.player.PlayerSubtitleHelper.Companion.toSubtitleMimeType 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 a0d1e65d4..48353736b 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 @@ -45,10 +45,10 @@ import androidx.media3.ui.PlayerNotificationManager.MediaDescriptionAdapter import androidx.preference.PreferenceManager import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import com.lagradost.cloudstream3.AcraApplication -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.amap import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull +import com.lagradost.cloudstream3.CloudStreamApp +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.databinding.DialogOnlineSubtitlesBinding import com.lagradost.cloudstream3.databinding.FragmentPlayerBinding @@ -931,7 +931,7 @@ class GeneratorPlayer : FullScreenPlayer() { safe { // It lies, it can be null if file manager quits. if (uri == null) return@safe - val ctx = context ?: AcraApplication.context ?: return@safe + val ctx = context ?: CloudStreamApp.context ?: return@safe // RW perms for the path ctx.contentResolver.takePersistableUriPermission( uri, diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PreviewGenerator.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PreviewGenerator.kt index 30e8d99ad..2893bcc47 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PreviewGenerator.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PreviewGenerator.kt @@ -9,7 +9,7 @@ import android.util.Log import androidx.annotation.WorkerThread import androidx.core.graphics.scale import androidx.preference.PreferenceManager -import com.lagradost.cloudstream3.AcraApplication +import com.lagradost.cloudstream3.CloudStreamApp import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.ui.settings.Globals.TV @@ -65,7 +65,7 @@ interface IPreviewGenerator { companion object { fun new(): IPreviewGenerator { - val userDisabled = AcraApplication.context?.let { ctx -> + val userDisabled = CloudStreamApp.context?.let { ctx -> PreferenceManager.getDefaultSharedPreferences(ctx)?.getBoolean( ctx.getString(R.string.preview_seekbar_key), true ) == false diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/source_priority/QualityDataHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/source_priority/QualityDataHelper.kt index 0922bdb5a..467efa68b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/source_priority/QualityDataHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/source_priority/QualityDataHelper.kt @@ -1,9 +1,9 @@ package com.lagradost.cloudstream3.ui.player.source_priority import androidx.annotation.StringRes -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.mvvm.debugAssert import com.lagradost.cloudstream3.utils.UiText 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 5ad8f4f9a..106c05a3c 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 @@ -11,14 +11,14 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.lagradost.cloudstream3.* -import com.lagradost.cloudstream3.AcraApplication.Companion.context -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.actions.AlwaysAskAction import com.lagradost.cloudstream3.actions.VideoClickActionHolder import com.lagradost.cloudstream3.APIHolder.apis import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull import com.lagradost.cloudstream3.APIHolder.unixTime import com.lagradost.cloudstream3.APIHolder.unixTimeMS +import com.lagradost.cloudstream3.CloudStreamApp.Companion.context +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.CommonActivity.activity import com.lagradost.cloudstream3.CommonActivity.getCastSession import com.lagradost.cloudstream3.CommonActivity.showToast @@ -1368,7 +1368,7 @@ class ResultViewModel2 : ViewModel() { // TODO Add skip loading here loadLinks(result, isVisible = true, sourceTypes, isCasting = isCasting) { links -> // Could not find a better way to do this - //val context = AcraApplication.context + //val context = CloudStreamApp.context postPopup( text, links.links.map { txt("${it.name} ${Qualities.getStringByInt(it.quality)}") } 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 8f9793ab6..d1efe6205 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 @@ -26,10 +26,10 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.button.MaterialButton import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull -import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey -import com.lagradost.cloudstream3.AcraApplication.Companion.removeKeys import com.lagradost.cloudstream3.AllLanguagesName import com.lagradost.cloudstream3.AnimeSearchResponse +import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKeys import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.HomePageList import com.lagradost.cloudstream3.MainAPI diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchViewModel.kt index de51ba009..63fb8c10e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchViewModel.kt @@ -5,9 +5,9 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.lagradost.cloudstream3.APIHolder.apis -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.getKeys -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeys +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.HomePageList import com.lagradost.cloudstream3.SearchResponse import com.lagradost.cloudstream3.amap diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsAccount.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsAccount.kt index 0693d0442..53d29cdb8 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsAccount.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsAccount.kt @@ -17,7 +17,7 @@ import androidx.fragment.app.FragmentActivity import androidx.preference.PreferenceManager import androidx.preference.SwitchPreference import androidx.recyclerview.widget.RecyclerView -import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser +import com.lagradost.cloudstream3.CloudStreamApp.Companion.openBrowser import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.ErrorLoadingException diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt index fe2db95ec..e89865fc4 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt @@ -10,9 +10,9 @@ import androidx.core.os.ConfigurationCompat import androidx.preference.PreferenceManager import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.APIHolder.allProviders -import com.lagradost.cloudstream3.AcraApplication -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CloudStreamApp +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.CommonActivity import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.MainActivity @@ -154,7 +154,7 @@ class SettingsGeneral : BasePreferenceFragmentCompat() { ) private val pathPicker = getChooseFolderLauncher { uri, path -> - val context = context ?: AcraApplication.context ?: return@getChooseFolderLauncher + val context = context ?: CloudStreamApp.context ?: return@getChooseFolderLauncher (path ?: uri.toString()).let { PreferenceManager.getDefaultSharedPreferences(context).edit() .putString(getString(R.string.download_path_key), uri.toString()) @@ -317,7 +317,7 @@ class SettingsGeneral : BasePreferenceFragmentCompat() { true, {}) { settingsManager.edit().putInt(getString(R.string.dns_pref), prefValues[it]).apply() - (context ?: AcraApplication.context)?.let { ctx -> app.initClient(ctx) } + (context ?: CloudStreamApp.context)?.let { ctx -> app.initClient(ctx) } } return@setOnPreferenceClickListener true } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsProviders.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsProviders.kt index ddad2070d..8bc3371ea 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsProviders.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsProviders.kt @@ -97,7 +97,7 @@ class SettingsProviders : BasePreferenceFragmentCompat() { selectedList.map { it.toString() }.toMutableSet() ).apply() DataStoreHelper.currentHomePage = null - //(context ?: AcraApplication.context)?.let { ctx -> app.initClient(ctx) } + //(context ?: CloudStreamApp.context)?.let { ctx -> app.initClient(ctx) } } return@setOnPreferenceClickListener true diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUI.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUI.kt index 924e8bc1a..a991f9297 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUI.kt @@ -5,7 +5,7 @@ import android.os.Bundle import android.view.View import androidx.preference.PreferenceManager import androidx.preference.SeekBarPreference -import com.lagradost.cloudstream3.AcraApplication.Companion.getActivity +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity import com.lagradost.cloudstream3.MainActivity import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.SearchQuality diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt index 168ffecea..30cd00470 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt @@ -8,8 +8,8 @@ import androidx.appcompat.app.AlertDialog import androidx.navigation.fragment.findNavController import androidx.preference.PreferenceManager import androidx.recyclerview.widget.LinearLayoutManager -import com.lagradost.cloudstream3.AcraApplication import com.lagradost.cloudstream3.AutoDownloadMode +import com.lagradost.cloudstream3.CloudStreamApp import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.app @@ -56,7 +56,7 @@ class SettingsUpdates : BasePreferenceFragmentCompat() { } private val pathPicker = getChooseFolderLauncher { uri, path -> - val context = context ?: AcraApplication.context ?: return@getChooseFolderLauncher + val context = context ?: CloudStreamApp.context ?: return@getChooseFolderLauncher (path ?: uri.toString()).let { PreferenceManager.getDefaultSharedPreferences(context).edit() .putString(getString(R.string.backup_path_key), uri.toString()) @@ -90,7 +90,7 @@ class SettingsUpdates : BasePreferenceFragmentCompat() { settingsManager.edit() .putInt(getString(R.string.automatic_backup_key), prefValues[index]).apply() BackupWorkManager.enqueuePeriodicWork( - context ?: AcraApplication.context, + context ?: CloudStreamApp.context, prefValues[index].toLong() ) } @@ -250,7 +250,7 @@ class SettingsUpdates : BasePreferenceFragmentCompat() { {}) { num -> settingsManager.edit() .putInt(getString(R.string.auto_download_plugins_key), prefValues[num]).apply() - (context ?: AcraApplication.context)?.let { ctx -> app.initClient(ctx) } + (context ?: CloudStreamApp.context)?.let { ctx -> app.initClient(ctx) } } return@setOnPreferenceClickListener true } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/ExtensionsViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/ExtensionsViewModel.kt index 6d5e2ce27..482251b78 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/ExtensionsViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/ExtensionsViewModel.kt @@ -4,7 +4,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.fasterxml.jackson.annotation.JsonProperty -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.amap import com.lagradost.cloudstream3.mvvm.debugAssert diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginAdapter.kt index c57013c51..47b0b3da3 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginAdapter.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginAdapter.kt @@ -10,7 +10,7 @@ import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView import androidx.viewbinding.ViewBinding -import com.lagradost.cloudstream3.AcraApplication.Companion.getActivity +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity import com.lagradost.cloudstream3.PROVIDER_STATUS_DOWN import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.TvType diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginDetailsFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginDetailsFragment.kt index 1fc10058b..0dcbece6c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginDetailsFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginDetailsFragment.kt @@ -5,7 +5,7 @@ import android.text.format.Formatter.formatFileSize import android.util.Log import android.view.View import androidx.core.view.isVisible -import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser +import com.lagradost.cloudstream3.CloudStreamApp.Companion.openBrowser import com.lagradost.cloudstream3.databinding.FragmentPluginDetailsBinding import com.lagradost.cloudstream3.plugins.PluginManager import com.lagradost.cloudstream3.plugins.VotingApi.canVote diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/utils/DirectoryPicker.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/utils/DirectoryPicker.kt index 9e126b7a6..08a79b4b4 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/utils/DirectoryPicker.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/utils/DirectoryPicker.kt @@ -4,14 +4,14 @@ import android.content.Intent import android.net.Uri import androidx.activity.result.contract.ActivityResultContracts import androidx.fragment.app.Fragment -import com.lagradost.cloudstream3.AcraApplication +import com.lagradost.cloudstream3.CloudStreamApp import com.lagradost.safefile.SafeFile fun Fragment.getChooseFolderLauncher(dirSelected: (uri: Uri?, path: String?) -> Unit) = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri -> // It lies, it can be null if file manager quits. if (uri == null) return@registerForActivityResult - val context = context ?: AcraApplication.context ?: return@registerForActivityResult + val context = context ?: CloudStreamApp.context ?: return@registerForActivityResult // RW perms for the path val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLanguage.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLanguage.kt index 946f7eeae..5ff85c53b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLanguage.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLanguage.kt @@ -6,8 +6,8 @@ import android.widget.ArrayAdapter import androidx.core.content.ContextCompat import androidx.navigation.fragment.findNavController import androidx.preference.PreferenceManager -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.BuildConfig +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.CommonActivity import com.lagradost.cloudstream3.databinding.FragmentSetupLanguageBinding import com.lagradost.cloudstream3.mvvm.safe diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLayout.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLayout.kt index 6c4dfc863..11cc12066 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLayout.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLayout.kt @@ -5,7 +5,7 @@ import android.widget.AbsListView import android.widget.ArrayAdapter import androidx.navigation.fragment.findNavController import androidx.preference.PreferenceManager -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.databinding.FragmentSetupLayoutBinding import com.lagradost.cloudstream3.mvvm.safe diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt index ca7a33d89..4f41b436d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt @@ -18,7 +18,7 @@ import com.google.android.gms.cast.TextTrackStyle.EDGE_TYPE_NONE import com.google.android.gms.cast.TextTrackStyle.EDGE_TYPE_OUTLINE import com.google.android.gms.cast.TextTrackStyle.EDGE_TYPE_RAISED import com.jaredrummler.android.colorpicker.ColorPickerDialog -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent import com.lagradost.cloudstream3.CommonActivity.showToast diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt index 2653e5011..9b0d31212 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt @@ -26,8 +26,8 @@ import androidx.media3.ui.SubtitleView import androidx.preference.PreferenceManager import com.fasterxml.jackson.annotation.JsonProperty import com.jaredrummler.android.colorpicker.ColorPickerDialog -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.CommonActivity.onColorSelectedEvent import com.lagradost.cloudstream3.CommonActivity.onDialogDismissedEvent import com.lagradost.cloudstream3.CommonActivity.showToast diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/AppContextUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/AppContextUtils.kt index 087f09b6d..8334833e4 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/AppContextUtils.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/AppContextUtils.kt @@ -55,8 +55,8 @@ import com.google.android.gms.common.GoogleApiAvailability import com.google.android.gms.common.wrappers.Wrappers import com.google.android.material.bottomsheet.BottomSheetDialog import com.lagradost.cloudstream3.APIHolder.apis -import com.lagradost.cloudstream3.AcraApplication.Companion.getActivity import com.lagradost.cloudstream3.AllLanguagesName +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity import com.lagradost.cloudstream3.CommonActivity.activity import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.DubStatus diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt index 3e22bc65e..1b67fe90c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt @@ -12,7 +12,7 @@ import androidx.fragment.app.FragmentActivity import androidx.preference.PreferenceManager import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.module.kotlin.readValue -import com.lagradost.cloudstream3.AcraApplication.Companion.getActivity +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.mvvm.logError diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt index e33a8f5e6..20d33c112 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt @@ -6,9 +6,9 @@ import androidx.preference.PreferenceManager import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.module.kotlin.kotlinModule -import com.lagradost.cloudstream3.AcraApplication.Companion.getKeyClass -import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey -import com.lagradost.cloudstream3.AcraApplication.Companion.setKeyClass +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeyClass +import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKeyClass import com.lagradost.cloudstream3.mvvm.logError import kotlin.reflect.KClass import kotlin.reflect.KProperty diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt index ddb3c2cbb..217dc2a52 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt @@ -3,13 +3,14 @@ package com.lagradost.cloudstream3.utils import android.content.Context import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.APIHolder.unixTimeMS -import com.lagradost.cloudstream3.AcraApplication -import com.lagradost.cloudstream3.AcraApplication.Companion.context -import com.lagradost.cloudstream3.AcraApplication.Companion.getKey -import com.lagradost.cloudstream3.AcraApplication.Companion.getKeys -import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey -import com.lagradost.cloudstream3.AcraApplication.Companion.removeKeys -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.context +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeyClass +import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeys +import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKeys +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKeyClass import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.DubStatus import com.lagradost.cloudstream3.EpisodeResponse @@ -56,7 +57,7 @@ class UserPreferenceDelegate( private val klass: KClass = default::class private val realKey get() = "${DataStoreHelper.currentAccount}/$key" operator fun getValue(self: Any?, property: KProperty<*>) = - AcraApplication.getKeyClass(realKey, klass.java) ?: default + getKeyClass(realKey, klass.java) ?: default operator fun setValue( self: Any?, @@ -66,7 +67,7 @@ class UserPreferenceDelegate( if (t == null) { removeKey(realKey) } else { - AcraApplication.setKeyClass(realKey, t) + setKeyClass(realKey, t) } } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DownloadFileWorkManager.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DownloadFileWorkManager.kt index 4eeb4e5da..0b9b81e40 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DownloadFileWorkManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DownloadFileWorkManager.kt @@ -7,7 +7,7 @@ import android.os.Build.VERSION.SDK_INT import androidx.work.CoroutineWorker import androidx.work.ForegroundInfo import androidx.work.WorkerParameters -import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.utils.Coroutines.main import com.lagradost.cloudstream3.utils.DataStore.getKey diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/PackageInstaller.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/PackageInstaller.kt index 4be0dd56c..67851f629 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/PackageInstaller.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/PackageInstaller.kt @@ -11,7 +11,7 @@ import android.content.pm.PackageInstaller import android.os.Build import android.util.Log import android.widget.Toast -import com.lagradost.cloudstream3.AcraApplication.Companion.context +import com.lagradost.cloudstream3.CloudStreamApp.Companion.context import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.services.PackageInstallerService 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 ebafd4d75..e114abe29 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt @@ -67,7 +67,7 @@ import com.google.android.material.appbar.AppBarLayout import com.google.android.material.chip.Chip import com.google.android.material.chip.ChipDrawable import com.google.android.material.chip.ChipGroup -import com.lagradost.cloudstream3.AcraApplication.Companion.context +import com.lagradost.cloudstream3.CloudStreamApp.Companion.context import com.lagradost.cloudstream3.CommonActivity.activity import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.R diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadManager.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadManager.kt index 022faeed4..9748bd296 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadManager.kt @@ -32,9 +32,9 @@ import coil3.request.ImageRequest import coil3.request.SuccessResult import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull -import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey -import com.lagradost.cloudstream3.AcraApplication.Companion.setKey import com.lagradost.cloudstream3.BuildConfig +import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey +import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.IDownloadableMinimum import com.lagradost.cloudstream3.MainActivity import com.lagradost.cloudstream3.R diff --git a/app/src/main/res/drawable/ic_baseline_bug_report_24.xml b/app/src/main/res/drawable/ic_baseline_bug_report_24.xml deleted file mode 100644 index dad38dca6..000000000 --- a/app/src/main/res/drawable/ic_baseline_bug_report_24.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/app/src/main/res/layout/fragment_setup_layout.xml b/app/src/main/res/layout/fragment_setup_layout.xml index a742c27b5..18815ced3 100644 --- a/app/src/main/res/layout/fragment_setup_layout.xml +++ b/app/src/main/res/layout/fragment_setup_layout.xml @@ -6,47 +6,6 @@ android:layout_height="match_parent" android:orientation="vertical"> - - Voorskou Agtergrond Speel Fliek Hou in om terug te stel na standaard - Deaktiveer outomatiese foutrapportering %1$dh %2$dm Maak leeg Omtrek kleur diff --git a/app/src/main/res/values-b+am/strings.xml b/app/src/main/res/values-b+am/strings.xml index f1b82c0bd..34b5c3433 100644 --- a/app/src/main/res/values-b+am/strings.xml +++ b/app/src/main/res/values-b+am/strings.xml @@ -109,5 +109,4 @@ ዓይነቶችን በመጠቀም ይፈልጉ ቅርጸ-ቁምፊዎችን በ%s ውስጥ በማስቀመጥ ያጫኑ hide_player_control_names_key - አውቶማቲክ የሳንካ ሪፖርት ማድረግን አሰናክል \ No newline at end of file diff --git a/app/src/main/res/values-b+apc/strings.xml b/app/src/main/res/values-b+apc/strings.xml index 28bfa7e14..e5e184435 100644 --- a/app/src/main/res/values-b+apc/strings.xml +++ b/app/src/main/res/values-b+apc/strings.xml @@ -6,9 +6,7 @@ التنزيلات %1$sالحلقة %2$d محي الملف - سوري، الآپ تعطل. رح ينبعت تقرير عن المشكلة للمطورين %1$d %2$s - بس بعات البيانات وقت ما يتعطل الآپ شوف الخلفية مشّي الفيلم ضلّ كابس لترجع السَتِنگز كيف كانة أول ما نزلتو الآپ @@ -63,7 +61,6 @@ لغة الترجمة لون الخلفية بتسيّڤ تاريخ المشاهدة و لوين وصلت بال ڤيديو - م بتبعت بيانات نبّش… هيدا المصدر مش عاطي \"ميتا داتا\". إزا مش موجودة بال مصدر، م رح يمشي الڤيديو. مافي أجزاء @@ -281,7 +278,6 @@ إشارات المرجعية التنزيل بَلَش فتّو على الأكونت \"%s\" - وقِف الإعلان الأتوماتيكي عن المشاكل يللي بال آپ محل عنوان الپوستر الشكل %1$d ساعة %2$d ديقة @@ -462,7 +458,6 @@ الإفتتاح الجودة وال عنوان شيل الإشتراك - بَلِغ عن الأعطال جودة وصوت ستبدل /؟؟ diff --git a/app/src/main/res/values-b+ar/strings.xml b/app/src/main/res/values-b+ar/strings.xml index 84e1d6321..2e1a4cdba 100644 --- a/app/src/main/res/values-b+ar/strings.xml +++ b/app/src/main/res/values-b+ar/strings.xml @@ -63,7 +63,6 @@ تشغيل الملف متابعة التنزيل إيقاف التنزيل مؤقتًا - قم بتعطيل الإبلاغ عن الأخطاء تلقائيًا مزيد من المعلومات إخفاء تشغيل @@ -143,8 +142,6 @@ معلومات البحث المتقدم يعطيك نتائج البحث مفصولة عن طريق المزود - إرسال البيانات عند الأعطال فقط - لا ترسل أي بيانات عرض حلقات الفلر للأنمي عرض المقاطع الدعائية عرض ملصقات من كيتسو @@ -167,7 +164,6 @@ تم نسخ الرابط إلى الحافظة تشغيل الحلقة إعادة التعيين إلى القيمة الافتراضية - عذرا، تعطل التطبيق. سيتم إرسال تقرير خطأ مجهول إلى المطورين موسم لا موسم حلقة @@ -404,7 +400,6 @@ السابق تخطي الإعداد قم بتغيير مظهر التطبيق ليناسب جهازك - إبلاغ الأعطال ماذا تريد ان تري تم الإضافات diff --git a/app/src/main/res/values-b+ars/strings.xml b/app/src/main/res/values-b+ars/strings.xml index d1efdbbc5..80d348550 100644 --- a/app/src/main/res/values-b+ars/strings.xml +++ b/app/src/main/res/values-b+ars/strings.xml @@ -85,11 +85,9 @@ معلومات التحديثات والنسخ الاحتياطي يعطيك نتائج البحث مفصولة حسب المزود - يرسل فقط البيانات عن الأعطال عرض المقطورات عرض الملصقات من كيتسو حسابات - لا يرسل أي بيانات عرض حلقة حشو للأنمي إخفاء جودة الفيديو المحددة في نتائج البحث تحديثات البرنامج المساعد التلقائي @@ -132,7 +130,6 @@ لا يتمتع هذا المزود بدعم كرومكاست لم يتم العثور على أي روابط تشغيل الحلقة - عذرًا، تعطل التطبيق. سيتم إرسال تقرير خطأ مجهول إلى المطورين %1$s%2$d%3$s لا يوجد موسم حلقة @@ -218,7 +215,6 @@ لون النافذة ارتفاع الترجمة حذف ملف - تعطيل الإبلاغ التلقائي عن الأخطاء بدأ التحديث انسخ بث diff --git a/app/src/main/res/values-b+as/strings.xml b/app/src/main/res/values-b+as/strings.xml index 26d47be69..3a3db9ab6 100644 --- a/app/src/main/res/values-b+as/strings.xml +++ b/app/src/main/res/values-b+as/strings.xml @@ -138,7 +138,6 @@ চাব ফাইল মচক ফাইল প্লে কৰক - স্বয়ংক্ৰিয় বাগ ৰিপ’ৰ্টিং নিষ্ক্ৰিয় কৰক ডাউনলোড পুনৰ আৰম্ভ কৰক ডাউনলোড ৰখা অধিক তথ্য @@ -212,8 +211,6 @@ ব্যাকআপ ফাইল ল\'ড কৰা হৈছে উন্নত সন্ধান আপোনাক প্ৰদানকাৰীৰে পৃথককৃত সন্ধান ফলাফল দিব - কেৱল ভূলৰ ক্ষেত্ৰত ডাটা প্ৰেৰণ কৰে - কোনো ডাটা প্ৰেৰণ নকৰে এনিমেৰ ফিলাৰ খণ্ড দেখুৱাওক ট্ৰেইলাৰ দেখুৱাওক কিৎসুৰ পৰা প\'ষ্টাৰ দেখুৱাওক @@ -234,7 +231,6 @@ এই প্ৰদানকাৰীৰ ক্ৰোমকাষ্ট সমৰ্থন নাই লিংক ক্লিপব\'ৰ্ডত কপিকৰ কৰা হ’ল এপিচ’ড প্লে কৰক - দুখিত, এপ্পটোৰ এক্সিডেণ্ট হৈছে। এজনামবাগ বাগ ৰিপ’ৰ্ট ডেভেলপাৰক পঠোৱা হ’ব চিজন ডিফল্ট মানলৈ পুনৰছেট কৰক %1$s %2$d%3$s @@ -435,7 +431,6 @@ অপ্রয়োজনীয়তাবোৰ সাবটাইটেলৰ পৰা আঁতৰাওক অতিৰিক্ত ট্ৰেইলাৰ - ক্ৰেছৰ ৰিপৰ্টিং https://example.com/example.mp4 পূৰ্বৰ ছেটআপ এৰি দিয়া diff --git a/app/src/main/res/values-b+az/strings.xml b/app/src/main/res/values-b+az/strings.xml index 17ac40a07..430cd4593 100644 --- a/app/src/main/res/values-b+az/strings.xml +++ b/app/src/main/res/values-b+az/strings.xml @@ -87,12 +87,10 @@ Kitabxana Hesablar və Təhlükəsizlik Təkmilləşdirilmiş Axtarış - Məlumat göndərmə Treylerləri göstər Kitsu afişalarını, posterlərini göstər Link mübadilə buferinə nüsxələndi Standart dəyərlərə sıfırla - Üzr istəyirik, tətbiqdə xəta baş verdi. Gizli xəta hesabatı tərtibatçılara göndəriləcək Sezon Dayandır Başlat diff --git a/app/src/main/res/values-b+bg/strings.xml b/app/src/main/res/values-b+bg/strings.xml index ce9d11a2b..2bd90287f 100644 --- a/app/src/main/res/values-b+bg/strings.xml +++ b/app/src/main/res/values-b+bg/strings.xml @@ -67,7 +67,6 @@ Възпроизвеждане на файл Възобновете изтеглянето Пауза на изтеглянето - Деактивирайте автоматичното докладване на грешки Повече информация Скрий Пусни @@ -148,8 +147,6 @@ Информация Подробно търсене Дава ви резултатите от търсенето, разделени по доставчик - Изпраща данни само за сривове - Не изпраща данни Показване заместващ епизод за аниме Показване на трейлъри Покажете плакати от Kitsu @@ -171,7 +168,6 @@ Връзката е копирана в клипборда Пусни епизода Възстановяване на стойността по подразбиране - За съжаление приложението се срина. Анонимен доклад за грешка ще бъде изпратен до разработчиците Сезон %1$s %2$d%3$s Без сезон @@ -390,7 +386,6 @@ Предишен Пропуснете настройката Променете външния вид на приложението, за да отговаря на вашето устройство - Докладване за сривове Какво искате да видите Край Разширения diff --git a/app/src/main/res/values-b+bn/strings.xml b/app/src/main/res/values-b+bn/strings.xml index f1bc8f82a..b21958770 100644 --- a/app/src/main/res/values-b+bn/strings.xml +++ b/app/src/main/res/values-b+bn/strings.xml @@ -62,7 +62,6 @@ সাব ফাইল চালান ডাউনলোড থামান - আটো বাগ রিপোর্ট বন্ধ করুন আরো তথ্য বন্ধ করুন চালান @@ -120,7 +119,6 @@ কালো প্রান্ত অপসারণ করুন অনুসন্ধান করুন অ্যাকাউন্টসমূহ এবং নিরাপত্তা - কোনো উপাত্ত পাঠাবে না বিরতি দিতে মাঝে দুইবার চাপুন সিস্টেম এর উজ্জ্বলতা ব্যবহার করুন ট্রেইলার চালু করুন @@ -150,8 +148,6 @@ প্লেয়ারে এগিয়ে যাওয়ার পরিমাণ (সেকেন্ডে) সামনে বা পিছনের দিকে যেতে ডান বা বাম দিকে দুবার আলতো চাপুন ফাইল ডিলিট - দুঃখিত, অ্যাপ্লিকেশন ক্র্যাশ হয়েছে। ডেভেলপারদের কাছে একটি বেনামী বাগ রিপোর্ট পাঠানো হবে - শুধুমাত্র ক্র্যাশ এর তথ্য পাঠায় মান ডিফল্ট এ রিসেট করুন ফুল রিলিজের পরিবর্তে শুধুমাত্র প্রি-রিলিজ আপডেটের জন্য অনুসন্ধান করুন স্টার্টআপে নতুন আপডেটের জন্য স্বয়ংক্রিয়ভাবে অনুসন্ধান করুন diff --git a/app/src/main/res/values-b+ckb/strings.xml b/app/src/main/res/values-b+ckb/strings.xml index 79941c8e3..c47af36a3 100644 --- a/app/src/main/res/values-b+ckb/strings.xml +++ b/app/src/main/res/values-b+ckb/strings.xml @@ -72,7 +72,6 @@ سڕینەوەی فایل دووبارە دەستپێکردنەوەی دابەزاندن وەستاندنی دابەزاندن - ڕاپۆرتکردنی هەڵە بە شێوەیەکی ئۆتۆماتیکی لەکاربخە زانیاری زیاتر شاردنەوە زانیاری diff --git a/app/src/main/res/values-b+cs/strings.xml b/app/src/main/res/values-b+cs/strings.xml index e848582d3..70b740079 100644 --- a/app/src/main/res/values-b+cs/strings.xml +++ b/app/src/main/res/values-b+cs/strings.xml @@ -65,7 +65,6 @@ Přehrát soubor Pokračovat ve stahování Pozastavit stahování - Zakázat automatické nahlašování chyb Více informací Skrýt Přehrát @@ -144,8 +143,6 @@ Informace Pokročilé hledání Zobrazí vám výsledky hledání oddělené poskytovatelem - Odešle data pouze při pádech - Nebude odesílat žádná data Zobrazit výplňové epizody u anime Zobrazit aktualizace aplikace Při spuštění aplikace automaticky zkontrolovat nové aktualizace. @@ -163,7 +160,6 @@ Odkaz zkopírován do schránky Přehrát epizodu Obnovit na výchozí hodnoty - Omlouváme se, aplikace spadla. Vývojářům bude odesláno anonymní hlášení o pádu Sezóna Žádná sezóna Epizoda @@ -425,7 +421,6 @@ NovýNázevWebu Povolit NSFW u podporovaných rozšíření Poskytovatelé - Hlášení pádů Předchozí Změnit vzhled aplikace tak, aby vám vyhovoval Co chcete vidět diff --git a/app/src/main/res/values-b+de/strings.xml b/app/src/main/res/values-b+de/strings.xml index 8d85c8448..fb4066d01 100644 --- a/app/src/main/res/values-b+de/strings.xml +++ b/app/src/main/res/values-b+de/strings.xml @@ -78,7 +78,6 @@ Datei abspielen Download fortsetzen Download pausieren - Automatische Fehlerberichtserstattung deaktivieren Mehr Infos Verstecken Abspielen @@ -155,8 +154,6 @@ Info Erweiterte Suche Liefert die Suchergebnisse getrennt nach Anbietern - Sendet Daten nur bei Abstürzen - Sendet keine Daten Füller-Episoden für Animes anzeigen Trailer anzeigen Vorschaubilder von Kitsu anzeigen @@ -177,7 +174,6 @@ Link in die Zwischenablage kopiert Episode abspielen Auf Standardwert zurücksetzen - Sorry, die Anwendung ist abgestürzt. Ein anonymer Fehlerbericht wird an die Entwickler gesendet Staffel Keine Staffel Episode @@ -385,7 +381,6 @@ Vorherige Einrichtung überspringen Aussehen der App passend zu dem des Geräts ändern - Absturzmeldung Was möchten Sie sehen Fertig Erweiterungen diff --git a/app/src/main/res/values-b+el/strings.xml b/app/src/main/res/values-b+el/strings.xml index 933d8b53c..9c6eb86a2 100644 --- a/app/src/main/res/values-b+el/strings.xml +++ b/app/src/main/res/values-b+el/strings.xml @@ -42,8 +42,6 @@ Αναπαραγωγή αρχείου Συνέχιση λήψης Παύση λήψης - Λυπόμαστε, η εφαρμογή κατέρρευσε. Μια ανώνυμη αναφορά σφαλμάτων θα σταλεί στους προγραμματιστές - Απενεργοποιήστε την αυτόματη αναφορά σφαλμάτων Εμφάνιση Logcat 🐈 Περαιτέρω πληροφορίες Απόκρυψη @@ -102,8 +100,6 @@ Πληροφορίες Προχωρημένη Αναζήτηση Δίνει τα αποτελέσματα αναζήτησης ταξινομημένα ανά πάροχο - Αποστέλλει δεδομένα μόνο για καταρρεύσεις - Δεν στέλνει δεδομένα Εμφάνιση ενημερώσεων Αυτόματη αναζήτηση νέων ενημερώσεων κατά την εκκίνηση της εφαρμογής. Ενημέρωση σε προ-εκδόσεις (beta) @@ -307,7 +303,6 @@ Προηγούμενο Παράλειψη διαμόρφωσης της εφαρμογής Αλλαγή της εμφάνισης της συσκευής για να ταιριάζει με την συσκευή σας - Αναφορά κατάρρευσης Τι θα θέλατε να δείτε Έγινε Extensions diff --git a/app/src/main/res/values-b+es/strings.xml b/app/src/main/res/values-b+es/strings.xml index b5cadb42b..220f88ea3 100644 --- a/app/src/main/res/values-b+es/strings.xml +++ b/app/src/main/res/values-b+es/strings.xml @@ -223,8 +223,6 @@ Información Búsqueda Avanzada Mostrar los resultados de la búsqueda por proveedor - Solo envíar los datos si la App se cierra / falla inesperadamente - No enviar datos Mostrar avances Mostrar pósters de Kitsu Actualizar a las versiones preliminares @@ -239,7 +237,6 @@ Enlaces no encontrados Enlaces copiados al portapapeles Reiniciar a valores predefinidos - Lo sentimos, la aplicación se bloqueó. Se enviará un informe de error anónimo a los desarrolladores Temporada %1$s %2$d%3$s Ninguna Temporada @@ -286,7 +283,6 @@ Mostrar actualizaciones de la aplicación Instalador de APK Algunos dispositivos no soportan el nuevo instalador de paquetes. Pruebe la opción antigua (legacy) si las actualizaciones no se instalan. - Desactivar reporte automático de bugs Sincronizar automáticamente el progreso de su episodio actual Actualización automática de plugins Características del reproductor @@ -467,7 +463,6 @@ Instalando actualización de la aplicación… No se pudo instalar la nueva versión de la aplicación App no encontrada - Reporte de fallos Plugin Borrado No puede cargar %s Descripción diff --git a/app/src/main/res/values-b+fa/strings.xml b/app/src/main/res/values-b+fa/strings.xml index 2e348017c..496373cdd 100644 --- a/app/src/main/res/values-b+fa/strings.xml +++ b/app/src/main/res/values-b+fa/strings.xml @@ -55,7 +55,6 @@ زیرنویس‌ها حذف دانلود آغاز شد - غیرفعال کردن گذارش باگ خودکار پاک کردن به‌روزرسانی آغاز شد کپی @@ -308,8 +307,6 @@ به‌روزرسانی پیشرفت ساعت شروع کنید به صحبت کردن… جواب سرچ های شما با تامین کننده - فقط درصورت کرش اطلاعات فرستاده می شوند - هیچ اطلاعاتی (دیتایی) فرستاده نمی شود نشان دادن آپدیت های برنامه دوباره پروسه راه اندازی را انجام بده نسخه های پیشین را آپدیت کن @@ -317,7 +314,6 @@ برنامه سبک رمان از توسعه دهندگان یکسان برنامه انیمه از توسعه دهندگان یکسان این ارائه دهنده هیچ پشتیبانی از کروم کست ندارد - متأسفیم، برنامه کرش کرد. یک گزارش از این باگ بطور ناشناس به توسعه دهندگان فرستاده می‌شود با شکست مواجه شد اخطار امتیاز diff --git a/app/src/main/res/values-b+fil/strings.xml b/app/src/main/res/values-b+fil/strings.xml index dbea6c62f..7ea370852 100644 --- a/app/src/main/res/values-b+fil/strings.xml +++ b/app/src/main/res/values-b+fil/strings.xml @@ -40,7 +40,6 @@ Available para mapanood offline Piliin Lahat Alisin sa pagkakapili ang Lahat - Huwag paganahin ang awtomatikong pag-uulat ng bug Maaaring kailanganin ng VPN para gumana ang provider na ito Ang provider na ito ay isang torrent, inirerekomendang gumamit ng VPN Ang metadata ay hindi ibinigay ng site, hindi gagana ang video kung wala ito sa site. @@ -51,8 +50,6 @@ Awtomatikong i-sync ang iyong kasalukuyang episode Nawawala ang mga pahintulot sa storage. Pakisubukang muli. Binibigyan ka ng mga resulta ng paghahanap na pinaghihiwalay ng provider - Nagpapadala lamang ng data sa mga pag-crash - Hindi nagpapadala ng data Itago ang napiling quality ng video sa mga resulta ng paghahanap Pumili ng mode upang i-filter ang pag-download ng mga plugin Awtomatikong i-install ang lahat ng hindi pa naka-install na plugin mula sa mga idinagdag na repository. diff --git a/app/src/main/res/values-b+fr/strings.xml b/app/src/main/res/values-b+fr/strings.xml index c8b971a5b..f7b638f0b 100644 --- a/app/src/main/res/values-b+fr/strings.xml +++ b/app/src/main/res/values-b+fr/strings.xml @@ -47,7 +47,6 @@ Lire le fichier Reprendre le téléchargement Mettre en pause le téléchargement - Désactiver le rapport de bug automatique Plus d\'information Cacher Affiche principale @@ -69,7 +68,6 @@ Lien copié dans le presse-papier Lecture de l\'episode Réinitialiser aux valeurs par défault - Désolé, l\'application à crashé. Un rapport de bug anonyme va être envoyé aux développeurs Saison Pas de Saison Épisode @@ -282,8 +280,6 @@ Info Recherche avancée Vous donne les résultats de la recherche séparés par fournisseur - Envoi de données uniquement en cas d\'accident - N\'envoie aucune donnée Afficher les épisodes spéciaux pour les animés Montrer les bandes-annonces Montrer les affiches provenant de Kitsu @@ -435,7 +431,6 @@ Certains téléphones ne supporte pas le nouvel installateur d\'application. Essayez l\'option de l\'ancien installateur si les mises-à-jour ne s\'installe pas. Précédent Ignorer la configuration - Rapport de crash Nom de dépôt (optionnel) plugin Supprimer le repository diff --git a/app/src/main/res/values-b+gl/strings.xml b/app/src/main/res/values-b+gl/strings.xml index d5a88bcec..263a2acc3 100644 --- a/app/src/main/res/values-b+gl/strings.xml +++ b/app/src/main/res/values-b+gl/strings.xml @@ -76,7 +76,6 @@ Reproducir Arquivo Continuar Descarga Pausar Descarga - Desactivar reporte automático de bugs Máis información Agochar Reproducir @@ -153,8 +152,6 @@ Subtítulos Sincronizar automáticamente o progreso do episodio actual Use o brillo do sistema no reprodutor da aplicación en lugar dunha superposición oscura - Só envía datos se a aplicacción falla inesperadamente - Non enviar datos Mostrar episodio de recheo para Anime Mostrar Trailers Mostrar pósters de Kitsu @@ -278,7 +275,6 @@ Ligazóns non atopadas Ligazón copiada ó portapapeis Reproducir capítulo - O sentimos, o aplicativo bloqueouse. Enviarase un informe de error anónimo aos desenvolvedores Temporada Capítulos diff --git a/app/src/main/res/values-b+hi/strings.xml b/app/src/main/res/values-b+hi/strings.xml index 3d2216816..453718af9 100644 --- a/app/src/main/res/values-b+hi/strings.xml +++ b/app/src/main/res/values-b+hi/strings.xml @@ -40,7 +40,6 @@ फ़ाइल चलाएं डाउनलोड फिर शुरू करें डाउनलोड रोकें - स्वचालित बग रिपोर्टिंग अक्षम करें और जानकारी छिपाएं चलाएं @@ -72,8 +71,6 @@ खोजें जानकारी खोज नतीजों को प्रोवाइडरों के हिसाब से अलग-अलग आपको दिखाता है - केवल क्रैश पर जानकारी भेजी जाएगी - आपकी जानकारी नहीं भेजी जाएगी हर बार एप खुलने पर स्वचालित रूप से नए अपडेट खोजें। केवल पूर्ण रिलीज़ के बजाय प्रीरिलीज़ अपडेट खोजें उन्हीं डेवलपर्स द्वारा Light novel ऐप @@ -86,7 +83,6 @@ कोई लिंक नहीं मिले लिंक क्लिपबोर्ड पर कॉपी किया गया एपिसोड चलायें - क्षमा करें, एप्प क्रैश हो गया है । निर्माताओं को एक अनाम बग रिपोर्ट भेजी जाएगी फ़ाइल डिलीट करें डिलीट रद्द करें diff --git a/app/src/main/res/values-b+hr/strings.xml b/app/src/main/res/values-b+hr/strings.xml index f65765e7e..b34a691f7 100644 --- a/app/src/main/res/values-b+hr/strings.xml +++ b/app/src/main/res/values-b+hr/strings.xml @@ -80,7 +80,6 @@ Pokreni datoteku Nastavi preuzimanje Pauziraj preuzimanje - Onemogući automatsko izvješćivanje o greškama Više informacija Sakrij Pokreni @@ -161,8 +160,6 @@ Informacije Napredna pretraga Daje rezultate pretrage odvojene prema pružatelju usluga - Šalje samo podatke o padovima aplikacije - Ne šalje podatke Prikaži dodatnu epizodu za anime Prikaži trailere Prikaži postere iz Kitsua @@ -184,7 +181,6 @@ Poveznica je kopirana u međuspremnik Pokreni epizodu Vrati na zadanu vrijednost - Nažalost se aplikacija srušila. Anonimno izvješće o grešci će se poslati programerima Sezona Nema sezone Epizoda @@ -405,7 +401,6 @@ Prethodno Preskoči postavljanje Promijeni izgled aplikacije kako bi odgovarao tvom uređaju - Izvještavanje o rušenju Što želiš vidjeti Gotovo Proširenja diff --git a/app/src/main/res/values-b+hu/strings.xml b/app/src/main/res/values-b+hu/strings.xml index 02a07a3f6..593f1dc12 100644 --- a/app/src/main/res/values-b+hu/strings.xml +++ b/app/src/main/res/values-b+hu/strings.xml @@ -80,7 +80,6 @@ Fájl lejátszása Letöltés folytatása Letöltés szüneteltetése - Automatikus hibajelentés kikapcsolása Több információ Elrejtés Lejátszás @@ -188,7 +187,6 @@ Hiba a biztonsági mentés során %s Fiókok és Biztonság Szolgáltató szerint elkülönítve adja meg a keresési eredményeket - Nem küld adatokat Poszterek megjelenítése Kitsu-ról Kiválasztott videóminőségek elrejtése keresési eredményekbe Automatikus bővítményfrissítések @@ -206,7 +204,6 @@ A link vágólapra másolva Epizód lejátszása Alapértelmezett értékre visszaállítása - Az alkalmazás összeomlott. Egy névtelen hibabejelentés küldünk a fejlesztőknek Évad %1$s %2$d%3$s Nincs évad @@ -253,7 +250,6 @@ Frissítés elkezdődött Nem sikerült visszaállítani az adatokat a %s fájlból Tárolási engedélyek hiányoznak. Kérjük próbálja újra. - Csak összeomlásokról küld adatokat APK Telepítő Egyes telefonok nem támogatják az új csomag telepítőt. Ha a frissítések nem települnek, próbálja meg a régi opciót. Banán adva @@ -405,7 +401,6 @@ Betöltés fájlból HDR Az alkalmazás megjelenésének módosítása, hogy az megfeleljen az eszközödnek - Összeomlás jelentése Nyilvános lista Állapot Összefoglaló diff --git a/app/src/main/res/values-b+in/strings.xml b/app/src/main/res/values-b+in/strings.xml index 592653734..404b6ae65 100644 --- a/app/src/main/res/values-b+in/strings.xml +++ b/app/src/main/res/values-b+in/strings.xml @@ -63,7 +63,6 @@ Putar Berkas Lanjutkan Unduh Jeda Unduh - Nonaktifkan pelaporan bug otomatis Lebih banyak info Sembunyikan Putar @@ -141,8 +140,6 @@ Info Pencarian Lanjutan Memberikan hasil pencarian yang dipisahkan berdasarkan penyedia - Hanya mengirim data saat ngecrash - Tidak mengirim data Tampilkan episode filler untuk anime Tampilkan update aplikasi Secara otomatis mencari update terbaru setelah aplikasi dibuka. @@ -160,7 +157,6 @@ Tautan disalin ke papan klip Putar Episode Ulang ke pengaturan default - Maaf, aplikasi ngecrash. Laporan bug anonim akan dikirim ke developer Season Tidak Ada Season Episode @@ -453,7 +449,6 @@ Selanjutnya Sebelumnya Ubah tampilan aplikasi - Laporkan Crash Selesai Ekstensi Hapus Repositori diff --git a/app/src/main/res/values-b+it/strings.xml b/app/src/main/res/values-b+it/strings.xml index ac24a39d2..0c59b494b 100644 --- a/app/src/main/res/values-b+it/strings.xml +++ b/app/src/main/res/values-b+it/strings.xml @@ -70,7 +70,6 @@ Riproduci file Riprendi download Ferma download - Disabilita segnalazione automatica di bug Più info Nascondi Riproduci @@ -151,8 +150,6 @@ Info Ricerca avanzata Dividi i risultati della ricerca per provider - Invia i dati solo in caso di crash - Non inviare alcun dato Mostra tag [filler] per anime Mostra trailer Mostra poster da Kitsu @@ -174,7 +171,6 @@ Link copiato negli appunti Riproduci episodio Ripristina il valore predefinito - Spiacente, l\'applicazione è andata in crash. Una segnalazione anonima di bug sarà inviata agli sviluppatori Stagione %1$s %2$d%3$s Nessuna stagione @@ -395,7 +391,6 @@ Precedente Salta configurazione Cambia l\'aspetto dell\'app per adattarla al proprio dispositivo - Segnala crash Cosa vuoi vedere Fatto Estensioni diff --git a/app/src/main/res/values-b+iw/strings.xml b/app/src/main/res/values-b+iw/strings.xml index 037286ce1..ed83fcb8d 100644 --- a/app/src/main/res/values-b+iw/strings.xml +++ b/app/src/main/res/values-b+iw/strings.xml @@ -58,7 +58,6 @@ נגן קובץ המשך הורדה השהה את ההורדה - השבת את דיווח הבאגים האוטומטי נגן מידע סנן סימניות @@ -191,7 +190,6 @@ עדכוני תוספים אוטומטיים כמות בנינים שניתנו עונה - מצטערים, האפליקציה קרסה. דוח באג אנונימי יישלח למפתחים טורנטים NSFW שגיאת מעבד @@ -283,8 +281,6 @@ חשבונות ובטיחות לא ניתנו בנינים מהירות ניגון - שולח נתונים רק בקריסות - לא שולח נתונים הצג טריילרים הצג פוסטרים מKitsu הסתר את איכות הסרטון שנבחרה בתוצאות החיפוש @@ -413,7 +409,6 @@ צפה בסרטונים בשפות אלה קודם שנה את מראה האפליקציה כך שיתאים למכשירך - דיווח על קריסה סוים הרחבות הוסף מאגר diff --git a/app/src/main/res/values-b+ja/strings.xml b/app/src/main/res/values-b+ja/strings.xml index 107c14434..12de7a8fc 100644 --- a/app/src/main/res/values-b+ja/strings.xml +++ b/app/src/main/res/values-b+ja/strings.xml @@ -213,7 +213,6 @@ リンクの読み込みエラー 137905 リンクがリロードされました - 自動バグ報告を無効にする プレーヤーの速度 字幕設定 ダブ @@ -238,7 +237,6 @@ hide_player_control_names_key ブックマークのフィルタ プロットが見つかりません - データを送信しない ダブルタップで一時停止 トレーラーを表示 GitHub プロキシ @@ -315,7 +313,6 @@ アプリ起動後に自動的に更新を探します。 プレリリースにアップデート 初期値にリセット - 残念ながらアプリがクラッシュしました。匿名のバグ報告が開発者に送信されます %1$d %2$s エピソードが見つかりません アプリのテーマ @@ -565,12 +562,10 @@ 凹んだ QRコード画像 前へ - クラッシュレポート 表示したいもの %1$d %2$s をダウンロードしました プロフィールをロック パスワード/PIN認証 - クラッシュ時のみデータを送信 検索結果で選択したビデオ品質を非表示 追加されたリポジトリから未インストールのすべてのプラグインを自動的にインストールします。 セットアッププロセスを再実行 diff --git a/app/src/main/res/values-b+kn/strings.xml b/app/src/main/res/values-b+kn/strings.xml index 8be5a737b..fcfaa9045 100644 --- a/app/src/main/res/values-b+kn/strings.xml +++ b/app/src/main/res/values-b+kn/strings.xml @@ -26,7 +26,6 @@ ಇಂಟರ್ನಲ್ ಸ್ಟೋರೇಜ್ ಡಬ್ ಸಬ್ - ಸ್ವಯಂಚಾಲಿತ ದೋಷ ವರದಿಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿ ಹೈಡ್ ಪ್ಲೇ ಮಾಹಿತಿ diff --git a/app/src/main/res/values-b+ko/strings.xml b/app/src/main/res/values-b+ko/strings.xml index 9ac7e1185..7ec22c991 100644 --- a/app/src/main/res/values-b+ko/strings.xml +++ b/app/src/main/res/values-b+ko/strings.xml @@ -48,7 +48,6 @@ 파일 재생 계속 다운로드 다운로드 일시정지 - 자동 오류 보고 비활성화 상세 정보 닫기 재생 @@ -156,7 +155,6 @@ 클립보드에 링크 복사됨 에피소드 재생 기본값으로 재설정 - 죄송합니다, 애플리케이션이 충돌했습니다. 버그 보고서가 익명으로 개발자에게 전송됩니다 에피소드 %1$d-%2$d 진행중 @@ -329,14 +327,12 @@ Picture-in-picture 플레이어 크기 조정 버튼 다른 앱 위에 있는 미니어처 플레이어에서 재생을 계속합니다 - 충돌에 관한 데이터만 전송 검은색 테두리 제거 오른쪽 또는 왼쪽을 두 번 탭하여 앞뒤로 탐색하기 자막 로드된 백업 파일 정보 고급 검색 - 데이터를 보내지 않습니다 설정 프로세스 다시 실행 APK 인스톨러 Github @@ -424,7 +420,6 @@ 플레이어 HDR TC - 충돌 보고 완료 다운로드되지 않음: %d HQ diff --git a/app/src/main/res/values-b+lt/strings.xml b/app/src/main/res/values-b+lt/strings.xml index cc68d77eb..6493e33e2 100644 --- a/app/src/main/res/values-b+lt/strings.xml +++ b/app/src/main/res/values-b+lt/strings.xml @@ -9,7 +9,6 @@ Sekantis atsitiktinai Peržiūros fonas Paleisti filmą - Išjungti automatini klaidų pateikimą Atstatyti į numatytą reikšmę Išvalyti Plakatas diff --git a/app/src/main/res/values-b+lv/strings.xml b/app/src/main/res/values-b+lv/strings.xml index cd981810e..bff199dfb 100644 --- a/app/src/main/res/values-b+lv/strings.xml +++ b/app/src/main/res/values-b+lv/strings.xml @@ -56,7 +56,6 @@ Palaist failu Atsākt ielādi Pauzēt ielādi - Atslēgt automātisko kļūdu ziņošanu Vairāk informācijas Slēpt Atskaņot @@ -153,8 +152,6 @@ Informācija Advancēta meklēšana Dod tev meklēšanas rezultātus citus no devēja - Tikai sūtīt datus no kļudām - Nesutīt datus Radīt fillera epizodi priekš animē Radīt feel Radīt plakātu no kitsu @@ -389,7 +386,6 @@ Iepriekšējais Izlaist uzstādīšanu Mainiet lietotnes izskatu, lai tā atbilstu savai ierīcei - Avārijas ziņošana Ko tu vēlies redzēt Pabeigts Papildinājumi @@ -473,7 +469,6 @@ Github Nav subtitru Atskaņot epizodi - Piedodiet, bet aplikācijā bija kļūda. Anonīms kļūdas ziņojums tika aizsūtīts izstrādātājiem Iet Bezmaksas Ieslēgt elementus uz plakātiem diff --git a/app/src/main/res/values-b+mk/strings.xml b/app/src/main/res/values-b+mk/strings.xml index 95f6fa7ec..1af176a12 100644 --- a/app/src/main/res/values-b+mk/strings.xml +++ b/app/src/main/res/values-b+mk/strings.xml @@ -47,7 +47,6 @@ Пушти датотека Продолжи со преземање Паузирај со преземање - Оневозможи автоматско известување за грешки Повеќе информации Скриј Пушти @@ -101,8 +100,6 @@ Информации Напредно пребарување Ви ги дава резултатите од пребарувањето одделени по провајдер - Испраќај податоци само за падови на апликацијата - Не испраќа податоци Прикажи епизода за полнење за аниме Прикажи ажурирања на апликации Автоматски пребарувај нови ажурирања откако ќе ја стартуваш апликацијата. @@ -120,7 +117,6 @@ Линкот е копиран во таблата со исечоци Пушти ја епизодата Ресетирање на стандардните вредности - За жал, апликацијата падна. Ќе се испрати анонимен извештај за грешка до програмерите Сезона Нема сезона Епизода @@ -466,7 +462,6 @@ Претходно Прескокни го поставувањето Промени го изгледот на апликацијата за да одговара на твојот уред - Известување за пад Што сакате да видите Име на изворот (Опционално) Приклучокот е преземен diff --git a/app/src/main/res/values-b+ml/strings.xml b/app/src/main/res/values-b+ml/strings.xml index bf0fede72..c10777681 100644 --- a/app/src/main/res/values-b+ml/strings.xml +++ b/app/src/main/res/values-b+ml/strings.xml @@ -45,7 +45,6 @@ ഫയൽ പ്ലേയ് ചെയ്യുക ഡൌൺലോഡ് തുടരുക ഡൌൺലോഡ് നിർത്തുക - ഓട്ടോമാറ്റിക് ബഗ് റിപ്പോർട്ടിംഗ് പ്രവർത്തനരഹിതമാക്കുക കൂടുതൽ വിവരം ഒളിക്കുക പ്ലേയ് @@ -94,8 +93,6 @@ വിവരം സ്ട്രോതസായി തിരിച്ച ഫലം തരുക - ക്രാഷാകുമ്പോൾ മാത്രം അയക്കുക - ടാറ്റ അയക്കാതിരിക്കുക അപ്ഡേറ്റുകൾ അറിയിക്കുക ആരംഭത്തിൽ അപ്ഡേറ്റുകൾ തിരയുക പരീക്ഷണാത്മക അപ്ഡേറ് @@ -111,7 +108,6 @@ ലിങ്കുകൾ ലഭ്യമല്ല ലിങ്ക് പകർത്തിയിരിക്കുന്നു എപ്പിസോഡ് പ്ലേയ് ചെയ്യുക - ആപ്പ് നിശ്ചലമായിരിക്കുന്നതിന് ക്ഷമിക്കണം സീസൺ സീസണില്ല എപ്പിസോഡ് diff --git a/app/src/main/res/values-b+ms/strings.xml b/app/src/main/res/values-b+ms/strings.xml index e93dc5015..9038a51e7 100644 --- a/app/src/main/res/values-b+ms/strings.xml +++ b/app/src/main/res/values-b+ms/strings.xml @@ -66,7 +66,6 @@ Buang disalin! Kelajuan Pemain - Lumpuhkan pelaporan pepijat automatik Buang Mulakan episod seterusnya apabila episod semasa tamat Buka video tempatan @@ -163,7 +162,6 @@ Pemain Aplikasi akan dikemas kini ketika keluar Pemain dalaman - Tiada data dihantar Durasi Laman web Sinopsis @@ -416,7 +414,6 @@ HD Sebelum Tukar kelihatan aplikasi mengikut peranti - Laporkan ralat Tamat Tambahan Tambah repositori @@ -514,7 +511,6 @@ Pautan disalin ke papan klip Main episod Tetapkan semula ke nilai lalai - Maaf, permohonan itu terhempas. Laporan bug tanpa nama akan dihantar kepada pemaju Musim %1$s %2$d%3$s Tiada musim @@ -522,7 +518,6 @@ Sandarkan data Gagal pulihkan data dari fail %s Ralat sandaran %s - Hanya hantar data apabila mengalami kegagalan Episode diff --git a/app/src/main/res/values-b+mt/strings.xml b/app/src/main/res/values-b+mt/strings.xml index ee890fbbd..bd605bb37 100644 --- a/app/src/main/res/values-b+mt/strings.xml +++ b/app/src/main/res/values-b+mt/strings.xml @@ -115,7 +115,6 @@ Hassar il-fajl Kompli Nizzel Ieqaf Nizzel - Iddiżattiva r-rappurtar awtomatiku tal-bugs Iktar Informazzjoni Aħbi Iffiltra l-Bookmarks diff --git a/app/src/main/res/values-b+my/strings.xml b/app/src/main/res/values-b+my/strings.xml index 9d82dd47d..6a991f885 100644 --- a/app/src/main/res/values-b+my/strings.xml +++ b/app/src/main/res/values-b+my/strings.xml @@ -92,7 +92,6 @@ အပ်ဒိတ်များနှင့်အရန်သိမ်းဆည်းမှု နက်နက်ရှိုင်းရှိုင်းရှာခြင်း သင့်ကိုဝန်ဆောင်မှုပေးသူအလိုက်ရှာဖွေမှုရလဒ်များပေးမည် - ချို့ယွင်းမှုအကြီးစားဖြစ်မှသာဒေတာများပေးပို့ပါ anime များအတွက်ဖြည့်စွက်အပိုင်းကိုပြရန် ထွေလာများကိုပြရန် Kitsu မှ ပိုစတာများကိုပြရန် @@ -239,7 +238,6 @@ ဖိုင်ကို ဖွင့်ရန် ဒေါင်းလုဒ် ဆက်လုပ်ရန် ဒေါင်းလုဒ် ရပ်ရန် - အလိုအလျောက်အက်ပ်ချို့ယွင်းချက်ပေးပို့ခြင်းကိုပိတ်မည် ပိုမို၍ ပ့ံပိုးပေးသောဝန်ဆောင်မှုများအသုံးပြု၍ရှာရန် ဝုက်ရန် @@ -267,7 +265,6 @@ ရှာရန် အကောင့်များ အချက်အလက် - ဒေတာများမပို့ရန် ကြည့်ရှုပြီးသောအချိန်ပမာဏ Android TV ကဲ့သို့သော သိုလှောင်မှုနေရာနည်းပါးသော စက်ပစ္စည်းများတွင် အလွန်မြင့်မားစွာ သတ်မှတ်ပါက ပြဿနာများ ဖြစ်လာနိုင်သည်။ ISP ပိတ်ဆို့ခြင်းကို ကျော်လွှားရန်အတွက် အသုံးဝင်သည် @@ -287,7 +284,6 @@ ပေးခဲ့သောစာအရေအတွက် အက်ပ်ဘာသာစကား မူလအခြေအနေများကိုပြန်ထားပါ - စိတ်မကောင်းပါ။အက်ပ်ရပ်တန့်သွားပါတယ်။အမည်မဖော်ထားတဲ့တင်ပြချက်ကို အက်ပ်ရေးသားသူများထံ ပို့မှာဖြစ်ပါတယ် %1$s %2$d%3$s အတွဲ %1$d %2$s @@ -457,7 +453,6 @@ TC အရည်အသွေး အစီအစဥ်ချခြင်းကိုကျော်မည် - ချို့ယွင်းမှုသတင်းပေးပို့ခြင်း ဘာတွေကြည့်ချင်လဲ ပြီးပြီ အဆက်များ diff --git a/app/src/main/res/values-b+ne/strings.xml b/app/src/main/res/values-b+ne/strings.xml index bff19dd3a..4eea78b9c 100644 --- a/app/src/main/res/values-b+ne/strings.xml +++ b/app/src/main/res/values-b+ne/strings.xml @@ -83,7 +83,6 @@ पुन: हेर्दै स्ट्रिम टोरेन्ट स्रोतहरू - स्वचालित बग रिपोर्टिङ असक्षम गर्नुहोस् लागू गर्नुहोस् साइट ले मेटाडाटा दिएको छैन,मेटाडाटा बिना भिडियो लोड नहुन सक्छ। प्रकरण %1$d प्रसङ्ग %2$d प्रशारण हुनेवाला छ diff --git a/app/src/main/res/values-b+nl/strings.xml b/app/src/main/res/values-b+nl/strings.xml index b10821a35..2497c0eba 100644 --- a/app/src/main/res/values-b+nl/strings.xml +++ b/app/src/main/res/values-b+nl/strings.xml @@ -71,7 +71,6 @@ Bestand afspelen Download hervatten Download pauzeren - Automatische bugrapportage uitschakelen Meer info Verberg Speel @@ -150,8 +149,6 @@ Info Geavanceerd zoeken Geeft u de zoekresultaten gescheiden door provider - Stuurt alleen gegevens bij crashes - Verstuurt geen gegevens Toon filler episode voor anime Toon trailers Toon posters van Kitsu @@ -171,7 +168,6 @@ Link gekopieerd naar klembord Aflevering afspelen Reset naar standaardwaarde - Sorry, de applicatie is gecrasht. Er wordt een anoniem bugrapport naar de ontwikkelaars gestuurd Seizoen Geen seizoen Aflevering @@ -392,7 +388,6 @@ Vorige Instelling overslaan Pas het uiterlijk van de app aan uw apparaat aan - Crashrapportage Wat wil je zien Klaar Markeer als bekeken diff --git a/app/src/main/res/values-b+nn/strings.xml b/app/src/main/res/values-b+nn/strings.xml index 5b5577c2e..6989a85da 100644 --- a/app/src/main/res/values-b+nn/strings.xml +++ b/app/src/main/res/values-b+nn/strings.xml @@ -54,7 +54,6 @@ Slett fil Spel av fil Sett nedlasting på vent - Deaktiver automatisk feilrapportering Gøym Spel(e) av Informasjon @@ -103,7 +102,6 @@ Kopiert lenke til utklipptavle Spel av episode Tilbakestill til standardverdi - Beklager, programmet har krasjet. Ein anonymisert feilrapport vil bli sendt til utviklarane %1$s %2$d%3$s Ingen sesong Episode diff --git a/app/src/main/res/values-b+no/strings.xml b/app/src/main/res/values-b+no/strings.xml index ac13f57f9..8fa0d8eca 100644 --- a/app/src/main/res/values-b+no/strings.xml +++ b/app/src/main/res/values-b+no/strings.xml @@ -57,7 +57,6 @@ Spill av fil Fortsett nedlasting Stopp nedlastingen - Deaktiver automatisk feilrapportering Mer informasjon Gjemme seg Spille @@ -110,8 +109,6 @@ Informasjon Avansert søk Gir deg søkeresultatene atskilt etter leverandør - Sender bare rapportere om krasjer - Sender ingen rapportere Vis filler-episode til anime Vis appoppdateringer Søk automatisk etter nye oppdateringer etter at appen har startet. @@ -129,7 +126,6 @@ Linken er kopiert til utklippstavlen spille episode tilbakestill standardverdien - Beklager, programmet krasjet. En anonym feilrapport vil bli sendt til utviklerne Sesong Ingen sesong Episode @@ -346,7 +342,6 @@ passord123 Språkkode (nb_NO) Forrige - Krasjrapportering Utvidelser %1$d %2$s MittKuleBrukernavn diff --git a/app/src/main/res/values-b+pl/strings.xml b/app/src/main/res/values-b+pl/strings.xml index 3bff02c2b..9d5043d3a 100644 --- a/app/src/main/res/values-b+pl/strings.xml +++ b/app/src/main/res/values-b+pl/strings.xml @@ -61,7 +61,6 @@ Odtwórz plik Wznów pobieranie Wstrzymaj pobieranie - Wyłącz przekazywanie błędów Więcej informacji Ukryj Odtwórz @@ -141,8 +140,6 @@ Informacje Zaawansowane wyszukiwanie Szukaj z podziałem na źródła - Wysyłaj dane tylko przy awariach - Nie wysyłaj żadnych danych Pokaż fillery dla anime Pokaż zwiastuny Pokaż obrazki z Kitsu @@ -165,7 +162,6 @@ Skopiowano do schowka Odtwórz odcinek Zresetowano - Awaria aplikacji. Anonimowe zgłoszenie błędu zostanie wysłane programistom Sezon %1$s %2$d%3$s Brak sezonu @@ -368,7 +364,6 @@ Poprzedni Pomiń konfigurację Dostosuj wygląd aplikacji do urządzenia - Zgłaszanie błędów Co chcesz obejrzeć Gotowe Rozszerzenia diff --git a/app/src/main/res/values-b+pt+BR/strings.xml b/app/src/main/res/values-b+pt+BR/strings.xml index e5871672d..e82aa0b8c 100644 --- a/app/src/main/res/values-b+pt+BR/strings.xml +++ b/app/src/main/res/values-b+pt+BR/strings.xml @@ -69,7 +69,6 @@ Reproduzir arquivo Continuar download Pausar download - Desative o relatório automático de erros Mais informações Ocultar Reproduzir @@ -148,8 +147,6 @@ Info Pesquisa avançada Mostrar resultados separados por fornecedor - Enviar apenas dados de falhas - Não enviar nenhum dado Mostrar episódios extras de animes Mostrar trailers Mostrar posters do Kitsu @@ -171,7 +168,6 @@ Link copiado para área de transferência Assistir episódio Restaurar para o padrão - Desculpe :/, o aplicativo travou. Um relatório de erro anônimo será enviado aos desenvolvedores Temporada Nenhuma temporada Episódio @@ -390,7 +386,6 @@ Anterior Saltar setup Change the look of the app to suit your device - Crash reporting What do you want to see Feito Extensões diff --git a/app/src/main/res/values-b+pt/strings.xml b/app/src/main/res/values-b+pt/strings.xml index f6ccf2d03..67706ed12 100644 --- a/app/src/main/res/values-b+pt/strings.xml +++ b/app/src/main/res/values-b+pt/strings.xml @@ -68,7 +68,6 @@ Reproduzir Ficheiro Retomar Transferência Pausar Transferência - Desativar relatório automático de erros Mais info Esconder Reproduzir @@ -147,8 +146,6 @@ Info Procura Avançada Mostra resultados separados por fornecedor - Só envia dados sobre falhas - Não envia nenhum dado Mostrar episódios de enchimento para anime Mostrar trailers Mostrar posters do kitsu @@ -169,7 +166,6 @@ Link copiado para a área de transferência Reproduzir episódio Restaurar para o padrão - Desculpe, a aplicação falhou. Um relatório de erro anónimo será enviado para os desenvolvedores Temporada Nenhuma Temporada Episódio @@ -349,7 +345,6 @@ Anterior Saltar setup Change the look of the app to suit your device - Crash reporting What do you want to see Feito Extensões diff --git a/app/src/main/res/values-b+qt/strings.xml b/app/src/main/res/values-b+qt/strings.xml index 2ca5a5881..246134c66 100644 --- a/app/src/main/res/values-b+qt/strings.xml +++ b/app/src/main/res/values-b+qt/strings.xml @@ -38,7 +38,6 @@ ahooo ouuhhh ahhaauugghh - ooo-ahahoohahoooooo-ahahouuhhhoouuhaaahhu ahooo a aaaghhouuhhh oh ahhh ahhhahaaaaaahhhaaaghh @@ -91,8 +90,6 @@ aauugghh ah aah ouuhhhooo-ahah aaaghh aauugghh ahahooo ouuhhhahh ooh oouuhahoooahhaaahhu ohaooh oouuhooo-ahah - aaaaa ahhhahhohoouuhahoooaaaghh aahhhaaaaa - oouuhoooohh ahhooo-ahah haa oohaauugghhooh oh aaaagggoooogg uuuugg aak aah aaaahhh ooogg uuuuuukh aah ooh aaaghh ahhhahoooooo-ahah aaaghh @@ -109,7 +106,6 @@ ooh oouuh ahoooah ohaa oh ouuhhh ouuhhhoouuh ouuhhh haaahhh ooo-ahah haaoh haaooh - oooooahoohaaaghh oouuhoooohhaaaaaoha ohaaauugghh oohaaaaaahooo ooo-ahah aaaaaa ahooo ahooo oouuhoooohh oooohhaaaghh oouuh ooo-ahah aauuh ohaahooo @@ -407,7 +403,6 @@ uuuugg aaaaggg ug aah uug aahh ug uuuuhhh oohh aah memory, oohh og oooohhh ug aaaahhh oooogggh - ooohh aaaaaakag ooogg aaaaggg aaaahhhuuhh %1$d %2$s… uuuhh aaaagg diff --git a/app/src/main/res/values-b+ro/strings.xml b/app/src/main/res/values-b+ro/strings.xml index a49bcb6f9..4c1685319 100644 --- a/app/src/main/res/values-b+ro/strings.xml +++ b/app/src/main/res/values-b+ro/strings.xml @@ -68,7 +68,6 @@ Redare fișier Continuați descărcarea Opriți descărcarea - Dezactivați raportarea automată a erorilor Mai multe informații Ascunde Începe @@ -147,8 +146,6 @@ Informații Căutare avansată Împărțiți rezultatele căutării în funcție de furnizor - Trimiteți date numai în cazul unui accident - Nu trimiteți niciun fel de date Afișează etichetele [filler] pentru anime Arată trailerul Arată afișele de la Kitsu @@ -168,7 +165,6 @@ Link copiat în clipboard Redare episod Restabilirea la valorile implicite - Ne pare rău, aplicația s-a blocat. Un raport de eroare anonim va fi trimis dezvoltatorilor Sezonul Nu există sezon Episodul @@ -436,7 +432,6 @@ Linkuri Funcții Autori - Raportarea accidentelor Adaugă depozit Biblioteca ta este goală :( \nConectați-vă într-un cont de bibliotecă sau adăugați emisiuni la biblioteca locală. diff --git a/app/src/main/res/values-b+ru/strings.xml b/app/src/main/res/values-b+ru/strings.xml index aa5e24ccc..bf22e8901 100644 --- a/app/src/main/res/values-b+ru/strings.xml +++ b/app/src/main/res/values-b+ru/strings.xml @@ -117,7 +117,6 @@ Внутренняя память Продолжить Скачать Остановить скачивание - Отключить автоматическое информирование об ошибках Импортируйте шрифты поместив их в %s Продолжить смотреть Убрать @@ -165,7 +164,6 @@ Ссылок не найдено Ссылка скопирована в буфер обмена Восстановить по умолчанию - Извините, приложение прекратило работу. Анонимный отчёт об ошибке будет отправлен разработчикам Серия Серии С @@ -220,7 +218,6 @@ Дополнения Плеер Резервное копирование данных - Отправлять данные только при вылетах Использовано Двойное нажатие для паузы Коснитесь дважды правой или левой стороны для поиска вперед или назад @@ -453,7 +450,6 @@ Скачивание обновления приложения… Недопустимый URL Перезапустите приложение, чтобы увидеть изменения. - Отчеты ошибках Что вы хотите увидеть Смотрите видео на этих языках Скачано файл @@ -485,7 +481,6 @@ Отображать случайную кнопку в библиотеке и главной странице Случайная кнопка Устаревший - Не отправляет данные Перезагрузить ссылки Предпочтительные медиа Опущенные diff --git a/app/src/main/res/values-b+sk/strings.xml b/app/src/main/res/values-b+sk/strings.xml index b13cbcc11..19be22684 100644 --- a/app/src/main/res/values-b+sk/strings.xml +++ b/app/src/main/res/values-b+sk/strings.xml @@ -50,7 +50,6 @@ Načítavanie… Dokončené Plánujem pozerať - Zakázať automatické nahlasovanie chýb Viac informácií Záložky Prehrať film @@ -151,7 +150,6 @@ Dvojitým ťuknutím pretočiť Automaticky sťahovať doplnky Pripojte sa na Discord - Neodosiela žiadne dáta Odstrániť čierne okraje Automaticky vyhľadať nové aktualizácie po spustení aplikácie. Prehrať epizódu @@ -167,7 +165,6 @@ V prehrávači použiť systémový jas namiesto tmavého prekrytia Zobraziť upútavky Automaticky nainštalovať všetky ešte nenainštalované doplnky z pridaných repozitárov. - Odosiela dáta len pri pádoch Knižnica GitHub Hľadať @@ -180,7 +177,6 @@ Zobraziť aktualizácie aplikácie Aktualizácia na predbežné vydania Vyhľadať aktualizácie predbežných vydaní namiesto plných vydaní - Ospravedlňujeme sa, aplikácia spadla. Vývojárom bude odoslané anonymné hlásenie o páde Obnoviť predvolenú hodnotu Sezóna Synopsa @@ -435,7 +431,6 @@ Neplatné dáta Neplatná URL adresa Odstráňte uzavreté titulky od titulkov - Správy zlyhania Zobraziť odporúčania Otestujte všetky rozšírenia Nadchádzajúce o %s diff --git a/app/src/main/res/values-b+so/strings.xml b/app/src/main/res/values-b+so/strings.xml index 8b1e4cc15..44a9b6d90 100644 --- a/app/src/main/res/values-b+so/strings.xml +++ b/app/src/main/res/values-b+so/strings.xml @@ -67,7 +67,6 @@ Trj Way bilaabmatay soo dejintu Daalaco - Jooji cillad gudbinta iskeed ah Waa la joojiyey dejintan Way bilaabantay cuaboonaysiintu Soo raridda lifaaqyadu way fashilantay @@ -96,7 +95,6 @@ Gurmadka iyo cusbooneysiinta Waa la kaydiyet xogta gurmadka Raadinta waxay kuugu kala qaybinaysaa mid kasta iyo qaybiyihiisa - Ma jirto xog la dirayo Way fashilantay in xogta laga soo celiyo faylka gurmadka%s Moobillada qaar ayaa awoodin iney Rakibaha cusub een isticmaalnay, kan ku day haddii cusbooneysiintu kuu shaqayn weydo. +30 @@ -108,7 +106,6 @@ Si iskii ah usoo deji sidkanaha Qari tayada muqaalka aad dooratay natiijada waxa aad raadiso Raadin heer-sare ah - Keliya xogta waxaa ka dirayaa marka appku duqeeyo Xalqad buuxis ah tusi anemiga Dhiseyaasha appka sii beniin Way fashilantay dejintu, hubi ogolaanshaha isticmaalka kaydka @@ -176,7 +173,6 @@ Bixiyahan kuma shaqeeyo koromakaastiga Asalkiisii hore kusoo celi Dulucuda - Raalliahow, wuu duqeeyey appku, waxa warbixin cillad-saarka ka caawisa loo direy dhiseyaasha Kalka %1$s %2$d%3$s Xalqad @@ -453,7 +449,6 @@ Kii hore Is dhaafi fadhiisintan Beddel sida appku u muuqdo si uu ugu habboonaado moobilekaaga - Warbixinra cillad-saarka Maxaad rabtaa inaad daawato Dhan Ku dar kayd-weyne diff --git a/app/src/main/res/values-b+sv/strings.xml b/app/src/main/res/values-b+sv/strings.xml index 2b6de30af..3bc16b041 100644 --- a/app/src/main/res/values-b+sv/strings.xml +++ b/app/src/main/res/values-b+sv/strings.xml @@ -40,7 +40,6 @@ Sub Radera fil Spela upp fil - Inaktivera automatisk felrapportering Mer information Göm @string/result_poster_img_des @@ -94,8 +93,6 @@ Information Avancerade sökresultat Presenterar sökresultaten i flera olika rader baserat på leverantören - Skickar endast data när appen kraschar - Skickar ingen data Visa appuppdateringar Sök automatiskt efter nya uppdateringar vid start. Uppdatera till beta-version @@ -112,7 +109,6 @@ Länken kopierades till urklipp Spela upp avsnitt Återställd till standardvärdet - Programmet kraschade tyvärr. En anonym felrapport kommer att skickas till utvecklarna Fel uppstod vid laddning av länkarna Säsong Ingen Säsong @@ -310,7 +306,6 @@ Slumpmässig Kommer snart… Filtrera efter föredraget språk - Kraschrapportering Kunde inte logga in på %s Utseende Layout diff --git a/app/src/main/res/values-b+ta/strings.xml b/app/src/main/res/values-b+ta/strings.xml index a71e4df2b..da1353229 100644 --- a/app/src/main/res/values-b+ta/strings.xml +++ b/app/src/main/res/values-b+ta/strings.xml @@ -34,7 +34,6 @@ கோப்பை அழி கோப்பு இடைநிறுத்தம் பதிவிறக்கம் - தானியங்கி பிழை அறிக்கையை முடக்கு மேலும் செய்தி மறை அகற்று @@ -203,7 +202,6 @@ காப்பு அதிர்வெண் தரவு சேமிக்கப்பட்டது சேமிப்பக அனுமதிகள் இல்லை. தயவு செய்து மீண்டும் முயற்சிக்கவும். - செயலிழப்புகள் குறித்த தரவை மட்டுமே அனுப்புகிறது சுவரொட்டியில் இடைமுகம் கூறுகளை மாற்றவும் மேம்படுத்தல் சோதிக்க பூட்டு @@ -213,7 +211,6 @@ மூலம் கேம் சுவரொட்டி படம் - செயலிழப்பு அறிக்கை பொது பட்டியல் பதிப்பு நூலகத்தைத் தேர்ந்தெடுக்கவும் @@ -410,13 +407,11 @@ பிழையைப் பதிவிறக்குங்கள், சேமிப்பக அனுமதிகளை சரிபார்க்கவும் வழங்குநரை மாற்றவும் முன்னோட்டம் பின்னணி - எந்த தரவை அனுப்பவில்லை அனிமேசுக்கு நிரப்பு அத்தியாயத்தைக் காட்டு கூடுதல் களஞ்சியங்களிலிருந்து இன்னும் நிறுவப்படாத அனைத்து செருகுநிரல்களையும் தானாக நிறுவவும். முழு வெளியீடுகளுக்கு பதிலாக மட்டுமே புதுப்பிப்புகளைத் தேடுங்கள் அதே தேவ்சின் அனிம் பயன்பாடு அத்தியாயங்கள் - மன்னிக்கவும், விண்ணப்பம் செயலிழந்தது. ஒரு அநாமதேய பிழை அறிக்கை டெவலப்பர்களுக்கு அனுப்பப்படும் முடிந்தது வசன வரிகள் இல்லை கார்ட்டூன்கள் diff --git a/app/src/main/res/values-b+tl/strings.xml b/app/src/main/res/values-b+tl/strings.xml index 5fd25031e..87c15f527 100644 --- a/app/src/main/res/values-b+tl/strings.xml +++ b/app/src/main/res/values-b+tl/strings.xml @@ -60,7 +60,6 @@ I-play ang file I-resume ang download I-pause ang download - Huwag awtomatikong mag-ulat ng bug More Info Itago I-play @@ -113,8 +112,6 @@ Impormasyon Adbans na maghanap Magbibigay ng pinaghiwa-hiwalay na resulta - Nagpapadala lamang ng data kung nag-crash ang app - Hindi magpapadala ng kahit anong data Ipakita ang filler episode sa anime Ipakita kung may bagong update Awtomatikong mag-check ng bagong update pagbukas ng app @@ -132,7 +129,6 @@ Link copied to clipboard Play Episode I-reset sa default value - Paumanhin, ang app ay nag-crash. Isang anonymous bug report ang ipapadala sa developers Season No season Episode diff --git a/app/src/main/res/values-b+tr/strings.xml b/app/src/main/res/values-b+tr/strings.xml index 34e702f91..6f9940160 100644 --- a/app/src/main/res/values-b+tr/strings.xml +++ b/app/src/main/res/values-b+tr/strings.xml @@ -84,7 +84,6 @@ Dosyayı Oynat İndirmeyi Sürdür İndirmeyi Duraklat - Otomatik hata raporlamayı kapat Daha fazla bilgi Gizle Oynat @@ -165,8 +164,6 @@ Bilgi Gelişmiş arama Arama sonuçlarını sağlayıcıya göre ayırır - Yalnızca çökmelerle ilgili verileri gönderir - Veri göndermez Anime için dolgu bölümünü göster Fragmanları göster Kitsu posterlerini göster @@ -188,7 +185,6 @@ Bağlantı panoya kopyalandı Bölümü oynat Varsayılan değere sıfırla - Üzgünüz, uygulama çöktü. Geliştiricilere anonim bir hata raporu gönderilecek Sezon %1$s %2$d%3$s Sezon yok @@ -427,7 +423,6 @@ Önceki Kurulumu atla Cihazınıza uygun uygulama görünümünü seçin - Çökme raporları Ne izlemek istiyorsunuz Bitti Eklentiler diff --git a/app/src/main/res/values-b+uk/strings.xml b/app/src/main/res/values-b+uk/strings.xml index eb7a25930..5761cf318 100644 --- a/app/src/main/res/values-b+uk/strings.xml +++ b/app/src/main/res/values-b+uk/strings.xml @@ -47,7 +47,6 @@ Суб. Видалити файл Відновити завантаження - Вимкнути автонадсилання звітів про помилки Приховати Переглянути Подробиці @@ -144,8 +143,6 @@ Подробиці Розширений пошук Показувати результати пошуку, розділені за постачальниками - Надсилати лише дані про збої - Не надсилати дані Показувати наповнювачі для аніме Показувати трейлери Приховати вибрану якість відео у результатах пошуку @@ -233,7 +230,6 @@ Дано бананів Рік +30 - Вибачте, у застосунку стався збій. Буде відправлено анонімне повідомлення про помилку розробникам %1$s %2$d%3$s Епізод %1$d-%2$d @@ -398,7 +394,6 @@ Далі Переглядайте відео на цих мовах Пропустити налаштування - Звітування про збої Що ви хочете побачити Готово Розширення diff --git a/app/src/main/res/values-b+ur/strings.xml b/app/src/main/res/values-b+ur/strings.xml index a6afb22de..494e3118e 100644 --- a/app/src/main/res/values-b+ur/strings.xml +++ b/app/src/main/res/values-b+ur/strings.xml @@ -124,8 +124,6 @@ اکاؤنٹس اور سیکیورٹی معلومات آپ کو فراہم کنندہ کے ذریعہ علیحدہ کردہ تلاش کے نتائج فراہم کرتا ہے - صرف کریش پر ڈیٹا بھیجتا ہے - کوئی ڈیٹا نہیں بھیجتا تلاش کے نتائج میں منتخب ویڈیو کوالٹی چھپائیں خودکار پلگ ان اپ ڈیٹس ایپ کی تازہ کاریاں نمایش کریں @@ -156,7 +154,6 @@ ڈاؤن لوڈ ہو گیا انٹرنل سٹوریج ڈاؤن لوڈ کو روکیں - خودکار بگ رپورٹنگ کو غیر فعال کریں ذرائع کا استعمال کرتے ہوئے تلاش کریں اس فراہم کنندہ کو مناسب طریقے سے کام کرنے کے لیے VPN کی ضرورت پڑ سکتی ہے ڈیفالٹ سیٹنگز پر ری سیٹ کرنے کے لیے دبائیں اور تھامیں @@ -177,7 +174,6 @@ شامل کردہ ذخیروں سے خود بخود تمام ابھی تک انسٹال نہیں ہوئے پلگ ان انسٹال کریں۔ اپلیکیشن کو شروع کرنے کے بعد خود بخود نئی اپ ڈیٹس کی تلاش کریں۔ کچھ فون نئے پیکیج انسٹالر کو سپورٹ نہیں کرتے ہیں. اگر اپ ڈیٹس انسٹال نہیں ہوتے ہیں تو لیگیسی آپشن کو آزمائیں. - معذرت، ایپلی کیشن کریش ہو گئی. ایک گمنام بگ رپورٹ ڈویلپرز کو بھیجی جائے گی سیزن %1$s %2$d%3$s کوئی سیزن نہیں @@ -396,7 +392,6 @@ حوالہ دینے والا (مرضی پر) ان زبانوں میں ویڈیوز دیکھیں سیٹ اپ کو چھوڑ دیں - کریش رپورٹنگ ہو گیا ایکسٹینشنز ذخیرہ URL diff --git a/app/src/main/res/values-b+vi/strings.xml b/app/src/main/res/values-b+vi/strings.xml index b1e166126..0a7474435 100644 --- a/app/src/main/res/values-b+vi/strings.xml +++ b/app/src/main/res/values-b+vi/strings.xml @@ -72,7 +72,6 @@ Xem Tệp Tiếp tục tải Tạm dừng tải - Tắt tự động gửi dữ liệu khi xảy ra lỗi Thông tin thêm Ẩn Xem ngay @@ -152,8 +151,6 @@ Thông tin Tìm kiếm nâng cao Cho phép tìm kiếm theo bộ lọc từng nhà cung cấp - Chỉ gửi dữ liệu khi xảy ra lỗi đến nhà phát triển - Không gửi dữ liệu Hiển thị tập phụ cho anime Hiển thị trailer Hiển thị poster từ Kitsu @@ -175,7 +172,6 @@ Đã sao chép liên kết vào bộ nhớ tạm Xem Phim Thiết lập lại giá trị mặc định - Rất tiếc! Ứng dụng đã xảy ra lỗi. Một báo cáo lỗi ẩn danh sẽ được gửi đến nhà phát triển Mùa Không có mùa nào Tập @@ -395,7 +391,6 @@ Trước đó Bỏ qua cài đặt setup Chọn giao diện phù hợp với thiết bị của bạn - Báo cáo sự cố Bạn muốn xem gì Hoàn tất Tiện ích mở rộng diff --git a/app/src/main/res/values-b+zh+TW/strings.xml b/app/src/main/res/values-b+zh+TW/strings.xml index e4d7f9fa2..c29a8e206 100644 --- a/app/src/main/res/values-b+zh+TW/strings.xml +++ b/app/src/main/res/values-b+zh+TW/strings.xml @@ -84,7 +84,6 @@ 播放檔案 繼續下載 暫停下載 - 停用自動錯誤報告 更多資訊 隱藏 播放 @@ -165,8 +164,6 @@ 資訊 進階搜尋 為您提供按片源分開的搜尋結果 - 僅在程式崩潰時傳送相關資料 - 不傳送資料 顯示動畫外傳 顯示預告片 顯示來自 Kitsu 的封面 @@ -188,7 +185,6 @@ 連結已複製到剪貼簿 播放劇集 重設為預設值 - 很抱歉,應用程式崩潰了,將傳送一份匿名錯誤報告給開發者 %1$s %2$d%3$s 無季 @@ -428,7 +424,6 @@ 上一個 跳過設定 更改應用程式的外觀以適應你的設備 - 程式崩潰報告 你想要看什麼 完成 擴充功能 diff --git a/app/src/main/res/values-b+zh/strings.xml b/app/src/main/res/values-b+zh/strings.xml index 4a5b8c1b2..9dfb9d904 100644 --- a/app/src/main/res/values-b+zh/strings.xml +++ b/app/src/main/res/values-b+zh/strings.xml @@ -84,7 +84,6 @@ 播放文件 继续下载 暂停下载 - 禁用自动错误报告 更多信息 隐藏 播放 @@ -165,8 +164,6 @@ 信息 高级搜索 按片源分割搜索结果 - 仅发送关于崩溃的数据 - 不发送数据 显示动画外传 显示预告片 显示来自 Kitsu 的封面 @@ -189,7 +186,6 @@ 链接已复制到剪贴板 播放剧集 重置为默认值 - 抱歉,应用崩溃了,将发送一份匿名错误报告给开发者 %1$s %2$d%3$s 无季 @@ -429,7 +425,6 @@ 上一个 跳过设置向导 更改为适应您的设备的应用布局 - 崩溃报告 您想要看什么 完成 扩展 diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 9d1bfd1f6..10f61e40e 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -83,7 +83,6 @@ Reprodueix el fitxer Continua la descàrrega Posa la descàrrega en espera - Deshabilita el report automàtic d\'errors Més informació Amaga Reprodueix @@ -290,7 +289,6 @@ Anterior Omet la configuració Canvia l\'aspecte de la aplicació perquè s\'adapti al vostre dispositiu - Informe d\'errors Què vols veure Fet Extensions diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c6fdfa092..2409c8878 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -179,7 +179,6 @@ Play File Resume Download Pause Download - Disable automatic bug reporting More info Hide Play @@ -273,8 +272,6 @@ Info Advanced Search Gives you the search results separated by provider - Only sends data on crashes - Sends no data Show filler episode for anime Show trailers Show posters from Kitsu @@ -302,9 +299,6 @@ Link copied to clipboard Play Episode Reset to default value - Sorry, the application crashed. An anonymous bug report will be sent to the - developers - Season %1$s %2$d%3$s No Season @@ -623,7 +617,6 @@ Previous Skip setup Change the look of the app to suit your device - Crash reporting What do you want to see Done Extensions diff --git a/app/src/main/res/xml/settings_updates.xml b/app/src/main/res/xml/settings_updates.xml index 2c2de0431..3eb63b28f 100644 --- a/app/src/main/res/xml/settings_updates.xml +++ b/app/src/main/res/xml/settings_updates.xml @@ -84,12 +84,5 @@ android:icon="@drawable/ic_baseline_construction_24" android:title="@string/redo_setup_process" app:key="@string/redo_setup_key" /> - diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 088cad6d5..d30e384ef 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,4 @@ [versions] -acraCore = "5.13.1" activityKtx = "1.11.0" androidGradlePlugin = "8.13.1" appcompat = "1.7.1" @@ -54,8 +53,6 @@ compileSdk = "36" targetSdk = "36" [libraries] -acra-core = { module = "ch.acra:acra-core", version.ref = "acraCore" } -acra-toast = { module = "ch.acra:acra-toast", version.ref = "acraCore" } activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activityKtx" } android-gradle-plugin = { module = "com.android.tools.build:gradle", version.ref = "androidGradlePlugin" } appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } From 009dcc2b895de671bde1f0dbc16dded63d490843 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Mon, 24 Nov 2025 10:26:07 -0700 Subject: [PATCH 156/513] Use version catalog for plugins (#2206) --- app/build.gradle.kts | 6 +++--- build.gradle.kts | 27 ++++++++------------------- docs/build.gradle.kts | 6 +++--- gradle/libs.versions.toml | 13 +++++++++---- library/build.gradle.kts | 12 ++++++------ settings.gradle.kts | 24 ++++++++++++++++++++---- 6 files changed, 49 insertions(+), 39 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1a98ac2f3..fb8f2e836 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -6,9 +6,9 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile plugins { - id("com.android.application") - id("kotlin-android") - id("org.jetbrains.dokka") + alias(libs.plugins.android.application) + alias(libs.plugins.dokka) + alias(libs.plugins.kotlin.android) } val javaTarget = JvmTarget.fromTarget(libs.versions.jvmTarget.get()) diff --git a/build.gradle.kts b/build.gradle.kts index 22cdc4ba3..a5c4f9fbc 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,25 +1,14 @@ -buildscript { - repositories { - google() - mavenCentral() - } - - dependencies { - classpath(libs.android.gradle.plugin) - classpath(libs.buildkonfig.gradle.plugin) // Universal build config - classpath(libs.dokka.gradle.plugin) - classpath(libs.kotlin.gradle.plugin) - } +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.android.library) apply false + alias(libs.plugins.buildkonfig) apply false // Universal build config + alias(libs.plugins.dokka) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.kotlin.jvm) apply false + alias(libs.plugins.kotlin.multiplatform) apply false } allprojects { - repositories { - google() - mavenCentral() - mavenLocal() - maven("https://jitpack.io") - } - // https://docs.gradle.org/current/userguide/upgrading_major_version_9.html#test_task_fails_when_no_tests_are_discovered tasks.withType().configureEach { failOnNoDiscoveredTests = false diff --git a/docs/build.gradle.kts b/docs/build.gradle.kts index 203b93818..8f5be2a2d 100644 --- a/docs/build.gradle.kts +++ b/docs/build.gradle.kts @@ -1,6 +1,6 @@ plugins { - kotlin("jvm") - id("org.jetbrains.dokka") + alias(libs.plugins.kotlin.jvm) + alias(libs.plugins.dokka) } dependencies { @@ -10,4 +10,4 @@ dependencies { dokka { moduleName = "Cloudstream" -} \ No newline at end of file +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d30e384ef..fdef44ef8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,3 +1,5 @@ +# https://docs.gradle.org/current/userguide/plugins.html#sec:version_catalog_plugin_application +# https://docs.gradle.org/current/userguide/dependency_versions.html#sec:strict-version [versions] activityKtx = "1.11.0" androidGradlePlugin = "8.13.1" @@ -54,10 +56,8 @@ targetSdk = "36" [libraries] activity-ktx = { module = "androidx.activity:activity-ktx", version.ref = "activityKtx" } -android-gradle-plugin = { module = "com.android.tools.build:gradle", version.ref = "androidGradlePlugin" } appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } biometric = { module = "androidx.biometric:biometric", version.ref = "biometric" } -buildkonfig-gradle-plugin = { module = "com.codingfeline.buildkonfig:buildkonfig-gradle-plugin", version.ref = "buildkonfigGradlePlugin" } coil = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" } colorpicker = { module = "com.github.recloudstream:color-picker-android", version.ref = "colorpicker" } @@ -67,7 +67,6 @@ core = { module = "androidx.test:core" } core-ktx = { module = "androidx.core:core-ktx", version.ref = "coreKtx" } databinding = { module = "androidx.databinding:viewbinding", version.ref = "androidGradlePlugin" } desugar_jdk_libs_nio = { module = "com.android.tools:desugar_jdk_libs_nio", version.ref = "desugar_jdk_libs_nio" } -dokka-gradle-plugin = { module = "org.jetbrains.dokka:dokka-gradle-plugin", version.ref = "dokkaGradlePlugin" } espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espressoCore" } ext-junit = { module = "androidx.test.ext:junit", version.ref = "junitVersion" } fuzzywuzzy = { module = "me.xdrop:fuzzywuzzy", version.ref = "fuzzywuzzy" } @@ -77,7 +76,6 @@ jsoup = { module = "org.jsoup:jsoup", version.ref = "jsoup" } junit = { module = "junit:junit", version.ref = "junit" } junit-ktx = { module = "androidx.test.ext:junit-ktx", version.ref = "junitKtx" } juniversalchardet = { module = "com.github.albfernandez:juniversalchardet", version.ref = "juniversalchardet" } -kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlinGradlePlugin" } kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesCore" } lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" } lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" } @@ -116,6 +114,13 @@ work-runtime = { module = "androidx.work:work-runtime", version.ref = "workRunti work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "workRuntimeKtx" } [plugins] +android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } +android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" } +buildkonfig = { id = "com.codingfeline.buildkonfig", version.ref = "buildkonfigGradlePlugin" } +dokka = { id = "org.jetbrains.dokka", version.ref = "dokkaGradlePlugin" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlinGradlePlugin" } +kotlin-jvm = { id = "org.jetbrains.kotlin.jvm" , version.ref = "kotlinGradlePlugin" } +kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlinGradlePlugin" } [bundles] media3 = ["media3-cast", "media3-common", "media3-container", "media3-datasource-cronet", "media3-datasource-okhttp", "media3-exoplayer", "media3-exoplayer-dash", "media3-exoplayer-hls", "media3-session", "media3-ui"] diff --git a/library/build.gradle.kts b/library/build.gradle.kts index 3fc1ce8dd..a418efaab 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -6,11 +6,11 @@ import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile plugins { - kotlin("multiplatform") - id("maven-publish") - id("com.android.library") - id("com.codingfeline.buildkonfig") - id("org.jetbrains.dokka") + id("maven-publish") // Gradle core plugin + alias(libs.plugins.kotlin.multiplatform) + alias(libs.plugins.android.library) + alias(libs.plugins.buildkonfig) + alias(libs.plugins.dokka) } val javaTarget = JvmTarget.fromTarget(libs.versions.jvmTarget.get()) @@ -125,4 +125,4 @@ dokka { } } } -} \ No newline at end of file +} diff --git a/settings.gradle.kts b/settings.gradle.kts index bd26f9f34..73bf5a195 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,21 @@ -rootProject.name = "CloudStream" +// https://developer.android.com/build#settings-file +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} -include(":app") -include(":library") -include(":docs") \ No newline at end of file +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + mavenLocal() + maven("https://jitpack.io") + } +} + +rootProject.name = "CloudStream" +include(":app", ":library", ":docs") From 7f9f89cbf66a5a48778d54f45245b8ece959fc60 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 25 Nov 2025 07:16:37 -0700 Subject: [PATCH 157/513] Use version catalog bundles for coil and lifecycle (#2237) --- app/build.gradle.kts | 14 ++++++-------- gradle/libs.versions.toml | 13 +++++++------ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index fb8f2e836..385b4af6d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -173,9 +173,8 @@ dependencies { implementation(libs.core.ktx) implementation(libs.activity.ktx) implementation(libs.appcompat) - implementation(libs.bundles.navigationKtx) - implementation(libs.lifecycle.livedata.ktx) - implementation(libs.lifecycle.viewmodel.ktx) + implementation(libs.bundles.lifecycle) + implementation(libs.bundles.navigation) // Design & UI implementation(libs.preference.ktx) @@ -184,21 +183,20 @@ dependencies { implementation(libs.swiperefreshlayout) // Coil Image Loading - implementation(libs.coil) - implementation(libs.coil.network.okhttp) + implementation(libs.bundles.coil) // Media 3 (ExoPlayer) implementation(libs.bundles.media3) implementation(libs.video) + // FFmpeg Decoding + implementation(libs.bundles.nextlib) + // PlayBack implementation(libs.colorpicker) // Subtitle Color Picker implementation(libs.newpipeextractor) // For Trailers implementation(libs.juniversalchardet) // Subtitle Decoding - // FFmpeg Decoding - implementation(libs.bundles.nextlibMedia3) - // UI Stuff implementation(libs.shimmer) // Shimmering Effect (Loading Skeleton) implementation(libs.palette.ktx) // Palette for Images -> Colors diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fdef44ef8..4ebe1ce2d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -24,8 +24,7 @@ junitVersion = "1.3.0" juniversalchardet = "2.5.0" kotlinGradlePlugin = "2.2.21" kotlinxCoroutinesCore = "1.10.2" -lifecycleLivedataKtx = "2.9.4" -lifecycleViewmodelKtx = "2.9.4" +lifecycleKtx = "2.9.4" material = "1.14.0-alpha06" media3 = "1.8.0" navigationKtx = "2.9.6" @@ -77,8 +76,8 @@ junit = { module = "junit:junit", version.ref = "junit" } junit-ktx = { module = "androidx.test.ext:junit-ktx", version.ref = "junitKtx" } juniversalchardet = { module = "com.github.albfernandez:juniversalchardet", version.ref = "juniversalchardet" } kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutinesCore" } -lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtx" } -lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" } +lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "lifecycleKtx" } +lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleKtx" } material = { module = "com.google.android.material:material", version.ref = "material" } media3-cast = { module = "androidx.media3:media3-cast", version.ref = "media3" } media3-common = { module = "androidx.media3:media3-common", version.ref = "media3" } @@ -123,6 +122,8 @@ kotlin-jvm = { id = "org.jetbrains.kotlin.jvm" , version.ref = "kotlinGradlePlug kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlinGradlePlugin" } [bundles] +coil = ["coil", "coil-network-okhttp"] +lifecycle = ["lifecycle-livedata-ktx", "lifecycle-viewmodel-ktx"] media3 = ["media3-cast", "media3-common", "media3-container", "media3-datasource-cronet", "media3-datasource-okhttp", "media3-exoplayer", "media3-exoplayer-dash", "media3-exoplayer-hls", "media3-session", "media3-ui"] -navigationKtx = ["navigation-fragment-ktx", "navigation-ui-ktx"] -nextlibMedia3 = ["nextlib-media3ext", "nextlib-mediainfo"] +navigation = ["navigation-fragment-ktx", "navigation-ui-ktx"] +nextlib = ["nextlib-media3ext", "nextlib-mediainfo"] From 9d651f1f8264d008540fb7eb9bdf35d80b34c41d Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 25 Nov 2025 07:24:21 -0700 Subject: [PATCH 158/513] Remove work-runtime dependency (#2234) We only really need to include the Kotlin version, work-runtime-ktx here. --- app/build.gradle.kts | 1 - gradle/libs.versions.toml | 2 -- 2 files changed, 3 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 385b4af6d..6cc801591 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -220,7 +220,6 @@ dependencies { implementation(libs.torrentserver) // Downloading & Networking - implementation(libs.work.runtime) implementation(libs.work.runtime.ktx) implementation(libs.nicehttp) // HTTP Lib diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4ebe1ce2d..8e22a64b2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -44,7 +44,6 @@ tmdbJava = "2.13.0" torrentserver = "7861970e038b35cd8c6918384e49caf26903e09e" tvprovider = "1.1.0" video = "1.0.0" -workRuntime = "2.10.5" workRuntimeKtx = "2.10.5" jvmTarget = "1.8" @@ -109,7 +108,6 @@ tmdb-java = { module = "com.uwetrottmann.tmdb2:tmdb-java", version.ref = "tmdbJa torrentserver = { module = "com.github.recloudstream:torrentserver", version.ref = "torrentserver" } tvprovider = { module = "androidx.tvprovider:tvprovider", version.ref = "tvprovider" } video = { module = "com.google.android.mediahome:video", version.ref = "video" } -work-runtime = { module = "androidx.work:work-runtime", version.ref = "workRuntime" } work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "workRuntimeKtx" } [plugins] From d43a371b15eb6806cb549adaeeda343ec939cd92 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 27 Nov 2025 11:34:14 -0700 Subject: [PATCH 159/513] Better backward compatibility for AcraApplication (#2265) --- .../lagradost/cloudstream3/AcraApplication.kt | 48 ++++++++++++++----- .../lagradost/cloudstream3/CloudStreamApp.kt | 2 + 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/AcraApplication.kt b/app/src/main/java/com/lagradost/cloudstream3/AcraApplication.kt index 92993f78b..262f57522 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/AcraApplication.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/AcraApplication.kt @@ -1,5 +1,11 @@ package com.lagradost.cloudstream3 +import android.content.Context +import com.lagradost.api.setContext +import com.lagradost.cloudstream3.utils.DataStore.getKey +import com.lagradost.cloudstream3.utils.DataStore.setKey +import java.lang.ref.WeakReference + /** * Deprecated alias for CloudStreamApp for backwards compatibility with plugins. * Use CloudStreamApp instead. @@ -12,61 +18,77 @@ package com.lagradost.cloudstream3 level = DeprecationLevel.WARNING )*/ class AcraApplication { + // All methods here can be changed to be a wrapper around CloudStream app + // without a seperate deprecation after next stable. All methods should + // also be deprecated at that time. companion object { + // This can be removed without deprecation after next stable + private var _context: WeakReference? = null /*@Deprecated( message = "AcraApplication is deprecated, use CloudStreamApp instead", replaceWith = ReplaceWith("com.lagradost.cloudstream3.CloudStreamApp.context"), level = DeprecationLevel.WARNING )*/ - val context get() = CloudStreamApp.context + var context + get() = _context?.get() + internal set(value) { + _context = WeakReference(value) + setContext(WeakReference(value)) + } /*@Deprecated( message = "AcraApplication is deprecated, use CloudStreamApp instead", replaceWith = ReplaceWith("com.lagradost.cloudstream3.CloudStreamApp.setKey(path, value)"), level = DeprecationLevel.WARNING )*/ - fun setKey(path: String, value: T) = - CloudStreamApp.setKey(path, value) + fun setKey(path: String, value: T) { + context?.setKey(path, value) + } /*@Deprecated( message = "AcraApplication is deprecated, use CloudStreamApp instead", replaceWith = ReplaceWith("com.lagradost.cloudstream3.CloudStreamApp.setKey(folder, path, value)"), level = DeprecationLevel.WARNING )*/ - fun setKey(folder: String, path: String, value: T) = - CloudStreamApp.setKey(folder, path, value) + fun setKey(folder: String, path: String, value: T) { + context?.setKey(folder, path, value) + } /*@Deprecated( message = "AcraApplication is deprecated, use CloudStreamApp instead", replaceWith = ReplaceWith("com.lagradost.cloudstream3.CloudStreamApp.getKey(path, defVal)"), level = DeprecationLevel.WARNING )*/ - inline fun getKey(path: String, defVal: T?): T? = - CloudStreamApp.getKey(path, defVal) + inline fun getKey(path: String, defVal: T?): T? { + return context?.getKey(path, defVal) + } /*@Deprecated( message = "AcraApplication is deprecated, use CloudStreamApp instead", replaceWith = ReplaceWith("com.lagradost.cloudstream3.CloudStreamApp.getKey(path)"), level = DeprecationLevel.WARNING )*/ - inline fun getKey(path: String): T? = - CloudStreamApp.getKey(path) + inline fun getKey(path: String): T? { + return context?.getKey(path) + } /*@Deprecated( message = "AcraApplication is deprecated, use CloudStreamApp instead", replaceWith = ReplaceWith("com.lagradost.cloudstream3.CloudStreamApp.getKey(folder, path)"), level = DeprecationLevel.WARNING )*/ - inline fun getKey(folder: String, path: String): T? = - CloudStreamApp.getKey(folder, path) + inline fun getKey(folder: String, path: String): T? { + return context?.getKey(folder, path) + } /*@Deprecated( message = "AcraApplication is deprecated, use CloudStreamApp instead", replaceWith = ReplaceWith("com.lagradost.cloudstream3.CloudStreamApp.getKey(folder, path, defVal)"), level = DeprecationLevel.WARNING )*/ - inline fun getKey(folder: String, path: String, defVal: T?): T? = - CloudStreamApp.getKey(folder, path, defVal) + inline fun getKey(folder: String, path: String, defVal: T?): T? { + return context?.getKey(folder, path, defVal) + } } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/CloudStreamApp.kt b/app/src/main/java/com/lagradost/cloudstream3/CloudStreamApp.kt index 6421f38c2..b78327998 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/CloudStreamApp.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/CloudStreamApp.kt @@ -86,6 +86,8 @@ class CloudStreamApp : Application(), SingletonImageLoader.Factory { override fun attachBaseContext(base: Context?) { super.attachBaseContext(base) context = base + // This can be removed without deprecation after next stable + AcraApplication.context = context } override fun newImageLoader(context: PlatformContext): ImageLoader { From 7fb6f3f5353306699f9a9779f96cd8797a37f5b8 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 27 Nov 2025 11:37:47 -0700 Subject: [PATCH 160/513] Add explicit dependsOn for copyJar (#2261) --- .github/workflows/prerelease.yml | 4 +--- app/build.gradle.kts | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 62fd571f7..164a8458e 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -48,9 +48,7 @@ jobs: echo "key_pwd=$KEY_PWD" >> $GITHUB_OUTPUT - name: Run Gradle - run: | - ./gradlew assemblePrerelease build androidSourcesJar - ./gradlew makeJar # for classes.jar, has to be done after assemblePrerelease + run: ./gradlew assemblePrerelease build androidSourcesJar makeJar env: SIGNING_KEY_ALIAS: "key0" SIGNING_KEY_PASSWORD: ${{ steps.fetch_keystore.outputs.key_pwd }} diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6cc801591..c0e55071b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -241,6 +241,7 @@ tasks.register("androidSourcesJar") { } tasks.register("copyJar") { + dependsOn("build", ":library:jvmJar") from( "build/intermediates/compile_app_classes_jar/prereleaseDebug/bundlePrereleaseDebugClassesToCompileJar", "../library/build/libs" From 38296bfb1a791d07e4611068b292a2537c51dbad Mon Sep 17 00:00:00 2001 From: Osten <11805592+LagradOst@users.noreply.github.com> Date: Fri, 28 Nov 2025 21:24:31 +0100 Subject: [PATCH 161/513] Fixed the atrocity of download selection along with some crash fixes and bugs. --- .../lagradost/cloudstream3/ui/BaseFragment.kt | 29 +- .../ui/download/DownloadAdapter.kt | 491 +++++++++--------- .../ui/download/DownloadChildFragment.kt | 45 +- .../ui/download/DownloadFragment.kt | 42 +- .../ui/download/DownloadViewModel.kt | 176 ++++--- .../ui/settings/SettingsFragment.kt | 3 +- .../ui/settings/extensions/PluginsFragment.kt | 4 +- .../cloudstream3/utils/ConsistentLiveData.kt | 44 ++ 8 files changed, 464 insertions(+), 370 deletions(-) create mode 100644 app/src/main/java/com/lagradost/cloudstream3/utils/ConsistentLiveData.kt diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/BaseFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/BaseFragment.kt index 14901dda2..72955e7cf 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/BaseFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/BaseFragment.kt @@ -126,6 +126,33 @@ abstract class BaseFragment( ) : Fragment(), BaseFragmentHelper { override var _binding: T? = null + /** Safer activity?.onBackPressedDispatcher?.onBackPressed() with fallback behavior instead of app crash */ + fun dispatchBackPressed() { + try { + activity?.onBackPressedDispatcher?.onBackPressed() + } catch (_: IllegalStateException) { + // FragmentManager is already executing transactions, so try again + delayedDispatchBackPressed(5) + } catch (t: Throwable) { + logError(t) + } + } + + /** Recursive back press when available */ + private fun delayedDispatchBackPressed(remaining: Int) { + if (remaining <= 0) return + binding?.root?.postDelayed({ + try { + activity?.onBackPressedDispatcher?.onBackPressed() + } catch (_: IllegalStateException) { + // FragmentManager is already executing transactions, so try again + delayedDispatchBackPressed(remaining - 1) + } catch (t: Throwable) { + logError(t) + } + }, 200) + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -238,7 +265,7 @@ abstract class BaseBottomSheetDialogFragment( } } -abstract class BasePreferenceFragmentCompat(): PreferenceFragmentCompat() { +abstract class BasePreferenceFragmentCompat() : PreferenceFragmentCompat() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setSystemBarsPadding() diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadAdapter.kt index e6daf0f2f..b26e99d81 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadAdapter.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadAdapter.kt @@ -1,5 +1,6 @@ package com.lagradost.cloudstream3.ui.download +import android.annotation.SuppressLint import android.text.format.Formatter.formatShortFileSize import android.view.LayoutInflater import android.view.ViewGroup @@ -7,16 +8,15 @@ import android.widget.CheckBox import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView import androidx.viewbinding.ViewBinding import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.databinding.DownloadChildEpisodeBinding import com.lagradost.cloudstream3.databinding.DownloadHeaderEpisodeBinding import com.lagradost.cloudstream3.mvvm.logError +import com.lagradost.cloudstream3.ui.NoStateAdapter +import com.lagradost.cloudstream3.ui.ViewHolderState import com.lagradost.cloudstream3.ui.download.button.DownloadStatusTell import com.lagradost.cloudstream3.utils.AppContextUtils.getNameFull -import com.lagradost.cloudstream3.utils.DataStoreHelper.fixVisual import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos import com.lagradost.cloudstream3.utils.ImageLoader.loadImage import com.lagradost.cloudstream3.utils.VideoDownloadHelper @@ -69,7 +69,7 @@ class DownloadAdapter( private val onHeaderClickEvent: (DownloadHeaderClickEvent) -> Unit, private val onItemClickEvent: (DownloadClickEvent) -> Unit, private val onItemSelectionChanged: (Int, Boolean) -> Unit, -) : ListAdapter(DiffCallback()) { +) : NoStateAdapter(DiffCallback()) { private var isMultiDeleteState: Boolean = false @@ -78,97 +78,194 @@ class DownloadAdapter( private const val VIEW_TYPE_CHILD = 1 } - inner class DownloadViewHolder( - private val binding: ViewBinding - ) : RecyclerView.ViewHolder(binding.root) { - fun bind(card: VisualDownloadCached?) { - when (binding) { - is DownloadHeaderEpisodeBinding -> bindHeader(card as? VisualDownloadCached.Header) - is DownloadChildEpisodeBinding -> bindChild(card as? VisualDownloadCached.Child) - } - } - - private fun bindHeader(card: VisualDownloadCached.Header?) { - if (binding !is DownloadHeaderEpisodeBinding || card == null) return - - val data = card.data - binding.apply { - episodeHolder.apply { - if (isMultiDeleteState) { - setOnClickListener { - toggleIsChecked(deleteCheckbox, data.id) - } - } - - setOnLongClickListener { - toggleIsChecked(deleteCheckbox, data.id) - true - } - } - - downloadHeaderPoster.apply { - loadImage(data.poster) - if (isMultiDeleteState) { - setOnClickListener { - toggleIsChecked(deleteCheckbox, data.id) - } - } else { - setOnClickListener { - onHeaderClickEvent.invoke( - DownloadHeaderClickEvent( - DOWNLOAD_ACTION_LOAD_RESULT, - data - ) - ) - } - } - - setOnLongClickListener { - toggleIsChecked(deleteCheckbox, data.id) - true - } - } - downloadHeaderTitle.text = data.name - val formattedSize = formatShortFileSize(itemView.context, card.totalBytes) - - if (card.child != null) { - handleChildDownload(card, formattedSize) - } else handleParentDownload(card, formattedSize) + private fun bindHeader(binding: ViewBinding, card: VisualDownloadCached.Header?) { + if (binding !is DownloadHeaderEpisodeBinding || card == null) return + val data = card.data + binding.apply { + episodeHolder.apply { if (isMultiDeleteState) { - deleteCheckbox.setOnCheckedChangeListener { _, isChecked -> - onItemSelectionChanged.invoke(data.id, isChecked) + setOnClickListener { + toggleIsChecked(deleteCheckbox, data.id) } - } else deleteCheckbox.setOnCheckedChangeListener(null) + setOnLongClickListener { + toggleIsChecked(deleteCheckbox, data.id) + true + } + } else { + setOnLongClickListener { + onItemSelectionChanged.invoke(data.id, true) + true + } + } + } - deleteCheckbox.apply { - isVisible = isMultiDeleteState - isChecked = card.isSelected + downloadHeaderPoster.apply { + loadImage(data.poster) + if (isMultiDeleteState) { + setOnClickListener { + toggleIsChecked(deleteCheckbox, data.id) + } + } else { + setOnClickListener { + onHeaderClickEvent.invoke( + DownloadHeaderClickEvent( + DOWNLOAD_ACTION_LOAD_RESULT, + data + ) + ) + } + } + + setOnLongClickListener { + toggleIsChecked(deleteCheckbox, data.id) + true + } + } + downloadHeaderTitle.text = data.name + val formattedSize = formatShortFileSize(binding.root.context, card.totalBytes) + + if (card.child != null) { + handleChildDownload(card, formattedSize) + } else handleParentDownload(card, formattedSize) + + if (isMultiDeleteState) { + deleteCheckbox.setOnCheckedChangeListener { _, isChecked -> + onItemSelectionChanged.invoke(data.id, isChecked) + } + } else deleteCheckbox.setOnCheckedChangeListener(null) + + deleteCheckbox.apply { + isVisible = isMultiDeleteState + isChecked = card.isSelected + } + } + } + + private fun DownloadHeaderEpisodeBinding.handleChildDownload( + card: VisualDownloadCached.Header, + formattedSize: String + ) { + card.child ?: return + downloadHeaderGotoChild.isVisible = false + + val posDur = getViewPos(card.data.id) + watchProgressContainer.isVisible = true + downloadHeaderEpisodeProgress.apply { + isVisible = posDur != null + posDur?.let { + val max = (it.duration / 1000).toInt() + val progress = (it.position / 1000).toInt() + + if (max > 0 && progress >= (0.95 * max).toInt()) { + playIcon.setImageResource(R.drawable.ic_baseline_check_24) + isVisible = false + } else { + playIcon.setImageResource(R.drawable.netflix_play) + this.max = max + this.progress = progress + isVisible = true } } } - private fun DownloadHeaderEpisodeBinding.handleChildDownload( - card: VisualDownloadCached.Header, - formattedSize: String - ) { - card.child ?: return - downloadHeaderGotoChild.isVisible = false + val status = downloadButton.getStatus(card.child.id, card.currentBytes, card.totalBytes) + if (status == DownloadStatusTell.IsDone) { + // We do this here instead if we are finished downloading + // so that we can use the value from the view model + // rather than extra unneeded disk operations and to prevent a + // delay in updating download icon state. + downloadButton.setProgress(card.currentBytes, card.totalBytes) + downloadButton.applyMetaData(card.child.id, card.currentBytes, card.totalBytes) + // We will let the view model handle this + downloadButton.doSetProgress = false + downloadButton.progressBar.progressDrawable = + downloadButton.getDrawableFromStatus(status) + ?.let { ContextCompat.getDrawable(downloadButton.context, it) } + downloadHeaderInfo.text = formattedSize + } else { + // We need to make sure we restore the correct progress + // when we refresh data in the adapter. + downloadButton.resetView() + val drawable = downloadButton.getDrawableFromStatus(status)?.let { + ContextCompat.getDrawable(downloadButton.context, it) + } + downloadButton.statusView.setImageDrawable(drawable) + downloadButton.progressBar.progressDrawable = + ContextCompat.getDrawable( + downloadButton.context, + downloadButton.progressDrawable + ) + } - val posDur = getViewPos(card.data.id) - watchProgressContainer.isVisible = true - downloadHeaderEpisodeProgress.apply { + downloadButton.setDefaultClickListener(card.child, downloadHeaderInfo, onItemClickEvent) + downloadButton.isVisible = !isMultiDeleteState + + if (!isMultiDeleteState) { + episodeHolder.setOnClickListener { + onItemClickEvent.invoke( + DownloadClickEvent( + DOWNLOAD_ACTION_PLAY_FILE, + card.child + ) + ) + } + } + } + + private fun DownloadHeaderEpisodeBinding.handleParentDownload( + card: VisualDownloadCached.Header, + formattedSize: String + ) { + downloadButton.isVisible = false + downloadHeaderEpisodeProgress.isVisible = false + downloadHeaderGotoChild.isVisible = !isMultiDeleteState + + try { + downloadHeaderInfo.text = + downloadHeaderInfo.context.getString(R.string.extra_info_format).format( + card.totalDownloads, + downloadHeaderInfo.context.resources.getQuantityString( + R.plurals.episodes, + card.totalDownloads + ), + formattedSize + ) + } catch (e: Exception) { + downloadHeaderInfo.text = null + logError(e) + } + + if (!isMultiDeleteState) { + episodeHolder.setOnClickListener { + onHeaderClickEvent.invoke( + DownloadHeaderClickEvent( + DOWNLOAD_ACTION_GO_TO_CHILD, + card.data + ) + ) + } + } + } + + private fun bindChild(binding: ViewBinding, card: VisualDownloadCached.Child?) { + if (binding !is DownloadChildEpisodeBinding || card == null) return + + val data = card.data + binding.apply { + val posDur = getViewPos(data.id) + downloadChildEpisodeProgress.apply { isVisible = posDur != null posDur?.let { val max = (it.duration / 1000).toInt() val progress = (it.position / 1000).toInt() if (max > 0 && progress >= (0.95 * max).toInt()) { - playIcon.setImageResource(R.drawable.ic_baseline_check_24) + downloadChildEpisodePlay.setImageResource(R.drawable.ic_baseline_check_24) isVisible = false } else { - playIcon.setImageResource(R.drawable.netflix_play) + downloadChildEpisodePlay.setImageResource(R.drawable.play_button_transparent) this.max = max this.progress = progress isVisible = true @@ -176,20 +273,21 @@ class DownloadAdapter( } } - val status = downloadButton.getStatus(card.child.id, card.currentBytes, card.totalBytes) + val status = downloadButton.getStatus(data.id, card.currentBytes, card.totalBytes) if (status == DownloadStatusTell.IsDone) { // We do this here instead if we are finished downloading // so that we can use the value from the view model // rather than extra unneeded disk operations and to prevent a // delay in updating download icon state. downloadButton.setProgress(card.currentBytes, card.totalBytes) - downloadButton.applyMetaData(card.child.id, card.currentBytes, card.totalBytes) + downloadButton.applyMetaData(data.id, card.currentBytes, card.totalBytes) // We will let the view model handle this downloadButton.doSetProgress = false downloadButton.progressBar.progressDrawable = downloadButton.getDrawableFromStatus(status) ?.let { ContextCompat.getDrawable(downloadButton.context, it) } - downloadHeaderInfo.text = formattedSize + downloadChildEpisodeTextExtra.text = + formatShortFileSize(downloadChildEpisodeTextExtra.context, card.totalBytes) } else { // We need to make sure we restore the correct progress // when we refresh data in the adapter. @@ -205,208 +303,105 @@ class DownloadAdapter( ) } - downloadButton.setDefaultClickListener(card.child, downloadHeaderInfo, onItemClickEvent) + downloadButton.setDefaultClickListener( + data, + downloadChildEpisodeTextExtra, + onItemClickEvent + ) downloadButton.isVisible = !isMultiDeleteState - if (!isMultiDeleteState) { - episodeHolder.setOnClickListener { - onItemClickEvent.invoke( - DownloadClickEvent( - DOWNLOAD_ACTION_PLAY_FILE, - card.child - ) - ) - } - } - } - - private fun DownloadHeaderEpisodeBinding.handleParentDownload( - card: VisualDownloadCached.Header, - formattedSize: String - ) { - downloadButton.isVisible = false - downloadHeaderEpisodeProgress.isVisible = false - downloadHeaderGotoChild.isVisible = !isMultiDeleteState - - try { - downloadHeaderInfo.text = - downloadHeaderInfo.context.getString(R.string.extra_info_format).format( - card.totalDownloads, - downloadHeaderInfo.context.resources.getQuantityString( - R.plurals.episodes, - card.totalDownloads - ), - formattedSize - ) - } catch (e: Exception) { - downloadHeaderInfo.text = null - logError(e) + downloadChildEpisodeText.apply { + text = context.getNameFull(data.name, data.episode, data.season) + isSelected = true // Needed for text repeating } - if (!isMultiDeleteState) { - episodeHolder.setOnClickListener { - onHeaderClickEvent.invoke( - DownloadHeaderClickEvent( - DOWNLOAD_ACTION_GO_TO_CHILD, - card.data - ) - ) - } + downloadChildEpisodeHolder.setOnClickListener { + onItemClickEvent.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, data)) } - } - private fun bindChild(card: VisualDownloadCached.Child?) { - if (binding !is DownloadChildEpisodeBinding || card == null) return - - val data = card.data - binding.apply { - val posDur = getViewPos(data.id) - downloadChildEpisodeProgress.apply { - isVisible = posDur != null - posDur?.let { - val max = (it.duration / 1000).toInt() - val progress = (it.position / 1000).toInt() - - if (max > 0 && progress >= (0.95 * max).toInt()) { - downloadChildEpisodePlay.setImageResource(R.drawable.ic_baseline_check_24) - isVisible = false - } else { - downloadChildEpisodePlay.setImageResource(R.drawable.play_button_transparent) - this.max = max - this.progress = progress - isVisible = true + downloadChildEpisodeHolder.apply { + when { + isMultiDeleteState -> { + setOnClickListener { + toggleIsChecked(deleteCheckbox, data.id) + } + setOnLongClickListener { + toggleIsChecked(deleteCheckbox, data.id) + true } } - } - val status = downloadButton.getStatus(data.id, card.currentBytes, card.totalBytes) - if (status == DownloadStatusTell.IsDone) { - // We do this here instead if we are finished downloading - // so that we can use the value from the view model - // rather than extra unneeded disk operations and to prevent a - // delay in updating download icon state. - downloadButton.setProgress(card.currentBytes, card.totalBytes) - downloadButton.applyMetaData(data.id, card.currentBytes, card.totalBytes) - // We will let the view model handle this - downloadButton.doSetProgress = false - downloadButton.progressBar.progressDrawable = - downloadButton.getDrawableFromStatus(status) - ?.let { ContextCompat.getDrawable(downloadButton.context, it) } - downloadChildEpisodeTextExtra.text = - formatShortFileSize(downloadChildEpisodeTextExtra.context, card.totalBytes) - } else { - // We need to make sure we restore the correct progress - // when we refresh data in the adapter. - downloadButton.resetView() - val drawable = downloadButton.getDrawableFromStatus(status)?.let { - ContextCompat.getDrawable(downloadButton.context, it) - } - downloadButton.statusView.setImageDrawable(drawable) - downloadButton.progressBar.progressDrawable = - ContextCompat.getDrawable( - downloadButton.context, - downloadButton.progressDrawable - ) - } - - downloadButton.setDefaultClickListener( - data, - downloadChildEpisodeTextExtra, - onItemClickEvent - ) - downloadButton.isVisible = !isMultiDeleteState - - downloadChildEpisodeText.apply { - text = context.getNameFull(data.name, data.episode, data.season) - isSelected = true // Needed for text repeating - } - - downloadChildEpisodeHolder.setOnClickListener { - onItemClickEvent.invoke(DownloadClickEvent(DOWNLOAD_ACTION_PLAY_FILE, data)) - } - - downloadChildEpisodeHolder.apply { - when { - isMultiDeleteState -> { - setOnClickListener { - toggleIsChecked(deleteCheckbox, data.id) - } - } - - else -> { - setOnClickListener { - onItemClickEvent.invoke( - DownloadClickEvent( - DOWNLOAD_ACTION_PLAY_FILE, - data - ) + else -> { + setOnClickListener { + onItemClickEvent.invoke( + DownloadClickEvent( + DOWNLOAD_ACTION_PLAY_FILE, + data ) - } + ) + } + + setOnLongClickListener { + onItemSelectionChanged.invoke(data.id, true) + true } } - - setOnLongClickListener { - toggleIsChecked(deleteCheckbox, data.id) - true - } } + } - if (isMultiDeleteState) { - deleteCheckbox.setOnCheckedChangeListener { _, isChecked -> - onItemSelectionChanged.invoke(data.id, isChecked) - } - } else deleteCheckbox.setOnCheckedChangeListener(null) - - deleteCheckbox.apply { - isVisible = isMultiDeleteState - isChecked = card.isSelected + if (isMultiDeleteState) { + deleteCheckbox.setOnCheckedChangeListener { _, isChecked -> + onItemSelectionChanged.invoke(data.id, isChecked) } + } else deleteCheckbox.setOnCheckedChangeListener(null) + + deleteCheckbox.apply { + isVisible = isMultiDeleteState + isChecked = card.isSelected } } } - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DownloadViewHolder { + override fun onCreateCustomContent(parent: ViewGroup, viewType: Int): ViewHolderState { val inflater = LayoutInflater.from(parent.context) val binding = when (viewType) { VIEW_TYPE_HEADER -> DownloadHeaderEpisodeBinding.inflate(inflater, parent, false) VIEW_TYPE_CHILD -> DownloadChildEpisodeBinding.inflate(inflater, parent, false) else -> throw IllegalArgumentException("Invalid view type") } - return DownloadViewHolder(binding) + return ViewHolderState(binding) } - override fun onBindViewHolder(holder: DownloadViewHolder, position: Int) { - holder.bind(getItem(position)) - } + override fun onBindContent( + holder: ViewHolderState, + item: VisualDownloadCached, + position: Int + ) { + when (val binding = holder.view) { + is DownloadHeaderEpisodeBinding -> bindHeader( + binding, + item as? VisualDownloadCached.Header + ) - override fun getItemViewType(position: Int): Int { - return when (getItem(position)) { - is VisualDownloadCached.Child -> VIEW_TYPE_CHILD - is VisualDownloadCached.Header -> VIEW_TYPE_HEADER - else -> throw IllegalArgumentException("Invalid data type at position $position") + is DownloadChildEpisodeBinding -> bindChild( + binding, + item as? VisualDownloadCached.Child + ) } } + override fun customContentViewType(item: VisualDownloadCached): Int { + return when (item) { + is VisualDownloadCached.Child -> VIEW_TYPE_CHILD + is VisualDownloadCached.Header -> VIEW_TYPE_HEADER + } + } + + @SuppressLint("NotifyDataSetChanged") fun setIsMultiDeleteState(value: Boolean) { if (isMultiDeleteState == value) return isMultiDeleteState = value - notifyItemRangeChanged(0, itemCount) - } - - fun notifyAllSelected() { - currentList.indices.forEach { index -> - if (!currentList[index].isSelected) { - notifyItemChanged(index) - } - } - } - - fun notifySelectionStates() { - currentList.indices.forEach { index -> - if (currentList[index].isSelected) { - notifyItemChanged(index) - } - } + notifyDataSetChanged() // This is shit, but what can you do? } private fun toggleIsChecked(checkbox: CheckBox, itemId: Int) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildFragment.kt index 980d08a9e..08194fd31 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildFragment.kt @@ -9,6 +9,7 @@ import androidx.core.view.isVisible import androidx.fragment.app.activityViewModels import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.databinding.FragmentChildDownloadsBinding +import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.observe import com.lagradost.cloudstream3.ui.BaseFragment import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick @@ -41,6 +42,7 @@ class DownloadChildFragment : BaseFragment( override fun onDestroyView() { activity?.detachBackPressedCallback("Downloads") + downloadViewModel.clearChildren() super.onDestroyView() } @@ -68,27 +70,22 @@ class DownloadChildFragment : BaseFragment( downloadViewModel.setIsMultiDeleteState(false) } - /** - * We have to make sure selected items are - * cleared here as well so we don't run in an - * inconsistent state where selected items do - * not match the multi delete state we are in. - */ - downloadViewModel.clearSelectedItems() val folder = arguments?.getString("folder") val name = arguments?.getString("name") if (folder == null) { - activity?.onBackPressedDispatcher?.onBackPressed() + dispatchBackPressed() return } + context?.let { downloadViewModel.updateChildList(it, folder) } + binding.downloadChildToolbar.apply { title = name if (isLayout(PHONE or EMULATOR)) { setNavigationIcon(R.drawable.ic_baseline_arrow_back_24) setNavigationOnClickListener { - activity?.onBackPressedDispatcher?.onBackPressed() + dispatchBackPressed() } } setAppBarNoScrollFlagsOnTV() @@ -96,13 +93,18 @@ class DownloadChildFragment : BaseFragment( binding.downloadDeleteAppbar.setAppBarNoScrollFlagsOnTV() - observe(downloadViewModel.childCards) { - if (it.isEmpty()) { - activity?.onBackPressedDispatcher?.onBackPressed() - return@observe + observe(downloadViewModel.childCards) { cards -> + when (cards) { + is Resource.Success -> { + if (cards.value.isEmpty()) { + dispatchBackPressed() + } + (binding.downloadChildList.adapter as? DownloadAdapter)?.submitList(cards.value) + } + else -> { + (binding.downloadChildList.adapter as? DownloadAdapter)?.submitList(null) + } } - - (binding.downloadChildList.adapter as? DownloadAdapter)?.submitList(it) } observe(downloadViewModel.isMultiDeleteState) { isMultiDeleteState -> val adapter = binding.downloadChildList.adapter as? DownloadAdapter @@ -124,7 +126,7 @@ class DownloadChildFragment : BaseFragment( binding.btnDelete.isVisible = it.isNotEmpty() binding.selectItemsText.isVisible = it.isEmpty() - val allSelected = downloadViewModel.isAllSelected() + val allSelected = downloadViewModel.isAllChildrenSelected() if (allSelected) { binding.btnToggleAll.setText(R.string.deselect_all) } else binding.btnToggleAll.setText(R.string.select_all) @@ -156,11 +158,9 @@ class DownloadChildFragment : BaseFragment( nextDown = FOCUS_SELF, ) } - - context?.let { downloadViewModel.updateChildList(it, folder) } } - private fun handleSelectedChange(selected: MutableSet) { + private fun handleSelectedChange(selected: Set) { if (selected.isNotEmpty()) { binding?.downloadDeleteAppbar?.isVisible = true binding?.downloadChildToolbar?.isVisible = false @@ -179,14 +179,11 @@ class DownloadChildFragment : BaseFragment( } binding?.btnToggleAll?.setOnClickListener { - val allSelected = downloadViewModel.isAllSelected() - val adapter = binding?.downloadChildList?.adapter as? DownloadAdapter + val allSelected = downloadViewModel.isAllChildrenSelected() if (allSelected) { - adapter?.notifySelectionStates() downloadViewModel.clearSelectedItems() } else { - adapter?.notifyAllSelected() - downloadViewModel.selectAllItems() + downloadViewModel.selectAllChildren() } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt index 46bb0c7dc..e3d77abac 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt @@ -25,6 +25,7 @@ import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.databinding.FragmentDownloadsBinding import com.lagradost.cloudstream3.databinding.StreamInputBinding import com.lagradost.cloudstream3.isEpisodeBased +import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.safe import com.lagradost.cloudstream3.mvvm.observe import com.lagradost.cloudstream3.ui.BaseFragment @@ -101,19 +102,27 @@ class DownloadFragment : BaseFragment( downloadViewModel.setIsMultiDeleteState(false) } - /** - * We have to make sure selected items are - * cleared here as well so we don't run in an - * inconsistent state where selected items do - * not match the multi delete state we are in. - */ - downloadViewModel.clearSelectedItems() + observe(downloadViewModel.headerCards) { cards -> + when (cards) { + is Resource.Success -> { + (binding.downloadList.adapter as? DownloadAdapter)?.submitList(cards.value) + binding.textNoDownloads.isVisible = cards.value.isEmpty() + binding.downloadLoading.isVisible = false + binding.downloadList.isVisible = true + } - observe(downloadViewModel.headerCards) { - (binding.downloadList.adapter as? DownloadAdapter)?.submitList(it) - binding.downloadLoading.isVisible = false - binding.textNoDownloads.isVisible = it.isEmpty() + is Resource.Loading -> { + binding.downloadList.isVisible = false + binding.downloadLoading.isVisible = true + } + + is Resource.Failure -> { + binding.downloadList.isVisible = true + binding.downloadLoading.isVisible = false + } + } } + observe(downloadViewModel.availableBytes) { updateStorageInfo( binding.root.context, @@ -173,7 +182,7 @@ class DownloadFragment : BaseFragment( binding.btnDelete.isVisible = it.isNotEmpty() binding.selectItemsText.isVisible = it.isEmpty() - val allSelected = downloadViewModel.isAllSelected() + val allSelected = downloadViewModel.isAllHeadersSelected() if (allSelected) { binding.btnToggleAll.setText(R.string.deselect_all) } else binding.btnToggleAll.setText(R.string.select_all) @@ -251,7 +260,7 @@ class DownloadFragment : BaseFragment( } } - private fun handleSelectedChange(selected: MutableSet) { + private fun handleSelectedChange(selected: Set) { if (selected.isNotEmpty()) { binding?.downloadDeleteAppbar?.isVisible = true binding?.downloadAppbar?.isVisible = false @@ -270,14 +279,11 @@ class DownloadFragment : BaseFragment( } binding?.btnToggleAll?.setOnClickListener { - val allSelected = downloadViewModel.isAllSelected() - val adapter = binding?.downloadList?.adapter as? DownloadAdapter + val allSelected = downloadViewModel.isAllHeadersSelected() if (allSelected) { - adapter?.notifySelectionStates() downloadViewModel.clearSelectedItems() } else { - adapter?.notifyAllSelected() - downloadViewModel.selectAllItems() + downloadViewModel.selectAllHeaders() } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadViewModel.kt index 137f1355e..bf81e6069 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadViewModel.kt @@ -6,20 +6,22 @@ import android.os.Environment import android.os.StatFs import androidx.appcompat.app.AlertDialog import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.isEpisodeBased +import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.launchSafe import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.utils.AppContextUtils.getNameFull import com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus +import com.lagradost.cloudstream3.utils.ConsistentLiveData import com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE import com.lagradost.cloudstream3.utils.DOWNLOAD_HEADER_CACHE import com.lagradost.cloudstream3.utils.DataStore.getFolderName import com.lagradost.cloudstream3.utils.DataStore.getKey import com.lagradost.cloudstream3.utils.DataStore.getKeys +import com.lagradost.cloudstream3.utils.ResourceLiveData import com.lagradost.cloudstream3.utils.VideoDownloadHelper import com.lagradost.cloudstream3.utils.VideoDownloadManager.deleteFilesAndUpdateSettings import com.lagradost.cloudstream3.utils.VideoDownloadManager.getDownloadFileInfoAndUpdateSettings @@ -27,69 +29,80 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext class DownloadViewModel : ViewModel() { + private val _headerCards = ResourceLiveData>(Resource.Loading()) + val headerCards: LiveData>> = _headerCards - private val _headerCards = MutableLiveData>() - val headerCards: LiveData> = _headerCards + private val _childCards = ResourceLiveData>(Resource.Loading()) + val childCards: LiveData>> = _childCards - private val _childCards = MutableLiveData>() - val childCards: LiveData> = _childCards - - private val _usedBytes = MutableLiveData() + private val _usedBytes = ConsistentLiveData() val usedBytes: LiveData = _usedBytes - private val _availableBytes = MutableLiveData() + private val _availableBytes = ConsistentLiveData() val availableBytes: LiveData = _availableBytes - private val _downloadBytes = MutableLiveData() + private val _downloadBytes = ConsistentLiveData() val downloadBytes: LiveData = _downloadBytes - private val _selectedBytes = MutableLiveData(0) + private val _selectedBytes = ConsistentLiveData(0) val selectedBytes: LiveData = _selectedBytes - private val _isMultiDeleteState = MutableLiveData(false) + private val _isMultiDeleteState = ConsistentLiveData(false) val isMultiDeleteState: LiveData = _isMultiDeleteState - private val _selectedItemIds = MutableLiveData>(mutableSetOf()) - val selectedItemIds: LiveData> = _selectedItemIds - - private var previousVisual: List? = null + private val _selectedItemIds = ConsistentLiveData>(mutableSetOf()) + val selectedItemIds: LiveData> = _selectedItemIds fun setIsMultiDeleteState(value: Boolean) { _isMultiDeleteState.postValue(value) } fun addSelected(itemId: Int) { - updateSelectedItems { it.add(itemId) } + updateSelectedItems { it + itemId } } fun removeSelected(itemId: Int) { - updateSelectedItems { it.remove(itemId) } + updateSelectedItems { it - itemId } } - fun selectAllItems() { - val items = headerCards.value.orEmpty() + childCards.value.orEmpty() - updateSelectedItems { it.addAll(items.map { item -> item.data.id }) } + fun selectAllHeaders() { + updateSelectedItems { + _headerCards.success.orEmpty() + .map { item -> item.data.id }.toSet() + } + } + + fun selectAllChildren() { + updateSelectedItems { + _childCards.success.orEmpty() + .map { item -> item.data.id }.toSet() + } } fun clearSelectedItems() { // We need this to be done immediately // so we can't use postValue - _selectedItemIds.value = mutableSetOf() - updateSelectedItems { it.clear() } + updateSelectedItems { emptySet() } } - fun isAllSelected(): Boolean { + fun isAllChildrenSelected(): Boolean { val currentSelected = selectedItemIds.value ?: return false - val items = headerCards.value.orEmpty() + childCards.value.orEmpty() - return items.count() == currentSelected.count() && items.all { it.data.id in currentSelected } + val children = _childCards.success.orEmpty() + return currentSelected.size == children.size && children.all { it.data.id in currentSelected } } - private fun updateSelectedItems(action: (MutableSet) -> Unit) { - val currentSelected = selectedItemIds.value ?: mutableSetOf() - action(currentSelected) + fun isAllHeadersSelected(): Boolean { + val currentSelected = selectedItemIds.value ?: return false + val headers = _headerCards.success.orEmpty() + return currentSelected.size == headers.size && headers.all { it.data.id in currentSelected } + } + + private fun updateSelectedItems(action: (Set) -> Set) { + val currentSelected = action(selectedItemIds.value ?: mutableSetOf()) _selectedItemIds.postValue(currentSelected) + postHeaders() + postChildren() updateSelectedBytes() - updateSelectedCards() } private fun updateSelectedBytes() = viewModelScope.launchSafe { @@ -98,25 +111,12 @@ class DownloadViewModel : ViewModel() { _selectedBytes.postValue(totalSelectedBytes) } - private fun updateSelectedCards() = viewModelScope.launchSafe { - val currentSelected = selectedItemIds.value ?: return@launchSafe - - headerCards.value?.let { headers -> - headers.forEach { header -> - header.isSelected = header.data.id in currentSelected - } - _headerCards.postValue(headers) - } - - childCards.value?.let { children -> - children.forEach { child -> - child.isSelected = child.data.id in currentSelected - } - _childCards.postValue(children) - } - } fun updateHeaderList(context: Context) = viewModelScope.launchSafe { + // Do not push loading as it interrupts the UI + //_headerCards.postValue(Resource.Loading()) + clearSelectedItems() + val visual = withContext(Dispatchers.IO) { val children = context.getKeys(DOWNLOAD_EPISODE_CACHE) .mapNotNull { context.getKey(it) } @@ -133,11 +133,32 @@ class DownloadViewModel : ViewModel() { ) } - if (visual != previousVisual) { - previousVisual = visual - updateStorageStats(visual) - _headerCards.postValue(visual) - } + updateStorageStats(visual) + postHeaders(visual) + } + + fun postHeaders(newValue: List? = null) { + val newValue = newValue ?: _headerCards.success ?: return + val selection = selectedItemIds.value ?: emptySet() + _headerCards.postValue(Resource.Success(newValue.map { + it.copy( + isSelected = selection.contains( + it.data.id + ) + ) + })) + } + + fun postChildren(newValue: List? = null) { + val newValue = newValue ?: _childCards.success ?: return + val selection = selectedItemIds.value ?: emptySet() + _childCards.postValue(Resource.Success(newValue.map { + it.copy( + isSelected = selection.contains( + it.data.id + ) + ) + })) } private fun calculateDownloadStats( @@ -152,7 +173,8 @@ class DownloadViewModel : ViewModel() { val totalDownloads = mutableMapOf() children.forEach { child -> - val childFile = getDownloadFileInfoAndUpdateSettings(context, child.id) ?: return@forEach + val childFile = + getDownloadFileInfoAndUpdateSettings(context, child.id) ?: return@forEach if (childFile.fileLength <= 1) return@forEach val len = childFile.totalBytes @@ -179,10 +201,11 @@ class DownloadViewModel : ViewModel() { if (bytes <= 0 || downloads <= 0) return@mapNotNull null val isSelected = selectedItemIds.value?.contains(it.id) ?: false - val movieEpisode = if (it.type.isEpisodeBased()) null else context.getKey( - DOWNLOAD_EPISODE_CACHE, - getFolderName(it.id.toString(), it.id.toString()) - ) + val movieEpisode = + if (it.type.isEpisodeBased()) null else context.getKey( + DOWNLOAD_EPISODE_CACHE, + getFolderName(it.id.toString(), it.id.toString()) + ) VisualDownloadCached.Header( currentBytes = currentBytes, @@ -208,12 +231,16 @@ class DownloadViewModel : ViewModel() { } fun updateChildList(context: Context, folder: String) = viewModelScope.launchSafe { + _childCards.postValue(Resource.Loading()) // always push loading + clearSelectedItems() + val visual = withContext(Dispatchers.IO) { context.getKeys(folder).mapNotNull { key -> context.getKey(key) }.mapNotNull { val isSelected = selectedItemIds.value?.contains(it.id) ?: false - val info = getDownloadFileInfoAndUpdateSettings(context, it.id) ?: return@mapNotNull null + val info = + getDownloadFileInfoAndUpdateSettings(context, it.id) ?: return@mapNotNull null VisualDownloadCached.Child( currentBytes = info.fileLength, totalBytes = info.totalBytes, @@ -221,24 +248,20 @@ class DownloadViewModel : ViewModel() { data = it, ) } - }.sortedWith(compareBy( - // Sort by season first, and then by episode number, - // to ensure sorting is consistent. - { it.data.season ?: 0 }, - { it.data.episode } - )) + }.sortedWith( + compareBy( + // Sort by season first, and then by episode number, + // to ensure sorting is consistent. + { it.data.season ?: 0 }, + { it.data.episode } + )) - if (previousVisual != visual) { - previousVisual = visual - _childCards.postValue(visual) - } + postChildren(visual) } private fun removeItems(idsToRemove: Set) = viewModelScope.launchSafe { - val updatedHeaders = headerCards.value.orEmpty().filter { it.data.id !in idsToRemove } - val updatedChildren = childCards.value.orEmpty().filter { it.data.id !in idsToRemove } - _headerCards.postValue(updatedHeaders) - _childCards.postValue(updatedChildren) + postHeaders(_headerCards.success?.filter { it.data.id !in idsToRemove }) + postChildren(_childCards.success?.filter { it.data.id !in idsToRemove }) } private fun updateStorageStats(visual: List) { @@ -414,8 +437,8 @@ class DownloadViewModel : ViewModel() { } private fun getSelectedItemsData(): List? { - val headers = headerCards.value.orEmpty() - val children = childCards.value.orEmpty() + val headers = _headerCards.success.orEmpty() + val children = _childCards.success.orEmpty() return selectedItemIds.value?.mapNotNull { id -> headers.find { it.data.id == id } ?: children.find { it.data.id == id } @@ -423,10 +446,11 @@ class DownloadViewModel : ViewModel() { } private fun getItemDataFromId(itemId: Int): List { - val headers = headerCards.value.orEmpty() - val children = childCards.value.orEmpty() + return (_headerCards.success.orEmpty() + _childCards.success.orEmpty()).filter { it.data.id == itemId } + } - return (headers + children).filter { it.data.id == itemId } + fun clearChildren() { + _childCards.postValue(Resource.Loading()) } private data class DeleteData( diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt index 6ad0fffc6..c2d5e43e9 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt @@ -16,6 +16,7 @@ import com.lagradost.cloudstream3.BuildConfig import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.databinding.MainSettingsBinding import com.lagradost.cloudstream3.mvvm.logError +import com.lagradost.cloudstream3.mvvm.safe import com.lagradost.cloudstream3.syncproviders.AccountManager import com.lagradost.cloudstream3.syncproviders.AuthRepo import com.lagradost.cloudstream3.ui.BaseFragment @@ -136,7 +137,7 @@ class SettingsFragment : BaseFragment( setNavigationIcon(R.drawable.ic_baseline_arrow_back_24) children.firstOrNull { it is ImageView }?.tag = getString(R.string.tv_no_focus_tag) setNavigationOnClickListener { - activity?.onBackPressedDispatcher?.onBackPressed() + safe { activity?.onBackPressedDispatcher?.onBackPressed() } } } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginsFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginsFragment.kt index 152131111..ee333abad 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginsFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/PluginsFragment.kt @@ -66,7 +66,7 @@ class PluginsFragment : BaseFragment( val downloadAllButton = binding.settingsToolbar.menu?.findItem(R.id.download_all) if (url == null || name == null) { - activity?.onBackPressedDispatcher?.onBackPressed() + dispatchBackPressed() return } @@ -126,7 +126,7 @@ class PluginsFragment : BaseFragment( if (searchView?.isIconified == false) { searchView.isIconified = true } else { - activity?.onBackPressedDispatcher?.onBackPressed() + dispatchBackPressed() } } searchView?.setOnQueryTextFocusChangeListener { _, hasFocus -> diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/ConsistentLiveData.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ConsistentLiveData.kt new file mode 100644 index 000000000..7bb777bc4 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ConsistentLiveData.kt @@ -0,0 +1,44 @@ +package com.lagradost.cloudstream3.utils + +import androidx.annotation.MainThread +import androidx.lifecycle.LiveData +import com.lagradost.cloudstream3.mvvm.Resource + +/** + * This is an atomic LiveData where you can do .value instantly after doing .postValue + * + * Fuck all that is LiveData, because we want this value to be accessible everywhere instantly. + * */ +open class ConsistentLiveData(initValue : T? = null) : LiveData() { + @Volatile private var internalValue : T? = initValue + + override fun getValue(): T? { + return internalValue + } + + /** If someone want the old behavior then good for them */ + val postedValue : T? get() = super.getValue() + + public override fun postValue(value : T?) { + super.postValue(value) + internalValue = value + } + + @MainThread + public override fun setValue(value: T?) { + super.setValue(value) + internalValue = value + } +} + +/** Atomic resource livedata, to make it easier to work with resources without local copies */ +class ResourceLiveData(initValue : Resource? = null) : ConsistentLiveData>(initValue) { + var success + get() = when(val output = this.value) { + is Resource.Success -> { + output.value + } + else -> null + } + set(value) = this.postValue(value?.let { Resource.Success(it) } ) +} From 1aa6a6215df2dc994e3a3f851d2fbba775749cbf Mon Sep 17 00:00:00 2001 From: Osten <11805592+LagradOst@users.noreply.github.com> Date: Fri, 28 Nov 2025 21:37:55 +0100 Subject: [PATCH 162/513] Minor fix to ConsistentLiveData --- .../com/lagradost/cloudstream3/utils/ConsistentLiveData.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/ConsistentLiveData.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ConsistentLiveData.kt index 7bb777bc4..def41d7a0 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/ConsistentLiveData.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ConsistentLiveData.kt @@ -5,11 +5,14 @@ import androidx.lifecycle.LiveData import com.lagradost.cloudstream3.mvvm.Resource /** - * This is an atomic LiveData where you can do .value instantly after doing .postValue + * This is an atomic LiveData where you can do .value instantly after doing .postValue. + * + * The default behavior is a footgun that will cause race conditions, + * as we do not really care if it is posted as we only want the latest data (even in the binding). * * Fuck all that is LiveData, because we want this value to be accessible everywhere instantly. * */ -open class ConsistentLiveData(initValue : T? = null) : LiveData() { +open class ConsistentLiveData(initValue : T? = null) : LiveData(initValue) { @Volatile private var internalValue : T? = initValue override fun getValue(): T? { From b68fadc956b789e5d1b26c8649f784537de29ca9 Mon Sep 17 00:00:00 2001 From: Osten <11805592+LagradOst@users.noreply.github.com> Date: Sun, 30 Nov 2025 00:24:08 +0100 Subject: [PATCH 163/513] Minor fixes to recycled DownloadAdapter cards --- .../com/lagradost/cloudstream3/ui/download/DownloadAdapter.kt | 4 ++++ .../cloudstream3/ui/download/button/BaseFetchButton.kt | 1 + 2 files changed, 5 insertions(+) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadAdapter.kt index b26e99d81..d0740f66a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadAdapter.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadAdapter.kt @@ -199,6 +199,7 @@ class DownloadAdapter( ) } + downloadHeaderInfo.isVisible = true downloadButton.setDefaultClickListener(card.child, downloadHeaderInfo, onItemClickEvent) downloadButton.isVisible = !isMultiDeleteState @@ -218,11 +219,14 @@ class DownloadAdapter( card: VisualDownloadCached.Header, formattedSize: String ) { + downloadButton.resetViewData() + watchProgressContainer.isVisible = false downloadButton.isVisible = false downloadHeaderEpisodeProgress.isVisible = false downloadHeaderGotoChild.isVisible = !isMultiDeleteState try { + downloadHeaderInfo.isVisible = true downloadHeaderInfo.text = downloadHeaderInfo.context.getString(R.string.extra_info_format).format( card.totalDownloads, diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/button/BaseFetchButton.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/button/BaseFetchButton.kt index 908e3a80a..36a84d9f3 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/button/BaseFetchButton.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/button/BaseFetchButton.kt @@ -62,6 +62,7 @@ abstract class BaseFetchButton(context: Context, attributeSet: AttributeSet) : open fun resetViewData() { // lastRequest = null + progressText = null isZeroBytes = true doSetProgress = true persistentId = null From d794f6182efe9cecf1118bc1ec51d85fa2bc3783 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sun, 30 Nov 2025 12:11:05 -0700 Subject: [PATCH 164/513] Add Prerelease annotation to extractors that are not in stable (#2281) --- .../com/lagradost/cloudstream3/extractors/HubCloud.kt | 2 ++ .../com/lagradost/cloudstream3/extractors/OkRuExtractor.kt | 4 ++++ .../cloudstream3/extractors/PixelDrainExtractor.kt | 6 +++--- .../com/lagradost/cloudstream3/extractors/VkExtractor.kt | 2 ++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HubCloud.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HubCloud.kt index f8b289469..d8a3fb1ec 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HubCloud.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HubCloud.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors import com.lagradost.api.Log +import com.lagradost.cloudstream3.Prerelease import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.amap import com.lagradost.cloudstream3.app @@ -11,6 +12,7 @@ import com.lagradost.cloudstream3.utils.loadExtractor import com.lagradost.cloudstream3.utils.newExtractorLink import java.net.URI +@Prerelease class HubCloud : ExtractorApi() { override val name = "Hub-Cloud" override val mainUrl = "https://hubcloud.*" diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/OkRuExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/OkRuExtractor.kt index d9803fa3e..f5f258cfe 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/OkRuExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/OkRuExtractor.kt @@ -2,6 +2,8 @@ package com.lagradost.cloudstream3.extractors +import com.lagradost.cloudstream3.Prerelease + open class OkRuSSL : Odnoklassniki() { override var name = "OkRuSSL" override var mainUrl = "https://ok.ru" @@ -12,10 +14,12 @@ open class OkRuHTTP : Odnoklassniki() { override var mainUrl = "http://ok.ru" } +@Prerelease class OkRuSSLMobile : OkRuSSL() { override var mainUrl = "https://m.ok.ru" } +@Prerelease class OkRuHTTPMobile : OkRuHTTP() { override var mainUrl = "http://m.ok.ru" } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/PixelDrainExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/PixelDrainExtractor.kt index 4651f769a..3426289f8 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/PixelDrainExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/PixelDrainExtractor.kt @@ -5,9 +5,11 @@ package com.lagradost.cloudstream3.extractors import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.utils.* -class PixelDrainDev : PixelDrain(){ +@Prerelease +class PixelDrainDev : PixelDrain() { override var mainUrl = "https://pixeldrain.dev" } + open class PixelDrain : ExtractorApi() { override val name = "PixelDrain" override val mainUrl = "https://pixeldrain.com" @@ -40,5 +42,3 @@ open class PixelDrain : ExtractorApi() { } } } - - diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VkExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VkExtractor.kt index 8e4540874..5009cea3e 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VkExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VkExtractor.kt @@ -1,6 +1,7 @@ // Made by @kraptor123 for cs-kraptor package com.lagradost.cloudstream3.extractors +import com.lagradost.cloudstream3.Prerelease import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.utils.ExtractorApi @@ -9,6 +10,7 @@ import com.lagradost.cloudstream3.utils.ExtractorLinkType import com.lagradost.cloudstream3.utils.getQualityFromName import com.lagradost.cloudstream3.utils.newExtractorLink +@Prerelease open class VkExtractor : ExtractorApi() { override val name = "Vk" override val mainUrl = "https://vkvideo.ru" From dad6b92ae3bdc34026a322104b3801a280c76adb Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sun, 30 Nov 2025 12:15:11 -0700 Subject: [PATCH 165/513] Fix downloads loading background (#2279) --- .../main/res/layout/fragment_downloads.xml | 106 +++++++++--------- 1 file changed, 50 insertions(+), 56 deletions(-) diff --git a/app/src/main/res/layout/fragment_downloads.xml b/app/src/main/res/layout/fragment_downloads.xml index 48e8bb074..d6f41d6b0 100644 --- a/app/src/main/res/layout/fragment_downloads.xml +++ b/app/src/main/res/layout/fragment_downloads.xml @@ -266,68 +266,62 @@ - + app:layout_behavior="@string/appbar_scrolling_view_behavior"> - - - - - - - + android:layout_height="match_parent" + android:paddingTop="20dp" + app:shimmer_auto_start="true" + app:shimmer_base_alpha="0.2" + app:shimmer_duration="@integer/loading_time" + app:shimmer_highlight_alpha="0.3" + tools:visibility="gone"> - - - - - - - - + + + + + + + + + + + + + + + Date: Sun, 30 Nov 2025 12:19:52 -0700 Subject: [PATCH 166/513] Fix no poster showing wrong poster (#2278) --- .../ui/search/SearchResultBuilder.kt | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchResultBuilder.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchResultBuilder.kt index 4c0aeb1bb..93526b57e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchResultBuilder.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchResultBuilder.kt @@ -128,18 +128,11 @@ object SearchResultBuilder { cardText?.text = card.name cardText?.isVisible = showTitle cardView.isVisible = true - cardView.loadImage(card.posterUrl, card.posterHeaders) { - error { getImageFromDrawable(itemView.context, R.drawable.default_cover) } - /* - createPaletteAsync is currently disabled as we use hardware acceleration on images - val posterUrl = card.posterUrl - if (posterUrl != null && colorCallback != null) { - this.listener(onSuccess = { _,success -> - val bitmap = success.image.toBitmap() - createPaletteAsync(posterUrl, bitmap, colorCallback) - }) - }*/ - } + if (!card.posterUrl.isNullOrEmpty()) { + cardView.loadImage(card.posterUrl, card.posterHeaders) { + error { getImageFromDrawable(itemView.context, R.drawable.default_cover) } + } + } else cardView.loadImage(R.drawable.default_cover) fun click(view: View?) { clickCallback.invoke( @@ -330,4 +323,4 @@ object SearchResultBuilder { backgroundTintList = ColorStateList.valueOf(context.colorFromAttribute(R.attr.textColor)) } } -} \ No newline at end of file +} From 1dd477a9658e4730f3e67339559ac953612b944e Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sun, 30 Nov 2025 12:21:09 -0700 Subject: [PATCH 167/513] Disable MissingTranslation lint (#2276) Translations are handled by weblate, so we don't really care about missing translations here. --- app/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c0e55071b..e2bdb2079 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -150,6 +150,7 @@ android { lint { abortOnError = false checkReleaseBuilds = false + disable.add("MissingTranslation") } buildFeatures { From 2ac0698bd23dda0d8f3ef8cbee488ce24b6c8cff Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sun, 30 Nov 2025 12:32:20 -0700 Subject: [PATCH 168/513] Handle new Android 16 biometrics error type (#2275) Adds handling for `BiometricManager.BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS` which was added in API level 36. --- .../utils/BiometricAuthenticator.kt | 67 ++++++++++++------- 1 file changed, 44 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/BiometricAuthenticator.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/BiometricAuthenticator.kt index 1d9cf5f46..bce8f09dc 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/BiometricAuthenticator.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/BiometricAuthenticator.kt @@ -1,5 +1,6 @@ package com.lagradost.cloudstream3.utils +import android.annotation.SuppressLint import android.app.Activity import android.app.KeyguardManager import android.content.Context @@ -100,31 +101,51 @@ object BiometricAuthenticator { } private fun isBiometricHardWareAvailable(): Boolean { - // authentication occurs only when this is true and device is truly capable + // Authentication occurs only when this is true and device is truly capable. var result = false - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - when (biometricManager?.canAuthenticate( - DEVICE_CREDENTIAL or BIOMETRIC_STRONG or BIOMETRIC_WEAK - )) { - BiometricManager.BIOMETRIC_SUCCESS -> result = true - BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> result = false - BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> result = false - BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> result = false - BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> result = true - BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> result = true - BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> result = false + when { + Build.VERSION.SDK_INT >= Build.VERSION_CODES.BAKLAVA -> { + @SuppressLint("RestrictedApi") + when (biometricManager?.canAuthenticate( + DEVICE_CREDENTIAL or BIOMETRIC_STRONG or BIOMETRIC_WEAK + )) { + BiometricManager.BIOMETRIC_SUCCESS -> result = true + BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> result = false + BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> result = false + BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> result = false + BiometricManager.BIOMETRIC_ERROR_NOT_ENABLED_FOR_APPS -> result = false + BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> result = true + BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> result = true + BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> result = false + } } - } else { - @Suppress("DEPRECATION") - when (biometricManager?.canAuthenticate()) { - BiometricManager.BIOMETRIC_SUCCESS -> result = true - BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> result = false - BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> result = false - BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> result = false - BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> result = true - BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> result = true - BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> result = false + + Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> { + @Suppress("SwitchIntDef") + when (biometricManager?.canAuthenticate( + DEVICE_CREDENTIAL or BIOMETRIC_STRONG or BIOMETRIC_WEAK + )) { + BiometricManager.BIOMETRIC_SUCCESS -> result = true + BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> result = false + BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> result = false + BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> result = false + BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> result = true + BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> result = true + BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> result = false + } + } + + else -> { + @Suppress("DEPRECATION", "SwitchIntDef") + when (biometricManager?.canAuthenticate()) { + BiometricManager.BIOMETRIC_SUCCESS -> result = true + BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE -> result = false + BiometricManager.BIOMETRIC_ERROR_HW_UNAVAILABLE -> result = false + BiometricManager.BIOMETRIC_ERROR_NONE_ENROLLED -> result = false + BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED -> result = true + BiometricManager.BIOMETRIC_ERROR_UNSUPPORTED -> result = true + BiometricManager.BIOMETRIC_STATUS_UNKNOWN -> result = false + } } } From 81b2718129639efe6d08750d502a53e43a5788a1 Mon Sep 17 00:00:00 2001 From: rockhero1234 <149141736+rockhero1234@users.noreply.github.com> Date: Fri, 5 Dec 2025 05:04:52 +0530 Subject: [PATCH 169/513] horizontal poster in expanded list (#2286) --- .../com/lagradost/cloudstream3/ui/home/HomeFragment.kt | 10 +++++++--- .../lagradost/cloudstream3/ui/search/SearchAdaptor.kt | 5 ++++- .../java/com/lagradost/cloudstream3/utils/UIHelper.kt | 8 ++++---- app/src/main/res/layout/search_result_grid.xml | 2 +- .../main/res/layout/search_result_grid_expanded.xml | 2 +- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt index 30b6b29d9..bc085df7e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt @@ -195,10 +195,10 @@ class HomeFragment : BaseFragment( // Span settings - binding.homeExpandedRecycler.spanCount = currentSpan + binding.homeExpandedRecycler.spanCount = context.getSpanCount(item.isHorizontalImages) binding.homeExpandedRecycler.setRecycledViewPool(SearchAdapter.sharedPool) binding.homeExpandedRecycler.adapter = - SearchAdapter(binding.homeExpandedRecycler) { callback -> + SearchAdapter(binding.homeExpandedRecycler,item.isHorizontalImages) { callback -> handleSearchClickCallback(callback) if (callback.action == SEARCH_ACTION_LOAD || callback.action == SEARCH_ACTION_PLAY_FILE) { bottomSheetDialogBuilder.ownHide() // we hide here because we want to resume it later @@ -238,7 +238,11 @@ class HomeFragment : BaseFragment( }) val spanListener = { span: Int -> - binding.homeExpandedRecycler.spanCount = span + if(item.isHorizontalImages){ + binding.homeExpandedRecycler.spanCount = context.getSpanCount(true) + }else{ + binding.homeExpandedRecycler.spanCount = span + } //(recycle.adapter as SearchAdapter).notifyDataSetChanged() } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchAdaptor.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchAdaptor.kt index 7c763bf42..9338d4942 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchAdaptor.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchAdaptor.kt @@ -32,6 +32,7 @@ class SearchClickCallback( class SearchAdapter( private val resView: AutofitRecyclerView, + private val isHorizontal:Boolean = false, private val clickCallback: (SearchClickCallback) -> Unit, ) : NoStateAdapter(diffCallback = BaseDiffCallback(itemSame = { a, b -> if (a.id != null || b.id != null) { @@ -47,7 +48,9 @@ class SearchAdapter( var hasNext: Boolean = false - private val coverHeight: Int get() = (resView.itemWidth / 0.68).roundToInt() + private val coverRatio = if(isHorizontal) 1.8 else 0.68 + + private val coverHeight: Int get() = (resView.itemWidth / coverRatio).roundToInt() override fun onCreateContent(parent: ViewGroup): ViewHolderState { val inflater = LayoutInflater.from(parent.context) 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 e114abe29..6a8dabada 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/UIHelper.kt @@ -200,10 +200,10 @@ object UIHelper { listView.requestLayout() } - fun Context.getSpanCount(): Int { - val compactView = false - val spanCountLandscape = if (compactView) 2 else 6 - val spanCountPortrait = if (compactView) 1 else 3 + fun Context.getSpanCount(isHorizontal:Boolean=false): Int { +// val compactView = false + val spanCountLandscape = if (isHorizontal) 3 else 6 + val spanCountPortrait = if (isHorizontal) 2 else 3 val orientation = resources.configuration.orientation return if (orientation == Configuration.ORIENTATION_LANDSCAPE) { diff --git a/app/src/main/res/layout/search_result_grid.xml b/app/src/main/res/layout/search_result_grid.xml index 601860b48..02fdf0211 100644 --- a/app/src/main/res/layout/search_result_grid.xml +++ b/app/src/main/res/layout/search_result_grid.xml @@ -14,7 +14,7 @@ Date: Thu, 4 Dec 2025 23:50:56 +0000 Subject: [PATCH 170/513] Fix: Configuration change view invalidation on AutofitRecyclerView popup --- .../cloudstream3/ui/home/HomeFragment.kt | 29 +++++++++---------- .../ui/quicksearch/QuickSearchFragment.kt | 2 +- .../cloudstream3/ui/search/SearchFragment.kt | 2 +- .../com/lagradost/cloudstream3/utils/Event.kt | 25 ++++++++++++++++ 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt index bc085df7e..6c58fac9a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeFragment.kt @@ -16,7 +16,9 @@ import android.widget.ListView import android.widget.TextView import android.widget.Toast import androidx.appcompat.app.AlertDialog +import androidx.core.net.toUri import androidx.core.view.isGone +import androidx.core.view.isInvisible import androidx.core.view.isVisible import androidx.fragment.app.activityViewModels import androidx.preference.PreferenceManager @@ -64,7 +66,7 @@ import com.lagradost.cloudstream3.utils.AppContextUtils.ownShow import com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.DataStoreHelper -import com.lagradost.cloudstream3.utils.Event +import com.lagradost.cloudstream3.utils.EmptyEvent import com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso import com.lagradost.cloudstream3.utils.TvChannelUtils import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe @@ -73,17 +75,15 @@ import com.lagradost.cloudstream3.utils.UIHelper.getSpanCount import com.lagradost.cloudstream3.utils.UIHelper.navigate import com.lagradost.cloudstream3.utils.UIHelper.popupMenuNoIconsAndNoStringRes import com.lagradost.cloudstream3.utils.UIHelper.toPx -import com.lagradost.cloudstream3.utils.txt -import androidx.core.net.toUri -import androidx.core.view.isInvisible private const val TAG = "HomeFragment" class HomeFragment : BaseFragment( - BaseFragment.BindingCreator.Bind(FragmentHomeBinding::bind) + BindingCreator.Bind(FragmentHomeBinding::bind) ) { companion object { - val configEvent = Event() + // Used for configuration changed events to fix any popups that are not attached to a fragment + val configEvent = EmptyEvent() var currentSpan = 1 val listHomepageItems = mutableListOf() @@ -114,6 +114,7 @@ class HomeFragment : BaseFragment( //} // returns a BottomSheetDialog that will be hidden with OwnHidden upon hide, and must be saved to be able call ownShow in onCreateView + fun Activity.loadHomepageList( expand: HomeViewModel.ExpandableHomepageList, deleteCallback: (() -> Unit)? = null, @@ -237,13 +238,12 @@ class HomeFragment : BaseFragment( } }) - val spanListener = { span: Int -> - if(item.isHorizontalImages){ - binding.homeExpandedRecycler.spanCount = context.getSpanCount(true) - }else{ - binding.homeExpandedRecycler.spanCount = span - } - //(recycle.adapter as SearchAdapter).notifyDataSetChanged() + val spanListener = Runnable { + binding.homeExpandedRecycler.spanCount = context.getSpanCount(item.isHorizontalImages) + // We want to rebind everything to update the UI, however we also want to avoid + // any animations ect, this is the easiest way to do this, and the most correct + @SuppressLint("NotifyDataSetChanged") + binding.homeExpandedRecycler.adapter?.notifyDataSetChanged() } configEvent += spanListener @@ -621,8 +621,7 @@ class HomeFragment : BaseFragment( ) // Fix grid - currentSpan = view.context.getSpanCount() - configEvent.invoke(currentSpan) + configEvent.invoke() } @SuppressLint("SetTextI18n") diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/quicksearch/QuickSearchFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/quicksearch/QuickSearchFragment.kt index a716cab41..724276ab7 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/quicksearch/QuickSearchFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/quicksearch/QuickSearchFragment.kt @@ -98,7 +98,7 @@ class QuickSearchFragment : BaseFragment( // Fix grid HomeFragment.currentSpan = view.context.getSpanCount() binding?.quickSearchAutofitResults?.spanCount = HomeFragment.currentSpan - HomeFragment.configEvent.invoke(HomeFragment.currentSpan) + HomeFragment.configEvent.invoke() } override fun onCreateView( 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 d1efe6205..ae31d03fb 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 @@ -220,7 +220,7 @@ class SearchFragment : BaseFragment( // Fix grid currentSpan = view.context.getSpanCount() binding?.searchAutofitResults?.spanCount = currentSpan - HomeFragment.configEvent.invoke(currentSpan) + HomeFragment.configEvent.invoke() } override fun onBindingCreated( diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/Event.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/Event.kt index a0dfe734e..f66da4e5f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/Event.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/Event.kt @@ -24,3 +24,28 @@ class Event { } } } + +class EmptyEvent { + private val observers = mutableSetOf() + + val size: Int get() = observers.size + + operator fun plusAssign(observer: Runnable) { + synchronized(observers) { + observers.add(observer) + } + } + + operator fun minusAssign(observer: Runnable) { + synchronized(observers) { + observers.remove(observer) + } + } + + operator fun invoke() { + synchronized(observers) { + for (observer in observers) + observer.run() + } + } +} From 0b3aa24e66fce2b1428502fc1189f012c764c21d Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 4 Dec 2025 17:09:54 -0700 Subject: [PATCH 171/513] Some cleanup/improvements to layouts (#2274) --- .../player_select_source_and_subs.xml | 1 + .../player_select_source_priority.xml | 5 +- app/src/main/res/layout/add_account_input.xml | 1 + app/src/main/res/layout/add_repo_input.xml | 1 + app/src/main/res/layout/add_site_input.xml | 1 + .../main/res/layout/bottom_input_dialog.xml | 71 ++++++++++--------- .../layout/chromecast_subtitle_settings.xml | 2 +- .../custom_preference_category_material.xml | 3 - .../res/layout/custom_preference_material.xml | 5 -- .../custom_preference_widget_seekbar.xml | 15 ++-- app/src/main/res/layout/empty_layout.xml | 33 ++++----- .../main/res/layout/fragment_extensions.xml | 4 +- app/src/main/res/layout/fragment_player.xml | 1 - .../main/res/layout/fragment_player_tv.xml | 1 - .../res/layout/fragment_plugin_details.xml | 2 +- .../main/res/layout/fragment_result_tv.xml | 2 +- app/src/main/res/layout/fragment_trailer.xml | 1 - app/src/main/res/layout/lock_pin_dialog.xml | 1 + app/src/main/res/layout/options_popup_tv.xml | 4 +- .../main/res/layout/player_custom_layout.xml | 2 +- .../res/layout/player_custom_layout_tv.xml | 1 - .../layout/player_select_source_and_subs.xml | 1 + .../layout/player_select_source_priority.xml | 3 +- app/src/main/res/layout/result_episode.xml | 3 +- app/src/main/res/layout/result_sync.xml | 1 + app/src/main/res/layout/stream_input.xml | 2 + app/src/main/res/layout/subtitle_offset.xml | 1 + app/src/main/res/layout/subtitle_settings.xml | 2 +- .../main/res/layout/trailer_custom_layout.xml | 1 - 29 files changed, 83 insertions(+), 88 deletions(-) diff --git a/app/src/main/res/layout-port/player_select_source_and_subs.xml b/app/src/main/res/layout-port/player_select_source_and_subs.xml index 06aed87fc..4710473d4 100644 --- a/app/src/main/res/layout-port/player_select_source_and_subs.xml +++ b/app/src/main/res/layout-port/player_select_source_and_subs.xml @@ -120,6 +120,7 @@ android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" + android:baselineAligned="false" android:orientation="horizontal"> + tools:text="@string/profile_number" + tools:ignore="LabelFor" /> + xmlns:tools="http://schemas.android.com/tools" + android:nextFocusDown="@id/nginx_text_input" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + android:id="@+id/nginx_text_input" + android:nextFocusRight="@id/cancel_btt" + android:nextFocusLeft="@id/apply_btt" + android:layout_marginBottom="60dp" + android:layout_marginHorizontal="10dp" + android:paddingTop="10dp" + android:requiresFadingEdge="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_rowWeight="1" + android:autofillHints="no" + android:inputType="text" + tools:text="nginx.com" + tools:ignore="LabelFor" /> + android:id="@+id/apply_btt_holder" + android:orientation="horizontal" + android:layout_gravity="bottom" + android:gravity="bottom|end" + android:layout_marginTop="-60dp" + android:layout_width="match_parent" + android:layout_height="60dp"> + android:layout_width="wrap_content" + android:layout_gravity="center_vertical|end" + android:text="@string/sort_apply" + android:id="@+id/apply_btt" + style="@style/WhiteButton" /> + android:layout_width="wrap_content" + android:layout_gravity="center_vertical|end" + android:text="@string/sort_cancel" + android:id="@+id/cancel_btt" + style="@style/BlackButton" /> diff --git a/app/src/main/res/layout/chromecast_subtitle_settings.xml b/app/src/main/res/layout/chromecast_subtitle_settings.xml index b1073190c..92d0bd350 100644 --- a/app/src/main/res/layout/chromecast_subtitle_settings.xml +++ b/app/src/main/res/layout/chromecast_subtitle_settings.xml @@ -12,7 +12,7 @@ diff --git a/app/src/main/res/layout/custom_preference_widget_seekbar.xml b/app/src/main/res/layout/custom_preference_widget_seekbar.xml index 02c5ec1be..132091e5f 100644 --- a/app/src/main/res/layout/custom_preference_widget_seekbar.xml +++ b/app/src/main/res/layout/custom_preference_widget_seekbar.xml @@ -18,13 +18,12 @@ + android:ellipsize="marquee" + tools:ignore="LabelFor" /> @@ -99,9 +96,7 @@ android:layout_width="0dp" android:layout_weight="1" android:layout_height="wrap_content" - android:paddingLeft="@dimen/preference_seekbar_padding_horizontal" android:paddingStart="@dimen/preference_seekbar_padding_horizontal" - android:paddingRight="@dimen/preference_seekbar_padding_horizontal" android:paddingEnd="@dimen/preference_seekbar_padding_horizontal" android:paddingTop="@dimen/preference_seekbar_padding_vertical" android:paddingBottom="@dimen/preference_seekbar_padding_vertical" @@ -113,13 +108,11 @@ - + - - \ No newline at end of file + + diff --git a/app/src/main/res/layout/fragment_extensions.xml b/app/src/main/res/layout/fragment_extensions.xml index fd1d0dade..b7cf4b6cd 100644 --- a/app/src/main/res/layout/fragment_extensions.xml +++ b/app/src/main/res/layout/fragment_extensions.xml @@ -70,8 +70,8 @@ android:nextFocusUp="@id/repo_recycler_view" android:orientation="horizontal" android:padding="10dp" - - android:visibility="visible"> + android:visibility="visible" + android:baselineAligned="false"> diff --git a/app/src/main/res/layout/result_episode.xml b/app/src/main/res/layout/result_episode.xml index 361ec0231..19f668889 100644 --- a/app/src/main/res/layout/result_episode.xml +++ b/app/src/main/res/layout/result_episode.xml @@ -54,7 +54,8 @@ + android:foreground="?android:attr/selectableItemBackgroundBorderless" + android:orientation="horizontal"> @@ -38,6 +39,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="20" + android:autofillHints="no" android:hint="@string/referer" android:inputType="textUri" tools:ignore="LabelFor" /> diff --git a/app/src/main/res/layout/subtitle_offset.xml b/app/src/main/res/layout/subtitle_offset.xml index 6741de807..8570e9a26 100644 --- a/app/src/main/res/layout/subtitle_offset.xml +++ b/app/src/main/res/layout/subtitle_offset.xml @@ -4,6 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + android:baselineAligned="false" android:orientation="horizontal"> From 2c0fa701016da996f2a762942a7c42b02148c947 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 4 Dec 2025 17:12:14 -0700 Subject: [PATCH 172/513] Clear home page adapter pools when reloading (#2272) --- .../java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt index b7a322a84..6df5bbbef 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/home/HomeViewModel.kt @@ -501,6 +501,9 @@ class HomeViewModel : ViewModel() { return@ioSafe } + HomeChildItemAdapter.sharedPool.clear() + ParentItemAdapter.sharedPool.clear() + val api = getApiFromNameNull(preferredApiName) if (preferredApiName == noneApi.name) { // just set to random From b2e06c5966ec6f40d85291b378d73aa8e2629486 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 4 Dec 2025 17:13:38 -0700 Subject: [PATCH 173/513] Remove `BuildConfig.BETA` (#2290) It's unused and can be accessed with `BuildConfig.FLAVOR == "prerelease"` --- app/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e2bdb2079..c386aca89 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -121,7 +121,6 @@ android { create("prerelease") { dimension = "state" resValue("bool", "is_prerelease", "true") - buildConfigField("boolean", "BETA", "true") applicationIdSuffix = ".prerelease" if (signingConfigs.names.contains("prerelease")) { signingConfig = signingConfigs.getByName("prerelease") From cd69597a54290e135972a673c3036a534e474515 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 4 Dec 2025 17:20:08 -0700 Subject: [PATCH 174/513] Move app version to BuildConfig (#2291) Also, the intent seems to be to be to set the version to `-PRE` when in pre release, which doesn't currently work, but this fixes that. --- app/build.gradle.kts | 11 +++++++++- .../ui/settings/SettingsFragment.kt | 3 ++- .../ui/settings/SettingsUpdates.kt | 22 +++++++++++-------- app/src/main/res/layout/main_settings.xml | 6 ++--- app/src/main/res/xml/settings_updates.xml | 3 +-- 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index c386aca89..3a1bdc5f7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -65,7 +65,6 @@ android { versionCode = 67 versionName = "4.6.1" - resValue("string", "app_version", "${defaultConfig.versionName}${versionNameSuffix ?: ""}") resValue("string", "commit_hash", getGitCommitHash()) resValue("bool", "is_prerelease", "false") @@ -79,6 +78,11 @@ android { "BUILD_DATE", "${System.currentTimeMillis()}" ) + buildConfigField( + "String", + "APP_VERSION", + "\"$versionName\"" + ) buildConfigField( "String", "SIMKL_CLIENT_ID", @@ -128,6 +132,11 @@ android { logger.warn("No prerelease signing config!") } versionNameSuffix = "-PRE" + buildConfigField( + "String", + "APP_VERSION", + "\"${defaultConfig.versionName}$versionNameSuffix\"" + ) versionCode = (System.currentTimeMillis() / 60000).toInt() } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt index c2d5e43e9..755620027 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt @@ -246,13 +246,14 @@ class SettingsFragment : BaseFragment( } } - val appVersion = getString(R.string.app_version) + val appVersion = BuildConfig.APP_VERSION val commitInfo = getString(R.string.commit_hash) val buildTimestamp = SimpleDateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.getDefault() ).apply { timeZone = TimeZone.getTimeZone("UTC") }.format(Date(BuildConfig.BUILD_DATE)).replace("UTC", "") + binding.appVersion.text = appVersion binding.buildDate.text = buildTimestamp binding.appVersionInfo.setOnLongClickListener { clipboardHelper(txt(R.string.extension_version), "$appVersion $commitInfo $buildTimestamp") diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt index 30cd00470..0d34cb988 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt @@ -9,6 +9,7 @@ import androidx.navigation.fragment.findNavController import androidx.preference.PreferenceManager import androidx.recyclerview.widget.LinearLayoutManager import com.lagradost.cloudstream3.AutoDownloadMode +import com.lagradost.cloudstream3.BuildConfig import com.lagradost.cloudstream3.CloudStreamApp import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.R @@ -221,18 +222,21 @@ class SettingsUpdates : BasePreferenceFragmentCompat() { return@setOnPreferenceClickListener true } - getPref(R.string.manual_check_update_key)?.setOnPreferenceClickListener { - ioSafe { - if (activity?.runAutoUpdate(false) == false) { - activity?.runOnUiThread { - showToast( - R.string.no_update_found, - Toast.LENGTH_SHORT - ) + getPref(R.string.manual_check_update_key)?.let { pref -> + pref.summary = BuildConfig.APP_VERSION + pref.setOnPreferenceClickListener { + ioSafe { + if (activity?.runAutoUpdate(false) == false) { + activity?.runOnUiThread { + showToast( + R.string.no_update_found, + Toast.LENGTH_SHORT + ) + } } } + return@setOnPreferenceClickListener true } - return@setOnPreferenceClickListener true } getPref(R.string.auto_download_plugins_key)?.setOnPreferenceClickListener { diff --git a/app/src/main/res/layout/main_settings.xml b/app/src/main/res/layout/main_settings.xml index 0b931843d..4a41759e0 100644 --- a/app/src/main/res/layout/main_settings.xml +++ b/app/src/main/res/layout/main_settings.xml @@ -115,12 +115,12 @@ android:orientation="horizontal"> + android:textColor="?attr/textColor" + tools:text="0.0.0" /> + app:key="@string/manual_check_update_key" /> Date: Thu, 4 Dec 2025 17:25:18 -0700 Subject: [PATCH 175/513] Bump material (#2241) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8e22a64b2..4c507ef2b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,7 +25,7 @@ juniversalchardet = "2.5.0" kotlinGradlePlugin = "2.2.21" kotlinxCoroutinesCore = "1.10.2" lifecycleKtx = "2.9.4" -material = "1.14.0-alpha06" +material = "1.14.0-alpha07" media3 = "1.8.0" navigationKtx = "2.9.6" newpipeextractor = "v0.24.8" From 93255dfc22b03db2cbfba23d8a22f3eb5e5bc3fb Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 4 Dec 2025 17:33:30 -0700 Subject: [PATCH 176/513] Add explicit dependency on fragment (#2233) As with some of my other PRs, explicit dependencies allow for better version control. --- app/build.gradle.kts | 1 + gradle/libs.versions.toml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3a1bdc5f7..d16730d4b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -182,6 +182,7 @@ dependencies { implementation(libs.core.ktx) implementation(libs.activity.ktx) implementation(libs.appcompat) + implementation(libs.fragment.ktx) implementation(libs.bundles.lifecycle) implementation(libs.bundles.navigation) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4c507ef2b..ebbc7a2f5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,6 +14,7 @@ coreKtx = "1.17.0" desugar_jdk_libs_nio = "2.1.5" dokkaGradlePlugin = "2.1.0" espressoCore = "3.7.0" +fragmentKtx = "1.8.9" fuzzywuzzy = "1.4.0" jacksonModuleKotlin = { strictly = "2.13.1" } # Later versions don't support minSdk <26 (Crashes on Android TV's and FireSticks) json = "20250517" @@ -67,6 +68,7 @@ databinding = { module = "androidx.databinding:viewbinding", version.ref = "andr desugar_jdk_libs_nio = { module = "com.android.tools:desugar_jdk_libs_nio", version.ref = "desugar_jdk_libs_nio" } espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espressoCore" } ext-junit = { module = "androidx.test.ext:junit", version.ref = "junitVersion" } +fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "fragmentKtx" } fuzzywuzzy = { module = "me.xdrop:fuzzywuzzy", version.ref = "fuzzywuzzy" } jackson-module-kotlin = { module = "com.fasterxml.jackson.module:jackson-module-kotlin", version.ref = "jacksonModuleKotlin" } json = { module = "org.json:json", version.ref = "json" } From 472d0bab8b7b22a5bdbadb2e0d478781517a56fd Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 4 Dec 2025 17:48:29 -0700 Subject: [PATCH 177/513] Remove unused swiperefreshlayout dependency (#2296) --- app/build.gradle.kts | 1 - gradle/libs.versions.toml | 2 -- 2 files changed, 3 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index d16730d4b..4e58c7ea0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -190,7 +190,6 @@ dependencies { implementation(libs.preference.ktx) implementation(libs.material) implementation(libs.constraintlayout) - implementation(libs.swiperefreshlayout) // Coil Image Loading implementation(libs.bundles.coil) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ebbc7a2f5..2f8556cf4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -40,7 +40,6 @@ qrcodeKotlin = "4.5.0" rhino = "1.8.0" safefile = "0.0.8" shimmer = "0.5.0" -swiperefreshlayout = "1.1.0" tmdbJava = "2.13.0" torrentserver = "7861970e038b35cd8c6918384e49caf26903e09e" tvprovider = "1.1.0" @@ -105,7 +104,6 @@ quickjs = { module = "app.cash.quickjs:quickjs-android", version = "0.9.2" } rhino = { module = "org.mozilla:rhino", version.ref = "rhino" } safefile = { module = "com.github.LagradOst:SafeFile", version.ref = "safefile" } shimmer = { module = "com.facebook.shimmer:shimmer", version.ref = "shimmer" } -swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "swiperefreshlayout" } tmdb-java = { module = "com.uwetrottmann.tmdb2:tmdb-java", version.ref = "tmdbJava" } torrentserver = { module = "com.github.recloudstream:torrentserver", version.ref = "torrentserver" } tvprovider = { module = "androidx.tvprovider:tvprovider", version.ref = "tvprovider" } From f2a008922d449052a3a6ec84e93089ab46d694e7 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 4 Dec 2025 17:51:12 -0700 Subject: [PATCH 178/513] Bump rhino to 1.8.1 (#2295) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2f8556cf4..1015a89c5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -37,7 +37,7 @@ paletteKtx = "1.0.0" preferenceKtx = "1.2.1" previewseekbarMedia3 = "1.1.1.0" qrcodeKotlin = "4.5.0" -rhino = "1.8.0" +rhino = "1.8.1" safefile = "0.0.8" shimmer = "0.5.0" tmdbJava = "2.13.0" From f77df2f3bfc397e0ddac903042243dca973b76a7 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 4 Dec 2025 17:52:24 -0700 Subject: [PATCH 179/513] Use temurin distribution for setup-java action (#2297) Per the note on the README for `actions/setup-java`: "AdoptOpenJDK got moved to Eclipse Temurin and won't be updated anymore. It is highly recommended to migrate workflows from `adopt` and `adopt-openj9`, to `temurin` and `semeru` respectively, to keep receiving software and security updates." --- .github/workflows/build_to_archive.yml | 2 +- .github/workflows/generate_dokka.yml | 2 +- .github/workflows/prerelease.yml | 2 +- .github/workflows/pull_request.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_to_archive.yml b/.github/workflows/build_to_archive.yml index ef7acc9df..ce920002e 100644 --- a/.github/workflows/build_to_archive.yml +++ b/.github/workflows/build_to_archive.yml @@ -38,8 +38,8 @@ jobs: - name: Set up JDK 17 uses: actions/setup-java@v5 with: + distribution: temurin java-version: 17 - distribution: adopt cache: gradle - name: Grant execute permission for gradlew diff --git a/.github/workflows/generate_dokka.yml b/.github/workflows/generate_dokka.yml index e3490730b..e082b79f4 100644 --- a/.github/workflows/generate_dokka.yml +++ b/.github/workflows/generate_dokka.yml @@ -43,8 +43,8 @@ jobs: - name: Set up JDK 17 uses: actions/setup-java@v5 with: + distribution: temurin java-version: 17 - distribution: adopt cache: gradle - name: Set up Android SDK diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index 164a8458e..cee9538bd 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -29,8 +29,8 @@ jobs: - name: Set up JDK 17 uses: actions/setup-java@v5 with: + distribution: temurin java-version: 17 - distribution: adopt cache: gradle - name: Grant execute permission for gradlew diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 023647d2a..0eb363682 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -11,8 +11,8 @@ jobs: - name: Set up JDK 17 uses: actions/setup-java@v5 with: + distribution: temurin java-version: 17 - distribution: adopt cache: gradle - name: Grant execute permission for gradlew From fdad31c10ef4470c538cd977c889d43590002130 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Dec 2025 08:29:57 -0700 Subject: [PATCH 180/513] Add backward compatibility for one more AcraApplication method (#2302) `removeKeys()` only seems to be used by one single extension, but I suppose it doesn't hurt to still add back compat for it. --- .../com/lagradost/cloudstream3/AcraApplication.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/AcraApplication.kt b/app/src/main/java/com/lagradost/cloudstream3/AcraApplication.kt index 262f57522..80f084b08 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/AcraApplication.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/AcraApplication.kt @@ -3,6 +3,7 @@ package com.lagradost.cloudstream3 import android.content.Context import com.lagradost.api.setContext import com.lagradost.cloudstream3.utils.DataStore.getKey +import com.lagradost.cloudstream3.utils.DataStore.removeKeys import com.lagradost.cloudstream3.utils.DataStore.setKey import java.lang.ref.WeakReference @@ -11,8 +12,7 @@ import java.lang.ref.WeakReference * Use CloudStreamApp instead. */ // Deprecate after next stable -/* -@Deprecated( +/*@Deprecated( message = "AcraApplication is deprecated, use CloudStreamApp instead", replaceWith = ReplaceWith("com.lagradost.cloudstream3.CloudStreamApp"), level = DeprecationLevel.WARNING @@ -37,6 +37,15 @@ class AcraApplication { setContext(WeakReference(value)) } + /*@Deprecated( + message = "AcraApplication is deprecated, use CloudStreamApp instead", + replaceWith = ReplaceWith("com.lagradost.cloudstream3.CloudStreamApp.removeKeys(folder)"), + level = DeprecationLevel.WARNING + )*/ + fun removeKeys(folder: String): Int? { + return context?.removeKeys(folder) + } + /*@Deprecated( message = "AcraApplication is deprecated, use CloudStreamApp instead", replaceWith = ReplaceWith("com.lagradost.cloudstream3.CloudStreamApp.setKey(path, value)"), From 1a852f1f4cdd4377600a1799abbd7ef4a9ac2acd Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Dec 2025 08:35:14 -0700 Subject: [PATCH 181/513] Use SharedPreferences.edit extension function (#2299) --- .../lagradost/cloudstream3/MainActivity.kt | 5 +- .../ui/settings/SettingsGeneral.kt | 35 +++++---- .../ui/settings/SettingsPlayer.kt | 78 +++++++++++-------- .../ui/settings/SettingsProviders.kt | 43 ++++++---- .../cloudstream3/ui/settings/SettingsUI.kt | 55 +++++++------ .../ui/settings/SettingsUpdates.kt | 45 ++++++----- .../ui/setup/SetupFragmentLanguage.kt | 6 +- .../ui/setup/SetupFragmentLayout.kt | 7 +- .../ui/setup/SetupFragmentMedia.kt | 7 +- .../ui/setup/SetupFragmentProviderLanguage.kt | 11 ++- .../ui/subtitles/SubtitlesFragment.kt | 8 +- .../cloudstream3/utils/PowerManagerAPI.kt | 8 +- 12 files changed, 180 insertions(+), 128 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index 42d9c1869..53ba51f52 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -32,6 +32,7 @@ import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity import androidx.cardview.widget.CardView import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.edit import androidx.core.view.children import androidx.core.view.get import androidx.core.view.isGone @@ -680,7 +681,9 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa .setNegativeButton(R.string.no) { _, _ -> /*NO-OP*/ } .setPositiveButton(R.string.yes) { _, _ -> if (dontShowAgainCheck.isChecked) { - settingsManager.edit().putInt(getString(R.string.confirm_exit_key), 1).commit() + settingsManager.edit(commit = true) { + putInt(getString(R.string.confirm_exit_key), 1) + } } // finish() causes a bug on some TVs where player // may keep playing after closing the app. diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt index e89865fc4..4c64b175b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt @@ -6,6 +6,7 @@ import android.os.Bundle import android.view.View import android.widget.Toast import androidx.appcompat.app.AlertDialog +import androidx.core.content.edit import androidx.core.os.ConfigurationCompat import androidx.preference.PreferenceManager import com.fasterxml.jackson.annotation.JsonProperty @@ -156,10 +157,10 @@ class SettingsGeneral : BasePreferenceFragmentCompat() { private val pathPicker = getChooseFolderLauncher { uri, path -> val context = context ?: CloudStreamApp.context ?: return@getChooseFolderLauncher (path ?: uri.toString()).let { - PreferenceManager.getDefaultSharedPreferences(context).edit() - .putString(getString(R.string.download_path_key), uri.toString()) - .putString(getString(R.string.download_path_key_visual), it) - .apply() + PreferenceManager.getDefaultSharedPreferences(context).edit { + putString(getString(R.string.download_path_key), uri.toString()) + putString(getString(R.string.download_path_key_visual), it) + } } } @@ -185,7 +186,9 @@ class SettingsGeneral : BasePreferenceFragmentCompat() { try { val langTagIETF = languageTagsIETF[selectedLangIndex] CommonActivity.setLocale(activity, langTagIETF) - settingsManager.edit().putString(getString(R.string.locale_key), langTagIETF).apply() + settingsManager.edit { + putString(getString(R.string.locale_key), langTagIETF) + } activity?.recreate() } catch (e: Exception) { logError(e) @@ -316,7 +319,7 @@ class SettingsGeneral : BasePreferenceFragmentCompat() { getString(R.string.dns_pref), true, {}) { - settingsManager.edit().putInt(getString(R.string.dns_pref), prefValues[it]).apply() + settingsManager.edit { putInt(getString(R.string.dns_pref), prefValues[it]) } (context ?: CloudStreamApp.context)?.let { ctx -> app.initClient(ctx) } } return@setOnPreferenceClickListener true @@ -341,7 +344,7 @@ class SettingsGeneral : BasePreferenceFragmentCompat() { } ?: emptyList() } - settingsManager.edit().putBoolean(getString(R.string.jsdelivr_proxy_key), getKey(getString(R.string.jsdelivr_proxy_key), false) ?: false).apply() + settingsManager.edit { putBoolean(getString(R.string.jsdelivr_proxy_key), getKey(getString(R.string.jsdelivr_proxy_key), false) ?: false) } getPref(R.string.jsdelivr_proxy_key)?.setOnPreferenceChangeListener { _, newValue -> setKey(getString(R.string.jsdelivr_proxy_key), newValue) return@setOnPreferenceChangeListener true @@ -371,10 +374,10 @@ class SettingsGeneral : BasePreferenceFragmentCompat() { // Sets both visual and actual paths. // key = used path // visual = visual path - settingsManager.edit() - .putString(getString(R.string.download_path_key), dirs[it]) - .putString(getString(R.string.download_path_key_visual), dirs[it]) - .apply() + settingsManager.edit { + putString(getString(R.string.download_path_key), dirs[it]) + putString(getString(R.string.download_path_key_visual), dirs[it]) + } } } return@setOnPreferenceClickListener true @@ -397,10 +400,12 @@ class SettingsGeneral : BasePreferenceFragmentCompat() { if (beneneCount%20 == 0) { activity?.navigate(R.id.action_navigation_settings_general_to_easterEggMonkeFragment) } - settingsManager.edit().putInt( - getString(R.string.benene_count), - beneneCount - ).apply() + settingsManager.edit { + putInt( + getString(R.string.benene_count), + beneneCount + ) + } it.summary = getString(R.string.benene_count_text).format(beneneCount) } catch (e: Exception) { logError(e) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsPlayer.kt index 4a1fad907..e301e8cc4 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsPlayer.kt @@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.ui.settings import android.os.Bundle import android.text.format.Formatter.formatShortFileSize import android.view.View +import androidx.core.content.edit import androidx.preference.PreferenceManager import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.actions.VideoClickActionHolder @@ -63,10 +64,11 @@ class SettingsPlayer : BasePreferenceFragmentCompat() { prefValues.indexOf(currentPrefSize), getString(R.string.video_buffer_length_settings), true, - {}) { - settingsManager.edit() - .putInt(getString(R.string.video_buffer_length_key), prefValues[it]) - .apply() + {} + ) { + settingsManager.edit { + putInt(getString(R.string.video_buffer_length_key), prefValues[it]) + } } return@setOnPreferenceClickListener true } @@ -81,10 +83,11 @@ class SettingsPlayer : BasePreferenceFragmentCompat() { prefValues.indexOf(current), getString(R.string.limit_title), true, - {}) { - settingsManager.edit() - .putInt(getString(R.string.prefer_limit_title_key), prefValues[it]) - .apply() + {} + ) { + settingsManager.edit { + putInt(getString(R.string.prefer_limit_title_key), prefValues[it]) + } } return@setOnPreferenceClickListener true } @@ -99,10 +102,11 @@ class SettingsPlayer : BasePreferenceFragmentCompat() { prefValues.indexOf(current), getString(R.string.software_decoding), true, - {}) { - settingsManager.edit() - .putInt(getString(R.string.software_decoding_key), prefValues[it]) - .apply() + {} + ) { + settingsManager.edit { + putInt(getString(R.string.software_decoding_key), prefValues[it]) + } } return@setOnPreferenceClickListener true } @@ -117,10 +121,11 @@ class SettingsPlayer : BasePreferenceFragmentCompat() { prefValues.indexOf(current), getString(R.string.limit_title_rez), true, - {}) { - settingsManager.edit() - .putInt(getString(R.string.prefer_limit_title_rez_key), prefValues[it]) - .apply() + {} + ) { + settingsManager.edit { + putInt(getString(R.string.prefer_limit_title_rez_key), prefValues[it]) + } } return@setOnPreferenceClickListener true } @@ -144,9 +149,11 @@ class SettingsPlayer : BasePreferenceFragmentCompat() { prefValues.indexOf(currentQuality), getString(R.string.watch_quality_pref), true, - {}) { - settingsManager.edit().putInt(getString(R.string.quality_pref_key), prefValues[it]) - .apply() + {} + ) { + settingsManager.edit { + putInt(getString(R.string.quality_pref_key), prefValues[it]) + } } return@setOnPreferenceClickListener true } @@ -168,9 +175,11 @@ class SettingsPlayer : BasePreferenceFragmentCompat() { prefValues.indexOf(currentQuality), getString(R.string.watch_quality_pref_data), true, - {}) { - settingsManager.edit().putInt(getString(R.string.quality_pref_mobile_data_key), prefValues[it]) - .apply() + {} + ) { + settingsManager.edit { + putInt(getString(R.string.quality_pref_mobile_data_key), prefValues[it]) + } } return@setOnPreferenceClickListener true } @@ -192,8 +201,11 @@ class SettingsPlayer : BasePreferenceFragmentCompat() { prefValues.indexOf(current), getString(R.string.player_pref), true, - {}) { - settingsManager.edit().putString(getString(R.string.player_default_key), prefValues[it]).apply() + {} + ) { + settingsManager.edit { + putString(getString(R.string.player_default_key), prefValues[it]) + } } return@setOnPreferenceClickListener true } @@ -220,10 +232,11 @@ class SettingsPlayer : BasePreferenceFragmentCompat() { prefValues.indexOf(currentPrefSize), getString(R.string.video_buffer_disk_settings), true, - {}) { - settingsManager.edit() - .putInt(getString(R.string.video_buffer_disk_key), prefValues[it]) - .apply() + {} + ) { + settingsManager.edit { + putInt(getString(R.string.video_buffer_disk_key), prefValues[it]) + } } return@setOnPreferenceClickListener true } @@ -239,10 +252,11 @@ class SettingsPlayer : BasePreferenceFragmentCompat() { prefValues.indexOf(currentPrefSize), getString(R.string.video_buffer_size_settings), true, - {}) { - settingsManager.edit() - .putInt(getString(R.string.video_buffer_size_key), prefValues[it]) - .apply() + {} + ) { + settingsManager.edit { + putInt(getString(R.string.video_buffer_size_key), prefValues[it]) + } } return@setOnPreferenceClickListener true } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsProviders.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsProviders.kt index 8bc3371ea..076f17a0a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsProviders.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsProviders.kt @@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.ui.settings import android.os.Bundle import android.view.View +import androidx.core.content.edit import androidx.navigation.fragment.findNavController import androidx.navigation.NavOptions import androidx.preference.PreferenceManager @@ -46,13 +47,15 @@ class SettingsProviders : BasePreferenceFragmentCompat() { names, currentList, getString(R.string.display_subbed_dubbed_settings), - {}) { selectedList -> + {} + ) { selectedList -> APIRepository.dubStatusActive = selectedList.map { dublist[it] }.toHashSet() - - settingsManager.edit().putStringSet( - this.getString(R.string.display_sub_key), - selectedList.map { names[it] }.toMutableSet() - ).apply() + settingsManager.edit { + putStringSet( + getString(R.string.display_sub_key), + selectedList.map { names[it] }.toMutableSet() + ) + } } } @@ -91,11 +94,14 @@ class SettingsProviders : BasePreferenceFragmentCompat() { names, currentList, getString(R.string.preferred_media_settings), - {}) { selectedList -> - settingsManager.edit().putStringSet( - this.getString(R.string.prefer_media_type_key), - selectedList.map { it.toString() }.toMutableSet() - ).apply() + {} + ) { selectedList -> + settingsManager.edit { + putStringSet( + getString(R.string.prefer_media_type_key), + selectedList.map { it.toString() }.toMutableSet() + ) + } DataStoreHelper.currentHomePage = null //(context ?: CloudStreamApp.context)?.let { ctx -> app.initClient(ctx) } } @@ -119,12 +125,15 @@ class SettingsProviders : BasePreferenceFragmentCompat() { languagesTagName.map { it.second }, currentIndexList, getString(R.string.provider_lang_settings), - {}) { selectedList -> - settingsManager.edit().putStringSet( - this.getString(R.string.provider_lang_key), - selectedList.map { languagesTagName[it].first }.toSet() - ).apply() - //APIRepository.providersActive = it.context.getApiSettings() + {} + ) { selectedList -> + settingsManager.edit { + putStringSet( + getString(R.string.provider_lang_key), + selectedList.map { languagesTagName[it].first }.toSet() + ) + } + // APIRepository.providersActive = it.context.getApiSettings() } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUI.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUI.kt index a991f9297..33add0e95 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUI.kt @@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.ui.settings import android.os.Build import android.os.Bundle import android.view.View +import androidx.core.content.edit import androidx.preference.PreferenceManager import androidx.preference.SeekBarPreference import com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity @@ -81,12 +82,13 @@ class SettingsUI : BasePreferenceFragmentCompat() { prefNames.toList(), prefValues, getString(R.string.poster_ui_settings), - {}) { list -> - val edit = settingsManager.edit() - for ((i, key) in keys.withIndex()) { - edit.putBoolean(key, list.contains(i)) + {} + ) { list -> + settingsManager.edit { + for ((i, key) in keys.withIndex()) { + putBoolean(key, list.contains(i)) + } } - edit.apply() SearchResultBuilder.updateCache(it.context) } @@ -108,9 +110,9 @@ class SettingsUI : BasePreferenceFragmentCompat() { dismissCallback = {}, callback = { try { - settingsManager.edit() - .putInt(getString(R.string.app_layout_key), prefValues[it]) - .apply() + settingsManager.edit { + putInt(getString(R.string.app_layout_key), prefValues[it]) + } context?.updateTv() activity?.recreate() } catch (e: Exception) { @@ -150,11 +152,12 @@ class SettingsUI : BasePreferenceFragmentCompat() { prefValues.indexOf(currentLayout), getString(R.string.app_theme_settings), true, - {}) { + {} + ) { try { - settingsManager.edit() - .putString(getString(R.string.app_theme_key), prefValues[it]) - .apply() + settingsManager.edit { + putString(getString(R.string.app_theme_key), prefValues[it]) + } activity?.recreate() } catch (e: Exception) { logError(e) @@ -187,11 +190,12 @@ class SettingsUI : BasePreferenceFragmentCompat() { prefValues.indexOf(currentLayout), getString(R.string.primary_color_settings), true, - {}) { + {} + ) { try { - settingsManager.edit() - .putString(getString(R.string.primary_color_key), prefValues[it]) - .apply() + settingsManager.edit { + putString(getString(R.string.primary_color_key), prefValues[it]) + } activity?.recreate() } catch (e: Exception) { logError(e) @@ -213,11 +217,14 @@ class SettingsUI : BasePreferenceFragmentCompat() { names, currentList, getString(R.string.pref_filter_search_quality), - {}) { selectedList -> - settingsManager.edit().putStringSet( - this.getString(R.string.pref_filter_search_quality_key), - selectedList.map { it.toString() }.toMutableSet() - ).apply() + {} + ) { selectedList -> + settingsManager.edit { + putStringSet( + getString(R.string.pref_filter_search_quality_key), + selectedList.map { it.toString() }.toMutableSet() + ) + } } return@setOnPreferenceClickListener true @@ -235,9 +242,9 @@ class SettingsUI : BasePreferenceFragmentCompat() { showApply = true, dismissCallback = {}, callback = { selectedOption -> - settingsManager.edit() - .putInt(getString(R.string.confirm_exit_key), prefValues[selectedOption]) - .apply() + settingsManager.edit { + putInt(getString(R.string.confirm_exit_key), prefValues[selectedOption]) + } } ) return@setOnPreferenceClickListener true diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt index 0d34cb988..6ff072038 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt @@ -5,6 +5,7 @@ import android.os.Bundle import android.view.View import android.widget.Toast import androidx.appcompat.app.AlertDialog +import androidx.core.content.edit import androidx.navigation.fragment.findNavController import androidx.preference.PreferenceManager import androidx.recyclerview.widget.LinearLayoutManager @@ -59,10 +60,10 @@ class SettingsUpdates : BasePreferenceFragmentCompat() { private val pathPicker = getChooseFolderLauncher { uri, path -> val context = context ?: CloudStreamApp.context ?: return@getChooseFolderLauncher (path ?: uri.toString()).let { - PreferenceManager.getDefaultSharedPreferences(context).edit() - .putString(getString(R.string.backup_path_key), uri.toString()) - .putString(getString(R.string.backup_dir_key), it) - .apply() + PreferenceManager.getDefaultSharedPreferences(context).edit { + putString(getString(R.string.backup_path_key), uri.toString()) + putString(getString(R.string.backup_dir_key), it) + } } } @@ -87,9 +88,11 @@ class SettingsUpdates : BasePreferenceFragmentCompat() { prefValues.indexOf(current), getString(R.string.backup_frequency), true, - {}) { index -> - settingsManager.edit() - .putInt(getString(R.string.automatic_backup_key), prefValues[index]).apply() + {} + ) { index -> + settingsManager.edit { + putInt(getString(R.string.automatic_backup_key), prefValues[index]) + } BackupWorkManager.enqueuePeriodicWork( context ?: CloudStreamApp.context, prefValues[index].toLong() @@ -118,7 +121,8 @@ class SettingsUpdates : BasePreferenceFragmentCompat() { dirs.indexOf(currentDir), getString(R.string.backup_path_title), true, - {}) { + {} + ) { // Last = custom if (it == dirs.size) { try { @@ -130,10 +134,10 @@ class SettingsUpdates : BasePreferenceFragmentCompat() { // Sets both visual and actual paths. // path = used uri // dir = dir path - settingsManager.edit() - .putString(getString(R.string.backup_path_key), dirs[it]) - .putString(getString(R.string.backup_dir_key), dirs[it]) - .apply() + settingsManager.edit { + putString(getString(R.string.backup_path_key), dirs[it]) + putString(getString(R.string.backup_dir_key), dirs[it]) + } } } return@setOnPreferenceClickListener true @@ -210,11 +214,12 @@ class SettingsUpdates : BasePreferenceFragmentCompat() { prefValues.indexOf(currentInstaller), getString(R.string.apk_installer_settings), true, - {}) { num -> + {} + ) { num -> try { - settingsManager.edit() - .putInt(getString(R.string.apk_installer_key), prefValues[num]) - .apply() + settingsManager.edit { + putInt(getString(R.string.apk_installer_key), prefValues[num]) + } } catch (e: Exception) { logError(e) } @@ -251,9 +256,11 @@ class SettingsUpdates : BasePreferenceFragmentCompat() { prefValues.indexOf(current), getString(R.string.automatic_plugin_download_mode_title), true, - {}) { num -> - settingsManager.edit() - .putInt(getString(R.string.auto_download_plugins_key), prefValues[num]).apply() + {} + ) { num -> + settingsManager.edit { + putInt(getString(R.string.auto_download_plugins_key), prefValues[num]) + } (context ?: CloudStreamApp.context)?.let { ctx -> app.initClient(ctx) } } return@setOnPreferenceClickListener true diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLanguage.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLanguage.kt index 5ff85c53b..e96a662c3 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLanguage.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLanguage.kt @@ -4,6 +4,7 @@ import android.view.View import android.widget.AbsListView import android.widget.ArrayAdapter import androidx.core.content.ContextCompat +import androidx.core.content.edit import androidx.navigation.fragment.findNavController import androidx.preference.PreferenceManager import com.lagradost.cloudstream3.BuildConfig @@ -62,8 +63,9 @@ class SetupFragmentLanguage : BaseFragment( listview1.setOnItemClickListener { _, _, selectedLangIndex, _ -> val langTagIETF = languageTagsIETF[selectedLangIndex] CommonActivity.setLocale(activity, langTagIETF) - settingsManager.edit().putString(getString(R.string.locale_key), langTagIETF) - .apply() + settingsManager.edit { + putString(getString(R.string.locale_key), langTagIETF) + } } nextBtt.setOnClickListener { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLayout.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLayout.kt index 11cc12066..4a8e784a1 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLayout.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentLayout.kt @@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.ui.setup import android.view.View import android.widget.AbsListView import android.widget.ArrayAdapter +import androidx.core.content.edit import androidx.navigation.fragment.findNavController import androidx.preference.PreferenceManager import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey @@ -44,9 +45,9 @@ class SetupFragmentLayout : BaseFragment( ) listview1.setOnItemClickListener { _, _, position, _ -> - settingsManager.edit() - .putInt(getString(R.string.app_layout_key), prefValues[position]) - .apply() + settingsManager.edit { + putInt(getString(R.string.app_layout_key), prefValues[position]) + } activity?.recreate() } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentMedia.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentMedia.kt index ca5e63cce..8da121daa 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentMedia.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentMedia.kt @@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.ui.setup import android.view.View import android.widget.AbsListView import android.widget.ArrayAdapter +import androidx.core.content.edit import androidx.core.util.forEach import androidx.navigation.fragment.findNavController import androidx.preference.PreferenceManager @@ -53,9 +54,9 @@ class SetupFragmentMedia : BaseFragment( val itemVal = TvType.valueOf(item) itemVal.ordinal.toString() }.toSet() - settingsManager.edit() - .putStringSet(getString(R.string.prefer_media_type_key), prefValues) - .apply() + settingsManager.edit { + putStringSet(getString(R.string.prefer_media_type_key), prefValues) + } // Regenerate set homepage DataStoreHelper.currentHomePage = null diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentProviderLanguage.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentProviderLanguage.kt index 6032af56d..3c4a09ade 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentProviderLanguage.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/setup/SetupFragmentProviderLanguage.kt @@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.ui.setup import android.view.View import android.widget.AbsListView import android.widget.ArrayAdapter +import androidx.core.content.edit import androidx.core.util.forEach import androidx.navigation.fragment.findNavController import androidx.preference.PreferenceManager @@ -58,10 +59,12 @@ class SetupFragmentProviderLanguage : BaseFragment if (value) selectedLanguages.add(languagesTagName[key].first) } - settingsManager.edit().putStringSet( - ctx.getString(R.string.provider_lang_key), - selectedLanguages.toSet() - ).apply() + settingsManager.edit { + putStringSet( + ctx.getString(R.string.provider_lang_key), + selectedLanguages.toSet() + ) + } } nextBtt.setOnClickListener { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt index 9b0d31212..09fd23abd 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt @@ -18,6 +18,7 @@ import android.widget.Toast import androidx.annotation.FontRes import androidx.annotation.OptIn import androidx.annotation.Px +import androidx.core.content.edit import androidx.core.content.res.ResourcesCompat import androidx.media3.common.text.Cue import androidx.media3.common.util.UnstableApi @@ -636,10 +637,9 @@ class SubtitlesFragment : BaseDialogFragment( subtitlesFilterSubLang.setOnCheckedChangeListener { _, b -> context?.let { ctx -> - PreferenceManager.getDefaultSharedPreferences(ctx) - .edit() - .putBoolean(getString(R.string.filter_sub_lang_key), b) - .apply() + PreferenceManager.getDefaultSharedPreferences(ctx).edit { + putBoolean(getString(R.string.filter_sub_lang_key), b) + } } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/PowerManagerAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/PowerManagerAPI.kt index 0d7a8abc4..63f7e1559 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/PowerManagerAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/PowerManagerAPI.kt @@ -9,6 +9,7 @@ import android.os.PowerManager import android.provider.Settings import android.util.Log import androidx.appcompat.app.AlertDialog +import androidx.core.content.edit import androidx.preference.PreferenceManager import com.lagradost.cloudstream3.BuildConfig import com.lagradost.cloudstream3.CommonActivity.showToast @@ -38,7 +39,6 @@ object BatteryOptimizationChecker { fun Context.showBatteryOptimizationDialog() { val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) - try { AlertDialog.Builder(this) .setTitle(R.string.battery_dialog_title) @@ -46,9 +46,9 @@ object BatteryOptimizationChecker { .setMessage(R.string.battery_dialog_message) .setPositiveButton(R.string.ok) { _, _ -> showRequestIgnoreBatteryOptDialog() } .setNegativeButton(R.string.cancel) { _, _ -> - settingsManager.edit() - .putBoolean(getString(R.string.battery_optimisation_key), false) - .apply() + settingsManager.edit { + putBoolean(getString(R.string.battery_optimisation_key), false) + } } .show() } catch (t: Throwable) { From e25847cb647951ab9e7682d7f717f4fb0bcde681 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sun, 7 Dec 2025 15:24:42 -0700 Subject: [PATCH 182/513] Add API for minimum media duration --- .../cloudstream3/ui/player/CS3IPlayer.kt | 24 ++++++++++++------- .../com/lagradost/cloudstream3/MainAPI.kt | 6 +++++ 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt index b7712cd79..41dc052a7 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CS3IPlayer.kt @@ -1572,16 +1572,22 @@ class CS3IPlayer : IPlayer { } Log.i(TAG, "Rendered first frame") hasUsedFirstRender = true - val invalid = exoPlayer?.duration?.let { duration -> - // Only errors short playback when not playing downloaded files - duration < 20_000L && currentDownloadedFile == null - // Concatenated sources (non 1 periodCount) bypasses the invalid check as exoPlayer.duration gives only the current period - // If you can get the total time that'd be better, but this is already niche. - && exoPlayer?.currentTimeline?.periodCount == 1 - && exoPlayer?.isCurrentMediaItemLive != true - } ?: false - if (invalid) { + // Only errors short playback when not playing downloaded files + val tooShort = if (currentDownloadedFile == null) { + val provider = getApiFromNameNull(currentLink?.source) + val minimumDurationMs = provider?.minimumDurationMs + exoPlayer?.duration?.let { duration -> + minimumDurationMs != null && + duration < minimumDurationMs && + // Concatenated sources (non 1 periodCount) bypasses the invalid check as exoPlayer.duration gives only the current period + // If you can get the total time that'd be better, but this is already niche. + exoPlayer?.currentTimeline?.periodCount == 1 && + exoPlayer?.isCurrentMediaItemLive != true + } ?: false + } else false + + if (tooShort) { releasePlayer(saveTime = false) event(ErrorEvent(InvalidFileException("Too short playback"))) return diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt index cce42da19..84b010759 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt @@ -557,6 +557,12 @@ abstract class MainAPI { * */ open val loadTimeoutMs: Long? = null + /** + * The minimum media duration in milliseconds. If the duration is smaller + * than this value, it will result in to short playback errors. + */ + @Prerelease + open val minimumDurationMs: Long? = null /** * A set of which ids the provider can open with getLoadUrl() From a46b0ac6e678f5fc5b82d0b1081fa6d8610c3d32 Mon Sep 17 00:00:00 2001 From: Osten <11805592+LagradOst@users.noreply.github.com> Date: Mon, 8 Dec 2025 22:35:11 +0100 Subject: [PATCH 183/513] Download selection fix + sub del fix + Del dialog fix (#2308) --- .../ui/download/DownloadChildFragment.kt | 107 +++++++----------- .../ui/download/DownloadFragment.kt | 99 ++++++---------- .../ui/download/DownloadViewModel.kt | 33 +++--- .../cloudstream3/utils/SubtitleUtils.kt | 25 ++-- .../utils/VideoDownloadManager.kt | 2 +- 5 files changed, 108 insertions(+), 158 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildFragment.kt index 08194fd31..d44ea0020 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadChildFragment.kt @@ -1,16 +1,16 @@ package com.lagradost.cloudstream3.ui.download import android.os.Bundle -import android.os.Handler -import android.os.Looper import android.text.format.Formatter.formatShortFileSize import android.view.View +import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.fragment.app.activityViewModels import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.databinding.FragmentChildDownloadsBinding import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.observe +import com.lagradost.cloudstream3.mvvm.observeNullable import com.lagradost.cloudstream3.ui.BaseFragment import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick import com.lagradost.cloudstream3.ui.result.FOCUS_SELF @@ -55,22 +55,6 @@ class DownloadChildFragment : BaseFragment( } override fun onBindingCreated(binding: FragmentChildDownloadsBinding) { - /** - * We never want to retain multi-delete state - * when navigating to downloads. Setting this state - * immediately can sometimes result in the observer - * not being notified in time to update the UI. - * - * By posting to the main looper, we ensure that this - * operation is executed after the view has been fully created - * and all initializations are completed, allowing the - * observer to properly receive and handle the state change. - */ - Handler(Looper.getMainLooper()).post { - downloadViewModel.setIsMultiDeleteState(false) - } - - val folder = arguments?.getString("folder") val name = arguments?.getString("name") if (folder == null) { @@ -101,30 +85,56 @@ class DownloadChildFragment : BaseFragment( } (binding.downloadChildList.adapter as? DownloadAdapter)?.submitList(cards.value) } + else -> { (binding.downloadChildList.adapter as? DownloadAdapter)?.submitList(null) } } } - observe(downloadViewModel.isMultiDeleteState) { isMultiDeleteState -> - val adapter = binding.downloadChildList.adapter as? DownloadAdapter - adapter?.setIsMultiDeleteState(isMultiDeleteState) - binding.downloadDeleteAppbar.isVisible = isMultiDeleteState - if (!isMultiDeleteState) { - activity?.detachBackPressedCallback("Downloads") - downloadViewModel.clearSelectedItems() - binding.downloadChildToolbar.isVisible = true - } - } + observe(downloadViewModel.selectedBytes) { updateDeleteButton(downloadViewModel.selectedItemIds.value?.count() ?: 0, it) } - observe(downloadViewModel.selectedItemIds) { - handleSelectedChange(it) - updateDeleteButton(it.count(), downloadViewModel.selectedBytes.value ?: 0L) - binding.btnDelete.isVisible = it.isNotEmpty() - binding.selectItemsText.isVisible = it.isEmpty() + + binding.apply { + btnDelete.setOnClickListener { view -> + downloadViewModel.handleMultiDelete(view.context ?: return@setOnClickListener) + } + + btnCancel.setOnClickListener { + downloadViewModel.cancelSelection() + } + + btnToggleAll.setOnClickListener { + val allSelected = downloadViewModel.isAllChildrenSelected() + if (allSelected) { + downloadViewModel.clearSelectedItems() + } else { + downloadViewModel.selectAllChildren() + } + } + } + + observeNullable(downloadViewModel.selectedItemIds) { selection -> + val isMultiDeleteState = selection != null + val adapter = binding.downloadChildList.adapter as? DownloadAdapter + adapter?.setIsMultiDeleteState(isMultiDeleteState) + binding.downloadDeleteAppbar.isVisible = isMultiDeleteState + binding.downloadChildToolbar.isGone = isMultiDeleteState + + if (selection == null) { + activity?.detachBackPressedCallback("Downloads") + return@observeNullable + } + activity?.attachBackPressedCallback("Downloads") { + downloadViewModel.cancelSelection() + } + + updateDeleteButton(selection.count(), downloadViewModel.selectedBytes.value ?: 0L) + + binding.btnDelete.isVisible = selection.isNotEmpty() + binding.selectItemsText.isVisible = selection.isEmpty() val allSelected = downloadViewModel.isAllChildrenSelected() if (allSelected) { @@ -160,37 +170,6 @@ class DownloadChildFragment : BaseFragment( } } - private fun handleSelectedChange(selected: Set) { - if (selected.isNotEmpty()) { - binding?.downloadDeleteAppbar?.isVisible = true - binding?.downloadChildToolbar?.isVisible = false - activity?.attachBackPressedCallback("Downloads") { - downloadViewModel.setIsMultiDeleteState(false) - } - - binding?.btnDelete?.setOnClickListener { - context?.let { ctx -> - downloadViewModel.handleMultiDelete(ctx) - } - } - - binding?.btnCancel?.setOnClickListener { - downloadViewModel.setIsMultiDeleteState(false) - } - - binding?.btnToggleAll?.setOnClickListener { - val allSelected = downloadViewModel.isAllChildrenSelected() - if (allSelected) { - downloadViewModel.clearSelectedItems() - } else { - downloadViewModel.selectAllChildren() - } - } - - downloadViewModel.setIsMultiDeleteState(true) - } - } - private fun updateDeleteButton(count: Int, selectedBytes: Long) { val formattedSize = formatShortFileSize(context, selectedBytes) binding?.btnDelete?.text = diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt index e3d77abac..3bd424640 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadFragment.kt @@ -7,8 +7,6 @@ import android.content.Context import android.content.Intent import android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION import android.os.Build -import android.os.Handler -import android.os.Looper import android.text.format.Formatter.formatShortFileSize import android.view.View import android.widget.LinearLayout @@ -28,6 +26,7 @@ import com.lagradost.cloudstream3.isEpisodeBased import com.lagradost.cloudstream3.mvvm.Resource import com.lagradost.cloudstream3.mvvm.safe import com.lagradost.cloudstream3.mvvm.observe +import com.lagradost.cloudstream3.mvvm.observeNullable import com.lagradost.cloudstream3.ui.BaseFragment import com.lagradost.cloudstream3.ui.download.DownloadButtonSetup.handleDownloadClick import com.lagradost.cloudstream3.ui.player.BasicLink @@ -87,21 +86,6 @@ class DownloadFragment : BaseFragment( binding.downloadAppbar.setAppBarNoScrollFlagsOnTV() binding.downloadDeleteAppbar.setAppBarNoScrollFlagsOnTV() - /** - * We never want to retain multi-delete state - * when navigating to downloads. Setting this state - * immediately can sometimes result in the observer - * not being notified in time to update the UI. - * - * By posting to the main looper, we ensure that this - * operation is executed after the view has been fully created - * and all initializations are completed, allowing the - * observer to properly receive and handle the state change. - */ - Handler(Looper.getMainLooper()).post { - downloadViewModel.setIsMultiDeleteState(false) - } - observe(downloadViewModel.headerCards) { cards -> when (cards) { is Resource.Success -> { @@ -161,26 +145,44 @@ class DownloadFragment : BaseFragment( observe(downloadViewModel.selectedBytes) { updateDeleteButton(downloadViewModel.selectedItemIds.value?.count() ?: 0, it) } - observe(downloadViewModel.isMultiDeleteState) { isMultiDeleteState -> - val adapter = binding.downloadList.adapter as? DownloadAdapter - adapter?.setIsMultiDeleteState(isMultiDeleteState) - binding.downloadDeleteAppbar.isVisible = isMultiDeleteState - if (!isMultiDeleteState) { - activity?.detachBackPressedCallback("Downloads") - downloadViewModel.clearSelectedItems() - // Prevent race condition and make sure - // we don't display it early - if (downloadViewModel.usedBytes.value?.let { it > 0 } == true) { - binding.downloadAppbar.isVisible = true + + binding.apply { + btnDelete.setOnClickListener { view -> + downloadViewModel.handleMultiDelete(view.context ?: return@setOnClickListener) + } + + btnCancel.setOnClickListener { + downloadViewModel.cancelSelection() + } + + btnToggleAll.setOnClickListener { + val allSelected = downloadViewModel.isAllHeadersSelected() + if (allSelected) { + downloadViewModel.clearSelectedItems() + } else { + downloadViewModel.selectAllHeaders() } } } - observe(downloadViewModel.selectedItemIds) { - handleSelectedChange(it) - updateDeleteButton(it.count(), downloadViewModel.selectedBytes.value ?: 0L) - binding.btnDelete.isVisible = it.isNotEmpty() - binding.selectItemsText.isVisible = it.isEmpty() + observeNullable(downloadViewModel.selectedItemIds) { selection -> + val isMultiDeleteState = selection != null + val adapter = binding.downloadList.adapter as? DownloadAdapter + adapter?.setIsMultiDeleteState(isMultiDeleteState) + binding.downloadDeleteAppbar.isVisible = isMultiDeleteState + binding.downloadAppbar.isGone = isMultiDeleteState + + if (selection == null) { + activity?.detachBackPressedCallback("Downloads") + return@observeNullable + } + activity?.attachBackPressedCallback("Downloads") { + downloadViewModel.cancelSelection() + } + updateDeleteButton(selection.count(), downloadViewModel.selectedBytes.value ?: 0L) + + binding.btnDelete.isVisible = selection.isNotEmpty() + binding.selectItemsText.isVisible = selection.isEmpty() val allSelected = downloadViewModel.isAllHeadersSelected() if (allSelected) { @@ -260,37 +262,6 @@ class DownloadFragment : BaseFragment( } } - private fun handleSelectedChange(selected: Set) { - if (selected.isNotEmpty()) { - binding?.downloadDeleteAppbar?.isVisible = true - binding?.downloadAppbar?.isVisible = false - activity?.attachBackPressedCallback("Downloads") { - downloadViewModel.setIsMultiDeleteState(false) - } - - binding?.btnDelete?.setOnClickListener { - context?.let { ctx -> - downloadViewModel.handleMultiDelete(ctx) - } - } - - binding?.btnCancel?.setOnClickListener { - downloadViewModel.setIsMultiDeleteState(false) - } - - binding?.btnToggleAll?.setOnClickListener { - val allSelected = downloadViewModel.isAllHeadersSelected() - if (allSelected) { - downloadViewModel.clearSelectedItems() - } else { - downloadViewModel.selectAllHeaders() - } - } - - downloadViewModel.setIsMultiDeleteState(true) - } - } - private fun updateDeleteButton(count: Int, selectedBytes: Long) { val formattedSize = formatShortFileSize(context, selectedBytes) binding?.btnDelete?.text = diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadViewModel.kt index bf81e6069..ee69390ff 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/download/DownloadViewModel.kt @@ -29,7 +29,8 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext class DownloadViewModel : ViewModel() { - private val _headerCards = ResourceLiveData>(Resource.Loading()) + private val _headerCards = + ResourceLiveData>(Resource.Loading()) val headerCards: LiveData>> = _headerCards private val _childCards = ResourceLiveData>(Resource.Loading()) @@ -47,22 +48,20 @@ class DownloadViewModel : ViewModel() { private val _selectedBytes = ConsistentLiveData(0) val selectedBytes: LiveData = _selectedBytes - private val _isMultiDeleteState = ConsistentLiveData(false) - val isMultiDeleteState: LiveData = _isMultiDeleteState + private val _selectedItemIds = ConsistentLiveData?>(null) + val selectedItemIds: LiveData?> = _selectedItemIds - private val _selectedItemIds = ConsistentLiveData>(mutableSetOf()) - val selectedItemIds: LiveData> = _selectedItemIds - fun setIsMultiDeleteState(value: Boolean) { - _isMultiDeleteState.postValue(value) + fun cancelSelection() { + updateSelectedItems { null } } fun addSelected(itemId: Int) { - updateSelectedItems { it + itemId } + updateSelectedItems { it?.plus(itemId) ?: setOf(itemId) } } fun removeSelected(itemId: Int) { - updateSelectedItems { it - itemId } + updateSelectedItems { it?.minus(itemId) ?: emptySet() } } fun selectAllHeaders() { @@ -97,8 +96,8 @@ class DownloadViewModel : ViewModel() { return currentSelected.size == headers.size && headers.all { it.data.id in currentSelected } } - private fun updateSelectedItems(action: (Set) -> Set) { - val currentSelected = action(selectedItemIds.value ?: mutableSetOf()) + private fun updateSelectedItems(action: (Set?) -> Set?) { + val currentSelected = action(selectedItemIds.value) _selectedItemIds.postValue(currentSelected) postHeaders() postChildren() @@ -115,7 +114,6 @@ class DownloadViewModel : ViewModel() { fun updateHeaderList(context: Context) = viewModelScope.launchSafe { // Do not push loading as it interrupts the UI //_headerCards.postValue(Resource.Loading()) - clearSelectedItems() val visual = withContext(Dispatchers.IO) { val children = context.getKeys(DOWNLOAD_EPISODE_CACHE) @@ -232,7 +230,6 @@ class DownloadViewModel : ViewModel() { fun updateChildList(context: Context, folder: String) = viewModelScope.launchSafe { _childCards.postValue(Resource.Loading()) // always push loading - clearSelectedItems() val visual = withContext(Dispatchers.IO) { context.getKeys(folder).mapNotNull { key -> @@ -260,6 +257,7 @@ class DownloadViewModel : ViewModel() { } private fun removeItems(idsToRemove: Set) = viewModelScope.launchSafe { + _selectedItemIds.postValue(null) postHeaders(_headerCards.success?.filter { it.data.id !in idsToRemove }) postChildren(_childCards.success?.filter { it.data.id !in idsToRemove }) } @@ -368,16 +366,16 @@ class DownloadViewModel : ViewModel() { .joinToString(separator = "\n") { "• $it" } return when { + data.seriesNames.isNotEmpty() && data.names.isEmpty() -> { + context.getString(R.string.delete_message_series_only).format(formattedSeriesNames) + } + data.ids.count() == 1 -> { context.getString(R.string.delete_message).format( data.names.firstOrNull() ) } - data.seriesNames.isNotEmpty() && data.names.isEmpty() -> { - context.getString(R.string.delete_message_series_only).format(formattedSeriesNames) - } - data.parentName != null && data.names.isNotEmpty() -> { context.getString(R.string.delete_message_series_episodes) .format(data.parentName, formattedNames) @@ -406,7 +404,6 @@ class DownloadViewModel : ViewModel() { when (which) { DialogInterface.BUTTON_POSITIVE -> { viewModelScope.launchSafe { - setIsMultiDeleteState(false) deleteFilesAndUpdateSettings(context, ids, this) { successfulIds -> // We always remove parent because if we are deleting from here // and we have it as non-empty, it was triggered on diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/SubtitleUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/SubtitleUtils.kt index 66a6e156c..97be98aea 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/SubtitleUtils.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/SubtitleUtils.kt @@ -2,8 +2,7 @@ package com.lagradost.cloudstream3.utils import android.content.Context import com.lagradost.api.Log -import com.lagradost.cloudstream3.utils.VideoDownloadManager.getFolder -import com.lagradost.safefile.SafeFile +import com.lagradost.cloudstream3.utils.VideoDownloadManager.basePathToFile object SubtitleUtils { @@ -14,16 +13,20 @@ object SubtitleUtils { ) fun deleteMatchingSubtitles(context: Context, info: VideoDownloadManager.DownloadedFileInfo) { - val relative = info.relativePath - val display = info.displayName - val cleanDisplay = cleanDisplayName(display) + val cleanDisplay = cleanDisplayName(info.displayName) - getFolder(context, relative, info.basePath)?.forEach { (name, uri) -> - if (isMatchingSubtitle(name, display, cleanDisplay)) { - val subtitleFile = SafeFile.fromUri(context, uri) - if (subtitleFile == null || subtitleFile.delete() != true) { - Log.e("SubtitleDeletion", "Failed to delete subtitle file: ${subtitleFile?.name()}") - } + val base = basePathToFile(context, info.basePath) + val folder = + base?.gotoDirectory(info.relativePath, createMissingDirectories = false) ?: return + val folderFiles = folder.listFiles() ?: return + + for (file in folderFiles) { + val name = file.name() ?: continue + if (!isMatchingSubtitle(name, info.displayName, cleanDisplay)) { + continue + } + if (file.delete() != true) { + Log.e("SubtitleDeletion", "Failed to delete subtitle file: $name") } } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadManager.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadManager.kt index 9748bd296..cdda11868 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/VideoDownloadManager.kt @@ -1628,7 +1628,7 @@ object VideoDownloadManager { * Turns a string to an UniFile. Used for stored string paths such as settings. * Should only be used to get a download path. * */ - private fun basePathToFile(context: Context, path: String?): SafeFile? { + fun basePathToFile(context: Context, path: String?): SafeFile? { return when { path.isNullOrBlank() -> getDefaultDir(context) path.startsWith("content://") -> SafeFile.fromUri(context, path.toUri()) From 8fabb5c572fd1542145ef7b7af507075d04c09c9 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 11 Dec 2025 09:17:25 -0700 Subject: [PATCH 184/513] Suppress an UnspecifiedRegisterReceiverFlag lint issue (#2316) Part of my work to fix all error level lint issues, in order to eventually enable `failOnError` and ensure better compatability with older API levels and a more consistent reporting of issues. --- .../cloudstream3/ui/player/AbstractPlayerFragment.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt index 413bc5d89..929550dc2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt @@ -221,11 +221,16 @@ abstract class AbstractPlayerFragment( ) } } + val filter = IntentFilter() filter.addAction(ACTION_MEDIA_CONTROL) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { activity?.registerReceiver(pipReceiver, filter, Context.RECEIVER_EXPORTED) - } else activity?.registerReceiver(pipReceiver, filter) + } else { + @SuppressLint("UnspecifiedRegisterReceiverFlag") + activity?.registerReceiver(pipReceiver, filter) + } + val isPlaying = player.getIsPlaying() val isPlayingValue = if (isPlaying) CSPlayerLoading.IsPlaying else CSPlayerLoading.IsPaused From d5eba57bc0a6e026db25de45ade3a29710a6fbf6 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 11 Dec 2025 09:20:22 -0700 Subject: [PATCH 185/513] Cleanup UnstableApi usage (#2314) * Remove `@UnstableApi` from GeneratorPlayer and use OptIn instead. * Remove `@OptIn` from WebviewFragment as it was unnecessary. * Move `@OptIn` in SaveCaptionStyle to the actual single line we need to OptIn. * Split `setCues` logic to a new method in ChromcastSubtitlesFragment and only add `@OptIn` to that method as it's only necessary there. * Add some missing `@OptIn` annotations to fix all remaining `UnsafeOptInUsageError` lint errors. --- .../com/lagradost/cloudstream3/ui/WebviewFragment.kt | 5 +---- .../cloudstream3/ui/player/AbstractPlayerFragment.kt | 3 +++ .../ui/player/CustomSubtitleDecoderFactory.kt | 8 ++++---- .../cloudstream3/ui/player/FullScreenPlayer.kt | 4 +--- .../cloudstream3/ui/player/GeneratorPlayer.kt | 7 +------ .../ui/subtitles/ChromecastSubtitlesFragment.kt | 10 +++++++++- .../cloudstream3/ui/subtitles/SubtitlesFragment.kt | 5 +++-- 7 files changed, 22 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/WebviewFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/WebviewFragment.kt index efc9b51c9..0d951bf6a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/WebviewFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/WebviewFragment.kt @@ -6,9 +6,7 @@ import android.webkit.JavascriptInterface import android.webkit.WebResourceRequest import android.webkit.WebView import android.webkit.WebViewClient -import androidx.annotation.OptIn import androidx.fragment.app.FragmentActivity -import androidx.media3.common.util.UnstableApi import androidx.navigation.fragment.findNavController import com.lagradost.cloudstream3.MainActivity import com.lagradost.cloudstream3.USER_AGENT @@ -28,7 +26,6 @@ class WebviewFragment : BaseFragment( } binding.webView.webViewClient = object : WebViewClient() { - @OptIn(UnstableApi::class) override fun shouldOverrideUrlLoading( view: WebView?, request: WebResourceRequest? @@ -43,6 +40,7 @@ class WebviewFragment : BaseFragment( return super.shouldOverrideUrlLoading(view, request) } } + binding.webView.apply { WebViewResolver.webViewUserAgent = settings.userAgentString @@ -53,7 +51,6 @@ class WebviewFragment : BaseFragment( loadUrl(url) } - } companion object { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt index 929550dc2..de04e386f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/AbstractPlayerFragment.kt @@ -20,11 +20,13 @@ import android.widget.ImageView import android.widget.ProgressBar import android.widget.Toast import androidx.annotation.LayoutRes +import androidx.annotation.OptIn import androidx.annotation.StringRes import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.media3.common.PlaybackException +import androidx.media3.common.util.UnstableApi import androidx.media3.exoplayer.ExoPlayer import androidx.media3.session.MediaSession import androidx.media3.ui.AspectRatioFrameLayout @@ -74,6 +76,7 @@ const val NEXT_WATCH_EPISODE_PERCENTAGE = 90 // when the player should sync the progress of "watched", TODO MAKE SETTING const val UPDATE_SYNC_PROGRESS_PERCENTAGE = 80 +@OptIn(UnstableApi::class) abstract class AbstractPlayerFragment( var player: IPlayer = CS3IPlayer() ) : Fragment() { diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomSubtitleDecoderFactory.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomSubtitleDecoderFactory.kt index 40aff83e1..ffcd83664 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomSubtitleDecoderFactory.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/CustomSubtitleDecoderFactory.kt @@ -35,8 +35,8 @@ import java.nio.charset.Charset /** * @param fallbackFormat used to create a decoder based on mimetype if the subtitle string is not * enough to identify the subtitle format. - **/ -@UnstableApi + */ +@OptIn(UnstableApi::class) class CustomDecoder(private val fallbackFormat: Format?) : SubtitleParser { companion object { fun updateForcedEncoding(context: Context) { @@ -392,7 +392,7 @@ class CustomSubtitleDecoderFactory : SubtitleDecoderFactory { /** * Decoders created here persists across reset() * Do not save state in the decoder which you want to reset (e.g subtitle offset) - **/ + */ override fun createDecoder(format: Format): SubtitleDecoder { val parser = CustomDecoder(format) // Allow garbage collection if player releases the decoder @@ -404,8 +404,8 @@ class CustomSubtitleDecoderFactory : SubtitleDecoderFactory { } } -@OptIn(UnstableApi::class) /** We need to convert the newer SubtitleParser to an older SubtitleDecoder */ +@OptIn(UnstableApi::class) class DelegatingSubtitleDecoder(name: String, private val parser: SubtitleParser) : SimpleSubtitleDecoder(name) { 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 9cc829e95..3821d880a 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 @@ -103,6 +103,7 @@ const val DOUBLE_TAB_PAUSE_PERCENTAGE = 0.15 // in both directions private const val SUBTITLE_DELAY_BUNDLE_KEY = "subtitle_delay" // All the UI Logic for the player +@OptIn(UnstableApi::class) open class FullScreenPlayer : AbstractPlayerFragment() { private var isVerticalOrientation: Boolean = false protected open var lockRotation = true @@ -274,7 +275,6 @@ open class FullScreenPlayer : AbstractPlayerFragment() { private fun animateLayoutChangesForSubtitles() = // Post here as bottomPlayerBar is gone the first frame => bottomPlayerBar.height = 0 playerBinding?.bottomPlayerBar?.post { - @OptIn(UnstableApi::class) val sView = subView ?: return@post val sStyle = CustomDecoder.style val binding = playerBinding ?: return@post @@ -378,7 +378,6 @@ open class FullScreenPlayer : AbstractPlayerFragment() { } } - @OptIn(UnstableApi::class) override fun subtitlesChanged() { val tracks = player.getVideoTracks() val isBuiltinSubtitles = tracks.currentTextTracks.all { track -> @@ -1526,7 +1525,6 @@ open class FullScreenPlayer : AbstractPlayerFragment() { private var loudnessEnhancer: LoudnessEnhancer? = null - @OptIn(UnstableApi::class) private fun handleVolumeAdjustment( delta: Float, fromButton: Boolean, 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 48353736b..6e362ed80 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 @@ -132,7 +132,7 @@ import kotlinx.coroutines.isActive import kotlinx.coroutines.Job import kotlinx.coroutines.launch -@UnstableApi +@OptIn(UnstableApi::class) class GeneratorPlayer : FullScreenPlayer() { companion object { const val NOTIFICATION_ID = 2326 @@ -266,12 +266,8 @@ class GeneratorPlayer : FullScreenPlayer() { return PendingIntent.getBroadcast(context, instanceId, intent, pendingFlags) } - @OptIn(UnstableApi::class) - @UnstableApi private var cachedPlayerNotificationManager: PlayerNotificationManager? = null - @OptIn(UnstableApi::class) - @UnstableApi private fun getMediaNotification(context: Context): PlayerNotificationManager { val cache = cachedPlayerNotificationManager if (cache != null) return cache @@ -876,7 +872,6 @@ class GeneratorPlayer : FullScreenPlayer() { //dialog.subtitles_search_year?.setText(currentTempMeta.year) } - @OptIn(UnstableApi::class) private fun openSubPicker() { try { subsPathPicker.launch( diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt index 4f41b436d..f9b1cb1fe 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt @@ -10,7 +10,9 @@ import android.util.TypedValue import android.view.View import android.widget.TextView import android.widget.Toast +import androidx.annotation.OptIn import androidx.media3.common.text.Cue +import androidx.media3.common.util.UnstableApi import com.fasterxml.jackson.annotation.JsonProperty import com.google.android.gms.cast.TextTrackStyle.EDGE_TYPE_DEPRESSED import com.google.android.gms.cast.TextTrackStyle.EDGE_TYPE_DROP_SHADOW @@ -49,7 +51,7 @@ data class SaveChromeCaptionStyle( @JsonProperty("fontScale") var fontScale: Float = 1.05f, @JsonProperty("windowColor") var windowColor: Int = Color.TRANSPARENT, ) -@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class) + class ChromecastSubtitlesFragment : BaseFragment( BaseFragment.BindingCreator.Inflate(ChromecastSubtitleSettingsBinding::inflate) ) { @@ -330,6 +332,12 @@ class ChromecastSubtitlesFragment : BaseFragment( BaseFragment.BindingCreator.Inflate(SubtitleSettingsBinding::inflate) ) { From ae5e25726df720898811ae3047ba339bcd77c3b9 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 11 Dec 2025 09:31:36 -0700 Subject: [PATCH 186/513] Use String.toUri consistently (#2304) --- .../java/com/lagradost/cloudstream3/MainActivity.kt | 6 +++--- .../cloudstream3/actions/temp/MpvKtPackage.kt | 3 +-- .../lagradost/cloudstream3/actions/temp/MpvPackage.kt | 3 +-- .../cloudstream3/actions/temp/PlayInBrowserAction.kt | 4 ++-- .../cloudstream3/actions/temp/WebVideoCastPackage.kt | 3 +-- .../lagradost/cloudstream3/utils/AppContextUtils.kt | 10 +++++----- .../com/lagradost/cloudstream3/utils/CastHelper.kt | 4 ++-- .../lagradost/cloudstream3/utils/PowerManagerAPI.kt | 4 ++-- .../com/lagradost/cloudstream3/utils/TvChannelUtils.kt | 10 +++++----- 9 files changed, 22 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index 53ba51f52..c12b10f36 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -9,7 +9,6 @@ import android.content.SharedPreferences import android.content.res.ColorStateList import android.content.res.Configuration import android.graphics.Rect -import android.net.Uri import android.os.Bundle import android.util.AttributeSet import android.util.Log @@ -33,6 +32,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.cardview.widget.CardView import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.edit +import androidx.core.net.toUri import androidx.core.view.children import androidx.core.view.get import androidx.core.view.isGone @@ -344,7 +344,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa activity?.findViewById(R.id.nav_rail_view)?.selectedItemId = R.id.navigation_search } else if (safeURI(str)?.scheme == APP_STRING_PLAYER) { - val uri = Uri.parse(str) + val uri = str.toUri() val name = uri.getQueryParameter("name") val url = URLDecoder.decode(uri.authority, "UTF-8") @@ -1924,7 +1924,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa fun buildMediaQueueItem(video: String): MediaQueueItem { // val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_PHOTO) //movieMetadata.putString(MediaMetadata.KEY_TITLE, "CloudStream") - val mediaInfo = MediaInfo.Builder(Uri.parse(video).toString()) + val mediaInfo = MediaInfo.Builder(video.toUri().toString()) .setStreamType(MediaInfo.STREAM_TYPE_NONE) .setContentType(MimeTypes.IMAGE_JPEG) // .setMetadata(movieMetadata).build() diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvKtPackage.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvKtPackage.kt index 102f0ac8b..faae39212 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvKtPackage.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvKtPackage.kt @@ -3,7 +3,6 @@ package com.lagradost.cloudstream3.actions.temp import android.app.Activity import android.content.Context import android.content.Intent -import android.net.Uri import androidx.core.net.toUri import com.lagradost.cloudstream3.actions.OpenInAppAction import com.lagradost.cloudstream3.actions.updateDurationAndPosition @@ -45,7 +44,7 @@ open class MpvKtPackage( intent.apply { putExtra("subs", result.subs.map { it.url.toUri() }.toTypedArray()) - setDataAndType(Uri.parse(link.url), "video/*") + setDataAndType(link.url.toUri(), "video/*") // m3u8 plays, but changing sources feature is not available // makeTempM3U8Intent(activity, this, result) diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvPackage.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvPackage.kt index 68e619c92..95d05aa3a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvPackage.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvPackage.kt @@ -3,7 +3,6 @@ package com.lagradost.cloudstream3.actions.temp import android.app.Activity import android.content.Context import android.content.Intent -import android.net.Uri import androidx.core.net.toUri import com.lagradost.api.Log import com.lagradost.cloudstream3.actions.OpenInAppAction @@ -44,7 +43,7 @@ open class MpvPackage(appName: String = "MPV", packageName: String = "is.xyz.mpv putExtra("title", video.name) if (index != null) { - setDataAndType(Uri.parse(result.links.getOrNull(index)?.url ?: return), "video/*") + setDataAndType((result.links.getOrNull(index)?.url ?: return).toUri(), "video/*") } else { makeTempM3U8Intent(context, this, result) } diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/PlayInBrowserAction.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/PlayInBrowserAction.kt index 7c1b68c05..bfd2926bf 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/PlayInBrowserAction.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/PlayInBrowserAction.kt @@ -2,7 +2,7 @@ package com.lagradost.cloudstream3.actions.temp import android.content.Context import android.content.Intent -import android.net.Uri +import androidx.core.net.toUri import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.actions.VideoClickAction import com.lagradost.cloudstream3.ui.result.LinkLoadingResult @@ -33,7 +33,7 @@ class PlayInBrowserAction: VideoClickAction() { ) { val link = result.links.getOrNull(index ?: 0) ?: return val i = Intent(Intent.ACTION_VIEW) - i.data = Uri.parse(link.url) + i.data = link.url.toUri() launch(i) } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/WebVideoCastPackage.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/WebVideoCastPackage.kt index 9f7eee7b8..963221bb3 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/WebVideoCastPackage.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/WebVideoCastPackage.kt @@ -3,7 +3,6 @@ package com.lagradost.cloudstream3.actions.temp import android.app.Activity import android.content.Context import android.content.Intent -import android.net.Uri import android.os.Bundle import androidx.core.net.toUri import com.lagradost.cloudstream3.USER_AGENT @@ -38,7 +37,7 @@ class WebVideoCastPackage: OpenInAppAction( val link = result.links[index ?: 0] intent.apply { - setDataAndType(Uri.parse(link.url), "video/*") + setDataAndType(link.url.toUri(), "video/*") val title = video.name ?: video.headerName diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/AppContextUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/AppContextUtils.kt index 8334833e4..0376b6835 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/AppContextUtils.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/AppContextUtils.kt @@ -18,7 +18,6 @@ import android.media.tv.TvContract.Channels.COLUMN_INTERNAL_PROVIDER_ID import android.net.ConnectivityManager import android.net.Network import android.net.NetworkCapabilities -import android.net.Uri import android.os.Build import android.os.Handler import android.os.Looper @@ -33,6 +32,7 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.RequiresApi import androidx.annotation.WorkerThread import androidx.appcompat.app.AlertDialog +import androidx.core.net.toUri import androidx.core.text.HtmlCompat import androidx.core.text.toSpanned import androidx.core.widget.ContentLoadingProgressBar @@ -170,10 +170,10 @@ object AppContextUtils { ) .setWatchNextType(TvContractCompat.WatchNextPrograms.WATCH_NEXT_TYPE_CONTINUE) .setTitle(title) - .setPosterArtUri(Uri.parse(card.posterUrl)) - .setIntentUri(Uri.parse(card.id?.let { + .setPosterArtUri(card.posterUrl?.toUri()) + .setIntentUri((card.id?.let { "$APP_STRING_RESUME_WATCHING://$it" - } ?: card.url)) + } ?: card.url).toUri()) .setInternalProviderId(card.url) .setLastEngagementTimeUtcMillis( resumeWatching?.updateTime ?: System.currentTimeMillis() @@ -603,7 +603,7 @@ object AppContextUtils { ) = (this.getActivity() ?: activity)?.runOnUiThread { try { val intent = Intent(Intent.ACTION_VIEW) - intent.data = Uri.parse(url) + intent.data = url.toUri() intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) // activityResultRegistry is used to fall back to webview if a browser is missing diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/CastHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/CastHelper.kt index d83731658..b48c8d40a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/CastHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/CastHelper.kt @@ -1,6 +1,6 @@ package com.lagradost.cloudstream3.utils -import android.net.Uri +import androidx.core.net.toUri import androidx.media3.common.MimeTypes import com.google.android.gms.cast.* import com.google.android.gms.cast.framework.CastSession @@ -41,7 +41,7 @@ object CastHelper { val srcPoster = epData.poster ?: holder.poster if (srcPoster != null) { - movieMetadata.addImage(WebImage(Uri.parse(srcPoster))) + movieMetadata.addImage(WebImage(srcPoster.toUri())) } var subIndex = 0 diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/PowerManagerAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/PowerManagerAPI.kt index 63f7e1559..e3c7d68df 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/PowerManagerAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/PowerManagerAPI.kt @@ -3,13 +3,13 @@ package com.lagradost.cloudstream3.utils import android.content.ActivityNotFoundException import android.content.Context import android.content.Intent -import android.net.Uri import android.os.Build.VERSION.SDK_INT import android.os.PowerManager import android.provider.Settings import android.util.Log import androidx.appcompat.app.AlertDialog import androidx.core.content.edit +import androidx.core.net.toUri import androidx.preference.PreferenceManager import com.lagradost.cloudstream3.BuildConfig import com.lagradost.cloudstream3.CommonActivity.showToast @@ -67,7 +67,7 @@ object BatteryOptimizationChecker { try { val intent = Intent().apply { action = Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS - data = Uri.parse("package:$PACKAGE_NAME") + data = "package:$PACKAGE_NAME".toUri() } startActivity(intent) } catch (t: Throwable) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/TvChannelUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/TvChannelUtils.kt index 17568c8d2..798cb9d07 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/TvChannelUtils.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/TvChannelUtils.kt @@ -4,8 +4,8 @@ import android.content.ComponentName import android.content.ContentUris import android.content.Context import android.content.Intent -import android.net.Uri import android.util.Log +import androidx.core.net.toUri import androidx.tvprovider.media.tv.Channel import androidx.tvprovider.media.tv.PreviewProgram import androidx.tvprovider.media.tv.TvContractCompat @@ -84,12 +84,12 @@ object TvChannelUtils { } .setContentId(item.url) .setType(TvContractCompat.PreviewPrograms.TYPE_MOVIE) - .setIntentUri(Uri.parse(csshareUri)) + .setIntentUri(csshareUri.toUri()) .setPosterArtAspectRatio(TvContractCompat.PreviewPrograms.ASPECT_RATIO_2_3) // Validate poster URL before setting if (!poster.isNullOrBlank() && poster.startsWith("http")) { - builder.setPosterArtUri(Uri.parse(poster)) + builder.setPosterArtUri(poster.toUri()) } val program = builder.build() @@ -135,14 +135,14 @@ object TvChannelUtils { fun createTvChannel(context: Context) { val componentName = ComponentName(context, MainActivity::class.java) - val iconUri = Uri.parse("android.resource://${context.packageName}/mipmap/ic_launcher") + val iconUri = "android.resource://${context.packageName}/mipmap/ic_launcher".toUri() val inputId = TvContractCompat.buildInputId(componentName) val channel = Channel.Builder() .setType(TvContractCompat.Channels.TYPE_PREVIEW) .setAppLinkIconUri(iconUri) .setDisplayName(context.getString(R.string.app_name)) .setAppLinkIntent(Intent(Intent.ACTION_VIEW).apply { - data = Uri.parse("cloudstreamapp://open") + data = "cloudstreamapp://open".toUri() }) .setInputId(inputId) .build() From e0231520d587ec5ab8e7fb9de2928a997e3dcb39 Mon Sep 17 00:00:00 2001 From: rockhero1234 <149141736+rockhero1234@users.noreply.github.com> Date: Thu, 11 Dec 2025 22:07:19 +0530 Subject: [PATCH 187/513] added mpvex (#2309) --- .../com/lagradost/cloudstream3/actions/VideoClickAction.kt | 2 ++ .../com/lagradost/cloudstream3/actions/temp/MpvPackage.kt | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/VideoClickAction.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/VideoClickAction.kt index d4f35f081..4843b7617 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/actions/VideoClickAction.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/VideoClickAction.kt @@ -16,6 +16,7 @@ import com.lagradost.cloudstream3.actions.temp.BiglyBTPackage import com.lagradost.cloudstream3.actions.temp.CopyClipboardAction import com.lagradost.cloudstream3.actions.temp.JustPlayerPackage import com.lagradost.cloudstream3.actions.temp.LibreTorrentPackage +import com.lagradost.cloudstream3.actions.temp.MpvExPackage import com.lagradost.cloudstream3.actions.temp.MpvKtPackage import com.lagradost.cloudstream3.actions.temp.MpvKtPreviewPackage import com.lagradost.cloudstream3.actions.temp.MpvPackage @@ -51,6 +52,7 @@ object VideoClickActionHolder { // main support external apps VlcPackage(), MpvPackage(), + MpvExPackage(), NextPlayerPackage(), JustPlayerPackage(), FcastAction(), diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvPackage.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvPackage.kt index 95d05aa3a..cd49eb994 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvPackage.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/MpvPackage.kt @@ -17,6 +17,9 @@ import com.lagradost.cloudstream3.utils.ExtractorLinkType // https://github.com/mpv-android/mpv-android/blob/0eb3cdc6f1632636b9c30d52ec50e4b017661980/app/src/main/java/is/xyz/mpv/MPVActivity.kt#L904 // https://mpv-android.github.io/mpv-android/intent.html +//https://github.com/marlboro-advance/mpvEx +class MpvExPackage: MpvPackage("mpvEx","app.marlboroadvance.mpvex","app.marlboroadvance.mpvex.ui.player.PlayerActivity") + class MpvYTDLPackage : MpvPackage("MPV YTDL", "is.xyz.mpv.ytdl") { override val sourceTypes = setOf( ExtractorLinkType.VIDEO, @@ -25,10 +28,10 @@ class MpvYTDLPackage : MpvPackage("MPV YTDL", "is.xyz.mpv.ytdl") { ) } -open class MpvPackage(appName: String = "MPV", packageName: String = "is.xyz.mpv"): OpenInAppAction( +open class MpvPackage(appName: String = "MPV", packageName: String = "is.xyz.mpv",intentClass:String = "is.xyz.mpv.MPVActivity"): OpenInAppAction( txt(appName), packageName, - "is.xyz.mpv.MPVActivity" + intentClass ) { override val oneSource = true // mpv has poor playlist support on TV override suspend fun putExtra( From 9a9e71354c0068d4d3be5a7d2fd359ffebdf6edb Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 11 Dec 2025 09:55:00 -0700 Subject: [PATCH 188/513] Remove check for SearchAutoComplete (#2313) --- .../java/com/lagradost/cloudstream3/CommonActivity.kt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt index e4e7c69f4..58d65b516 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt @@ -51,7 +51,7 @@ import com.lagradost.cloudstream3.ui.settings.extensions.PluginAdapter import com.lagradost.cloudstream3.utils.AppContextUtils.isRtl import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Event -import com.lagradost.cloudstream3.utils.UIHelper +import com.lagradost.cloudstream3.utils.UIHelper.showInputMethod import com.lagradost.cloudstream3.utils.UIHelper.toPx import com.lagradost.cloudstream3.utils.UiText import java.lang.ref.WeakReference @@ -648,6 +648,7 @@ object CommonActivity { else -> null } + // println("NEXT FOCUS : $nextView") if (nextView != null) { nextView.requestFocus() @@ -655,10 +656,8 @@ object CommonActivity { return true } - if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER && - (act.currentFocus is SearchView || act.currentFocus is SearchView.SearchAutoComplete) - ) { - UIHelper.showInputMethod(act.currentFocus?.findFocus()) + if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER && currentFocus is SearchView) { + showInputMethod(currentFocus.findFocus()) } //println("Keycode: $keyCode") @@ -667,7 +666,6 @@ object CommonActivity { // "Got Keycode $keyCode | ${KeyEvent.keyCodeToString(keyCode)} \n ${event?.action}", // Toast.LENGTH_LONG //) - } // if someone else want to override the focus then don't handle the event as it is already From 7ded6a4fa1c16a7234a96aff81996c9a3994b459 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 11 Dec 2025 09:56:34 -0700 Subject: [PATCH 189/513] Add tools:targetApi to appease lint (#2315) Part of my work to fix all error level lint issues, in order to eventually enable `failOnError` and ensure better compatability with older API levels and a more consistent reporting of issues. --- .../main/res/layout/settings_title_top.xml | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/app/src/main/res/layout/settings_title_top.xml b/app/src/main/res/layout/settings_title_top.xml index 1e3671a6f..646371405 100644 --- a/app/src/main/res/layout/settings_title_top.xml +++ b/app/src/main/res/layout/settings_title_top.xml @@ -1,22 +1,24 @@ + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + android:id="@+id/settings_top_root" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?attr/primaryGrayBackground" + android:orientation="vertical"> + android:id="@android:id/list_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?attr/primaryBlackBackground" + app:layout_behavior="@string/appbar_scrolling_view_behavior" + tools:targetApi="n" /> + \ No newline at end of file From 350d19bd6be3c0b1084ab6c28869ef2889ba4411 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 11 Dec 2025 10:27:54 -0700 Subject: [PATCH 190/513] Some minor miscellaneous cleanup (#2306) * Some minor miscellaneous cleanup * Remove classes --- .../lagradost/cloudstream3/CommonActivity.kt | 6 +-- .../HeaderDecorationBindingAdapter.kt | 11 ----- .../cloudstream3/ui/HeaderViewDecoration.kt | 42 ------------------- 3 files changed, 3 insertions(+), 56 deletions(-) delete mode 100644 app/src/main/java/com/lagradost/cloudstream3/HeaderDecorationBindingAdapter.kt delete mode 100644 app/src/main/java/com/lagradost/cloudstream3/ui/HeaderViewDecoration.kt diff --git a/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt index 58d65b516..2a994b8b7 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/CommonActivity.kt @@ -24,6 +24,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.SearchView import androidx.core.content.ContextCompat import androidx.core.view.children +import androidx.core.view.isNotEmpty import androidx.preference.PreferenceManager import com.google.android.gms.cast.framework.CastSession import com.google.android.material.chip.ChipGroup @@ -421,8 +422,7 @@ object CommonActivity { private fun View.hasContent(): Boolean { return isShown && when (this) { - //is RecyclerView -> this.childCount > 0 - is ViewGroup -> this.childCount > 0 + is ViewGroup -> this.isNotEmpty() else -> true } } @@ -452,7 +452,7 @@ object CommonActivity { // if cant focus but visible then break and let android decide // the exception if is the view is a parent and has children that wants focus val hasChildrenThatWantsFocus = (next as? ViewGroup)?.let { parent -> - parent.descendantFocusability == ViewGroup.FOCUS_AFTER_DESCENDANTS && parent.childCount > 0 + parent.descendantFocusability == ViewGroup.FOCUS_AFTER_DESCENDANTS && parent.isNotEmpty() } ?: false if (!next.isFocusable && shown && !hasChildrenThatWantsFocus) return null diff --git a/app/src/main/java/com/lagradost/cloudstream3/HeaderDecorationBindingAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/HeaderDecorationBindingAdapter.kt deleted file mode 100644 index 045a7963a..000000000 --- a/app/src/main/java/com/lagradost/cloudstream3/HeaderDecorationBindingAdapter.kt +++ /dev/null @@ -1,11 +0,0 @@ -package com.lagradost.cloudstream3 - -import android.view.LayoutInflater -import androidx.annotation.LayoutRes -import androidx.recyclerview.widget.RecyclerView -import com.lagradost.cloudstream3.ui.HeaderViewDecoration - -fun setHeaderDecoration(view: RecyclerView, @LayoutRes headerViewRes: Int) { - val headerView = LayoutInflater.from(view.context).inflate(headerViewRes, null) - view.addItemDecoration(HeaderViewDecoration(headerView)) -} \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/HeaderViewDecoration.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/HeaderViewDecoration.kt deleted file mode 100644 index 40c03012a..000000000 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/HeaderViewDecoration.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.lagradost.cloudstream3.ui - -import android.graphics.Canvas -import android.graphics.Rect -import android.view.View -import androidx.recyclerview.widget.RecyclerView - -class HeaderViewDecoration(private val customView: View) : RecyclerView.ItemDecoration() { - override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) { - super.onDraw(c, parent, state) - customView.layout(parent.left, 0, parent.right, customView.measuredHeight) - for (i in 0 until parent.childCount) { - val view = parent.getChildAt(i) - if (parent.getChildAdapterPosition(view) == 0) { - c.save() - val height = customView.measuredHeight - val top = view.top - height - c.translate(0f, top.toFloat()) - customView.draw(c) - c.restore() - break - } - } - } - - override fun getItemOffsets( - outRect: Rect, - view: View, - parent: RecyclerView, - state: RecyclerView.State - ) { - if (parent.getChildAdapterPosition(view) == 0) { - customView.measure( - View.MeasureSpec.makeMeasureSpec(parent.measuredWidth, View.MeasureSpec.AT_MOST), - View.MeasureSpec.makeMeasureSpec(parent.measuredHeight, View.MeasureSpec.AT_MOST) - ) - outRect.set(0, customView.measuredHeight, 0, 0) - } else { - outRect.setEmpty() - } - } -} \ No newline at end of file From 74ceaf9a3ffeee73a1831d983050da527749f2c6 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 11 Dec 2025 12:27:36 -0700 Subject: [PATCH 191/513] Add a lint suppression for RestrictedApi (#2312) --- .../java/com/lagradost/cloudstream3/utils/TvChannelUtils.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/TvChannelUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/TvChannelUtils.kt index 798cb9d07..feecbe312 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/TvChannelUtils.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/TvChannelUtils.kt @@ -1,5 +1,6 @@ package com.lagradost.cloudstream3.utils +import android.annotation.SuppressLint import android.content.ComponentName import android.content.ContentUris import android.content.Context @@ -66,6 +67,7 @@ object TvChannelUtils { } /** Insert programs into a channel */ + @SuppressLint("RestrictedApi") fun addPrograms(context: Context, channelId: Long, items: List) { for (item in items) { try { From a836b268495c1c988455eede70203594be09a70a Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 11 Dec 2025 12:32:32 -0700 Subject: [PATCH 192/513] Cleanup InAppUpdater (#2298) The only functional change here is that the commit in the updater dialog was normalized to what it is everywhere else, meaning it is 7 not 10 characters now. I also have another patch prepared to convert this entire class to an actual object rather than just a class with only a companion object but since that touches every single line due to indentation changes, I decided to split it in order to make it easier to review. --- .../cloudstream3/utils/InAppUpdater.kt | 237 ++++++++---------- 1 file changed, 104 insertions(+), 133 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt index 12befafe0..3ad6eb0f7 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt @@ -4,32 +4,34 @@ import android.app.Activity import android.content.Context import android.content.Intent import android.net.Uri +import android.text.TextUtils import android.util.Log import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.core.content.ContextCompat import androidx.core.content.FileProvider +import androidx.core.content.edit import androidx.preference.PreferenceManager import com.fasterxml.jackson.annotation.JsonProperty -import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.BuildConfig import com.lagradost.cloudstream3.CommonActivity.showToast +import com.lagradost.cloudstream3.MainActivity.Companion.deleteFileOnExit +import com.lagradost.cloudstream3.R +import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.mvvm.logError +import com.lagradost.cloudstream3.services.PackageInstallerService +import com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.Coroutines.ioSafe +import java.io.BufferedReader +import java.io.File +import java.io.InputStreamReader +import java.io.IOException import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import okio.BufferedSink import okio.buffer import okio.sink -import java.io.File -import android.text.TextUtils -import com.lagradost.cloudstream3.MainActivity.Companion.deleteFileOnExit -import com.lagradost.cloudstream3.services.PackageInstallerService -import com.lagradost.cloudstream3.utils.AppContextUtils.setDefaultFocus -import java.io.BufferedReader -import java.io.IOException -import java.io.InputStreamReader - class InAppUpdater { companion object { @@ -38,53 +40,51 @@ class InAppUpdater { private const val LOG_TAG = "InAppUpdater" - // === IN APP UPDATER === - data class GithubAsset( + private data class GithubAsset( @JsonProperty("name") val name: String, - @JsonProperty("size") val size: Int, // Size bytes - @JsonProperty("browser_download_url") val browserDownloadUrl: String, // download link + @JsonProperty("size") val size: Int, // Size in bytes + @JsonProperty("browser_download_url") val browserDownloadUrl: String, @JsonProperty("content_type") val contentType: String, // application/vnd.android.package-archive ) - data class GithubRelease( + private data class GithubRelease( @JsonProperty("tag_name") val tagName: String, // Version code - @JsonProperty("body") val body: String, // Desc + @JsonProperty("body") val body: String, // Description @JsonProperty("assets") val assets: List, - @JsonProperty("target_commitish") val targetCommitish: String, // branch + @JsonProperty("target_commitish") val targetCommitish: String, // Branch @JsonProperty("prerelease") val prerelease: Boolean, - @JsonProperty("node_id") val nodeId: String //Node Id + @JsonProperty("node_id") val nodeId: String, ) - data class GithubObject( - @JsonProperty("sha") val sha: String, // sha 256 hash - @JsonProperty("type") val type: String, // object type + private data class GithubObject( + @JsonProperty("sha") val sha: String, // SHA-256 hash + @JsonProperty("type") val type: String, @JsonProperty("url") val url: String, ) - data class GithubTag( + private data class GithubTag( @JsonProperty("object") val githubObject: GithubObject, ) - data class Update( + private data class Update( @JsonProperty("shouldUpdate") val shouldUpdate: Boolean, @JsonProperty("updateURL") val updateURL: String?, @JsonProperty("updateVersion") val updateVersion: String?, @JsonProperty("changelog") val changelog: String?, - @JsonProperty("updateNodeId") val updateNodeId: String? + @JsonProperty("updateNodeId") val updateNodeId: String?, ) private suspend fun Activity.getAppUpdate(): Update { return try { val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) - if (settingsManager.getBoolean( + if ( + settingsManager.getBoolean( getString(R.string.prerelease_update_key), resources.getBoolean(R.bool.is_prerelease) ) ) { getPreReleaseUpdate() - } else { - getReleaseUpdate() - } + } else getReleaseUpdate() } catch (e: Exception) { Log.e(LOG_TAG, Log.getStackTraceString(e)) Update(false, null, null, null, null) @@ -94,56 +94,44 @@ class InAppUpdater { private suspend fun Activity.getReleaseUpdate(): Update { val url = "https://api.github.com/repos/$GITHUB_USER_NAME/$GITHUB_REPO/releases" val headers = mapOf("Accept" to "application/vnd.github.v3+json") - val response = - parseJson>( - app.get( - url, - headers = headers - ).text - ) + val response = parseJson>( + app.get(url, headers = headers).text + ) val versionRegex = Regex("""(.*?((\d+)\.(\d+)\.(\d+))\.apk)""") val versionRegexLocal = Regex("""(.*?((\d+)\.(\d+)\.(\d+)).*)""") - /* - val releases = response.map { it.assets }.flatten() - .filter { it.content_type == "application/vnd.android.package-archive" } - val found = - releases.sortedWith(compareBy { - versionRegex.find(it.name)?.groupValues?.get(2) - }).toList().lastOrNull()*/ - val foundList = - response.filter { rel -> - !rel.prerelease - }.sortedWith(compareBy { release -> - release.assets.firstOrNull { it.contentType == "application/vnd.android.package-archive" }?.name?.let { it1 -> - versionRegex.find( - it1 - )?.groupValues?.let { - it[3].toInt() * 100_000_000 + it[4].toInt() * 10_000 + it[5].toInt() - } - } - }).toList() + val foundList = response.filter { rel -> + !rel.prerelease + }.sortedWith(compareBy { release -> + release.assets.firstOrNull { it.contentType == "application/vnd.android.package-archive" }?.name?.let { it1 -> + versionRegex.find( + it1 + )?.groupValues?.let { + it[3].toInt() * 100_000_000 + it[4].toInt() * 10_000 + it[5].toInt() + } + } + }).toList() + val found = foundList.lastOrNull() val foundAsset = found?.assets?.getOrNull(0) val currentVersion = packageName?.let { - packageManager.getPackageInfo( - it, - 0 - ) + packageManager.getPackageInfo(it, 0) } foundAsset?.name?.let { assetName -> val foundVersion = versionRegex.find(assetName) val shouldUpdate = - if (foundAsset.browserDownloadUrl != "" && foundVersion != null) currentVersion?.versionName?.let { versionName -> - versionRegexLocal.find(versionName)?.groupValues?.let { - it[3].toInt() * 100_000_000 + it[4].toInt() * 10_000 + it[5].toInt() - } - }?.compareTo( - foundVersion.groupValues.let { - it[3].toInt() * 100_000_000 + it[4].toInt() * 10_000 + it[5].toInt() - } - )!! < 0 else false + if (foundAsset.browserDownloadUrl != "" && foundVersion != null) { + currentVersion?.versionName?.let { versionName -> + versionRegexLocal.find(versionName)?.groupValues?.let { + it[3].toInt() * 100_000_000 + it[4].toInt() * 10_000 + it[5].toInt() + } + }?.compareTo( + foundVersion.groupValues.let { + it[3].toInt() * 100_000_000 + it[4].toInt() * 10_000 + it[5].toInt() + } + )!! < 0 + } else false return if (foundVersion != null) { Update( shouldUpdate, @@ -152,57 +140,43 @@ class InAppUpdater { found.body, found.nodeId ) - } else { - Update(false, null, null, null, null) - } + } else Update(false, null, null, null, null) } + return Update(false, null, null, null, null) } private suspend fun Activity.getPreReleaseUpdate(): Update { - val tagUrl = - "https://api.github.com/repos/$GITHUB_USER_NAME/$GITHUB_REPO/git/ref/tags/pre-release" + val tagUrl = "https://api.github.com/repos/$GITHUB_USER_NAME/$GITHUB_REPO/git/ref/tags/pre-release" val releaseUrl = "https://api.github.com/repos/$GITHUB_USER_NAME/$GITHUB_REPO/releases" val headers = mapOf("Accept" to "application/vnd.github.v3+json") - val response = - parseJson>(app.get(releaseUrl, headers = headers).text) + val response = parseJson>( + app.get(releaseUrl, headers = headers).text + ) + + val found = response.lastOrNull { rel -> + rel.prerelease || rel.tagName == "pre-release" + } - val found = - response.lastOrNull { rel -> - rel.prerelease || rel.tagName == "pre-release" - } val foundAsset = found?.assets?.filter { it -> it.contentType == "application/vnd.android.package-archive" }?.getOrNull(0) - val tagResponse = - parseJson(app.get(tagUrl, headers = headers).text) - - Log.d(LOG_TAG, "Fetched GitHub tag: ${tagResponse.githubObject.sha.take(7)}") - - val shouldUpdate = - (getString(R.string.commit_hash) - .trim { c -> c.isWhitespace() } - .take(7) - != - tagResponse.githubObject.sha - .trim { c -> c.isWhitespace() } - .take(7)) - return if (foundAsset != null) { + val tagResponse = parseJson(app.get(tagUrl, headers = headers).text) + val updateCommitHash = tagResponse.githubObject.sha.trim().take(7) + Log.d(LOG_TAG, "Fetched GitHub tag: $updateCommitHash") + Update( - shouldUpdate, + getString(R.string.commit_hash) != updateCommitHash, foundAsset.browserDownloadUrl, - tagResponse.githubObject.sha.take(10), + updateCommitHash, found.body, found.nodeId ) - } else { - Update(false, null, null, null, null) - } + } else Update(false, null, null, null, null) } - private val updateLock = Mutex() private suspend fun Activity.downloadUpdate(url: String): Boolean { @@ -214,9 +188,7 @@ class InAppUpdater { // Delete all old updates this.cacheDir.listFiles()?.filter { it.name.startsWith(appUpdateName) && it.extension == appUpdateSuffix - }?.forEach { - deleteFileOnExit(it) - } + }?.forEach { deleteFileOnExit(it) } val downloadedFile = File.createTempFile(appUpdateName, ".$appUpdateSuffix") val sink: BufferedSink = downloadedFile.sink().buffer() @@ -226,8 +198,10 @@ class InAppUpdater { sink.close() openApk(this, Uri.fromFile(downloadedFile)) } + return true } catch (e: Exception) { + logError(e) return false } } @@ -255,23 +229,20 @@ class InAppUpdater { /** * @param checkAutoUpdate if the update check was launched automatically - **/ + */ suspend fun Activity.runAutoUpdate(checkAutoUpdate: Boolean = true): Boolean { val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) - if (!checkAutoUpdate || settingsManager.getBoolean( getString(R.string.auto_update_key), true ) ) { val update = getAppUpdate() - if ( - update.shouldUpdate && - update.updateURL != null) { - + if (update.shouldUpdate && update.updateURL != null) { // Check if update should be skipped - val updateNodeId = - settingsManager.getString(getString(R.string.skip_update_key), "") + val updateNodeId = settingsManager.getString( + getString(R.string.skip_update_key), "" + ) // Skips the update if its an automatic update and the update is skipped // This allows updating manually @@ -282,10 +253,7 @@ class InAppUpdater { runOnUiThread { try { val currentVersion = packageName?.let { - packageManager.getPackageInfo( - it, - 0 - ) + packageManager.getPackageInfo(it, 0) } val builder = AlertDialog.Builder(this, R.style.AlertDialogCustom) @@ -302,8 +270,6 @@ class InAppUpdater { } // Sanitized because it looks cluttered builder.setMessage(sanitizedChangelog) - - val context = this builder.apply { setPositiveButton(R.string.update) { _, _ -> // Forcefully start any delayed installations @@ -312,42 +278,45 @@ class InAppUpdater { showToast(R.string.download_started, Toast.LENGTH_LONG) // Check if the setting hasn't been changed - if (settingsManager.getInt( + if ( + settingsManager.getInt( getString(R.string.apk_installer_key), -1 ) == -1 ) { - if (isMiUi()) // Set to legacy if using miui - settingsManager.edit() - .putInt(getString(R.string.apk_installer_key), 1) - .apply() + // Set to legacy installer if using MIUI + if (isMiUi()) { + settingsManager.edit { + putInt(getString(R.string.apk_installer_key), 1) + } + } } - val currentInstaller = - settingsManager.getInt( - getString(R.string.apk_installer_key), - 0 - ) + val currentInstaller = settingsManager.getInt( + getString(R.string.apk_installer_key), + 0 + ) when (currentInstaller) { // New method 0 -> { val intent = PackageInstallerService.Companion.getIntent( - context, + this@runAutoUpdate, update.updateURL ) - ContextCompat.startForegroundService(context, intent) + ContextCompat.startForegroundService(this@runAutoUpdate, intent) } // Legacy 1 -> { ioSafe { - if (!downloadUpdate(update.updateURL)) + if (!downloadUpdate(update.updateURL)) { runOnUiThread { showToast( R.string.download_failed, Toast.LENGTH_LONG ) } + } } } } @@ -357,10 +326,12 @@ class InAppUpdater { if (checkAutoUpdate) { setNeutralButton(R.string.skip_update) { _, _ -> - settingsManager.edit().putString( - getString(R.string.skip_update_key), - update.updateNodeId ?: "" - ).apply() + settingsManager.edit { + putString( + getString(R.string.skip_update_key), + update.updateNodeId ?: "" + ) + } } } } @@ -386,7 +357,7 @@ class InAppUpdater { BufferedReader(InputStreamReader(p.inputStream), 1024).use { it.readLine() } - } catch (ex: IOException) { + } catch (_: IOException) { null } } From 70121f45482fbd6cd6551930681a32a7c4151296 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 11 Dec 2025 12:41:51 -0700 Subject: [PATCH 193/513] Fix crash on Android 5 (#2320) I just realized I hadn't done a PR to fix this issue yet but this issue is why I've been working on fixing all error level lint issues so that we can enable `failOnError` which would have prevented this. --- .../lagradost/cloudstream3/ui/player/FullScreenPlayer.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 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 3821d880a..4be6c250c 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 @@ -1875,7 +1875,6 @@ open class FullScreenPlayer : AbstractPlayerFragment() { } playerBinding?.apply { - if (isLayout(TV or EMULATOR)) { mapOf( playerGoBack to playerGoBackText, @@ -1990,8 +1989,10 @@ open class FullScreenPlayer : AbstractPlayerFragment() { return@setOnTouchListener handleMotionEvent(callView, event) } - playerControlsScroll.setOnScrollChangeListener { _, _, _, _, _ -> - autoHide() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + playerControlsScroll.setOnScrollChangeListener { _, _, _, _, _ -> + autoHide() + } } exoProgress.setOnTouchListener { _, event -> From 5d2e432614a4841702ce66390e4a1f02b86b5796 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 11 Dec 2025 13:03:37 -0700 Subject: [PATCH 194/513] Make InAppUpdater an object (#2321) Better than a class with only a companion object I think. --- .../lagradost/cloudstream3/MainActivity.kt | 2 +- .../ui/settings/SettingsUpdates.kt | 2 +- .../cloudstream3/utils/InAppUpdater.kt | 532 +++++++++--------- 3 files changed, 267 insertions(+), 269 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index c12b10f36..f6b722fea 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -159,7 +159,7 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper.accounts import com.lagradost.cloudstream3.utils.DataStoreHelper.migrateResumeWatching import com.lagradost.cloudstream3.utils.Event import com.lagradost.cloudstream3.utils.ImageLoader.loadImage -import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate +import com.lagradost.cloudstream3.utils.InAppUpdater.runAutoUpdate import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog import com.lagradost.cloudstream3.utils.SnackbarHelper.showSnackbar import com.lagradost.cloudstream3.utils.UIHelper.changeStatusBarState diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt index 6ff072038..e2805c402 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsUpdates.kt @@ -33,7 +33,7 @@ import com.lagradost.cloudstream3.ui.settings.utils.getChooseFolderLauncher import com.lagradost.cloudstream3.utils.BackupUtils import com.lagradost.cloudstream3.utils.BackupUtils.restorePrompt import com.lagradost.cloudstream3.utils.Coroutines.ioSafe -import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate +import com.lagradost.cloudstream3.utils.InAppUpdater.runAutoUpdate import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog import com.lagradost.cloudstream3.utils.UIHelper.clipboardHelper diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt index 3ad6eb0f7..45891a5d0 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt @@ -33,333 +33,331 @@ import okio.BufferedSink import okio.buffer import okio.sink -class InAppUpdater { - companion object { - private const val GITHUB_USER_NAME = "recloudstream" - private const val GITHUB_REPO = "cloudstream" +object InAppUpdater { + private const val GITHUB_USER_NAME = "recloudstream" + private const val GITHUB_REPO = "cloudstream" - private const val LOG_TAG = "InAppUpdater" + private const val LOG_TAG = "InAppUpdater" - private data class GithubAsset( - @JsonProperty("name") val name: String, - @JsonProperty("size") val size: Int, // Size in bytes - @JsonProperty("browser_download_url") val browserDownloadUrl: String, - @JsonProperty("content_type") val contentType: String, // application/vnd.android.package-archive - ) + private data class GithubAsset( + @JsonProperty("name") val name: String, + @JsonProperty("size") val size: Int, // Size in bytes + @JsonProperty("browser_download_url") val browserDownloadUrl: String, + @JsonProperty("content_type") val contentType: String, // application/vnd.android.package-archive + ) - private data class GithubRelease( - @JsonProperty("tag_name") val tagName: String, // Version code - @JsonProperty("body") val body: String, // Description - @JsonProperty("assets") val assets: List, - @JsonProperty("target_commitish") val targetCommitish: String, // Branch - @JsonProperty("prerelease") val prerelease: Boolean, - @JsonProperty("node_id") val nodeId: String, - ) + private data class GithubRelease( + @JsonProperty("tag_name") val tagName: String, // Version code + @JsonProperty("body") val body: String, // Description + @JsonProperty("assets") val assets: List, + @JsonProperty("target_commitish") val targetCommitish: String, // Branch + @JsonProperty("prerelease") val prerelease: Boolean, + @JsonProperty("node_id") val nodeId: String, + ) - private data class GithubObject( - @JsonProperty("sha") val sha: String, // SHA-256 hash - @JsonProperty("type") val type: String, - @JsonProperty("url") val url: String, - ) + private data class GithubObject( + @JsonProperty("sha") val sha: String, // SHA-256 hash + @JsonProperty("type") val type: String, + @JsonProperty("url") val url: String, + ) - private data class GithubTag( - @JsonProperty("object") val githubObject: GithubObject, - ) + private data class GithubTag( + @JsonProperty("object") val githubObject: GithubObject, + ) - private data class Update( - @JsonProperty("shouldUpdate") val shouldUpdate: Boolean, - @JsonProperty("updateURL") val updateURL: String?, - @JsonProperty("updateVersion") val updateVersion: String?, - @JsonProperty("changelog") val changelog: String?, - @JsonProperty("updateNodeId") val updateNodeId: String?, - ) + private data class Update( + @JsonProperty("shouldUpdate") val shouldUpdate: Boolean, + @JsonProperty("updateURL") val updateURL: String?, + @JsonProperty("updateVersion") val updateVersion: String?, + @JsonProperty("changelog") val changelog: String?, + @JsonProperty("updateNodeId") val updateNodeId: String?, + ) - private suspend fun Activity.getAppUpdate(): Update { - return try { - val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) - if ( - settingsManager.getBoolean( - getString(R.string.prerelease_update_key), - resources.getBoolean(R.bool.is_prerelease) - ) - ) { - getPreReleaseUpdate() - } else getReleaseUpdate() - } catch (e: Exception) { - Log.e(LOG_TAG, Log.getStackTraceString(e)) - Update(false, null, null, null, null) - } + private suspend fun Activity.getAppUpdate(): Update { + return try { + val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) + if ( + settingsManager.getBoolean( + getString(R.string.prerelease_update_key), + resources.getBoolean(R.bool.is_prerelease) + ) + ) { + getPreReleaseUpdate() + } else getReleaseUpdate() + } catch (e: Exception) { + Log.e(LOG_TAG, Log.getStackTraceString(e)) + Update(false, null, null, null, null) } + } - private suspend fun Activity.getReleaseUpdate(): Update { - val url = "https://api.github.com/repos/$GITHUB_USER_NAME/$GITHUB_REPO/releases" - val headers = mapOf("Accept" to "application/vnd.github.v3+json") - val response = parseJson>( - app.get(url, headers = headers).text - ) + private suspend fun Activity.getReleaseUpdate(): Update { + val url = "https://api.github.com/repos/$GITHUB_USER_NAME/$GITHUB_REPO/releases" + val headers = mapOf("Accept" to "application/vnd.github.v3+json") + val response = parseJson>( + app.get(url, headers = headers).text + ) - val versionRegex = Regex("""(.*?((\d+)\.(\d+)\.(\d+))\.apk)""") - val versionRegexLocal = Regex("""(.*?((\d+)\.(\d+)\.(\d+)).*)""") - val foundList = response.filter { rel -> - !rel.prerelease - }.sortedWith(compareBy { release -> - release.assets.firstOrNull { it.contentType == "application/vnd.android.package-archive" }?.name?.let { it1 -> - versionRegex.find( - it1 - )?.groupValues?.let { - it[3].toInt() * 100_000_000 + it[4].toInt() * 10_000 + it[5].toInt() - } + val versionRegex = Regex("""(.*?((\d+)\.(\d+)\.(\d+))\.apk)""") + val versionRegexLocal = Regex("""(.*?((\d+)\.(\d+)\.(\d+)).*)""") + val foundList = response.filter { rel -> + !rel.prerelease + }.sortedWith(compareBy { release -> + release.assets.firstOrNull { it.contentType == "application/vnd.android.package-archive" }?.name?.let { it1 -> + versionRegex.find( + it1 + )?.groupValues?.let { + it[3].toInt() * 100_000_000 + it[4].toInt() * 10_000 + it[5].toInt() } - }).toList() - - val found = foundList.lastOrNull() - val foundAsset = found?.assets?.getOrNull(0) - val currentVersion = packageName?.let { - packageManager.getPackageInfo(it, 0) } + }).toList() - foundAsset?.name?.let { assetName -> - val foundVersion = versionRegex.find(assetName) - val shouldUpdate = - if (foundAsset.browserDownloadUrl != "" && foundVersion != null) { - currentVersion?.versionName?.let { versionName -> - versionRegexLocal.find(versionName)?.groupValues?.let { - it[3].toInt() * 100_000_000 + it[4].toInt() * 10_000 + it[5].toInt() - } - }?.compareTo( - foundVersion.groupValues.let { - it[3].toInt() * 100_000_000 + it[4].toInt() * 10_000 + it[5].toInt() - } - )!! < 0 - } else false - return if (foundVersion != null) { - Update( - shouldUpdate, - foundAsset.browserDownloadUrl, - foundVersion.groupValues[2], - found.body, - found.nodeId - ) - } else Update(false, null, null, null, null) - } - - return Update(false, null, null, null, null) + val found = foundList.lastOrNull() + val foundAsset = found?.assets?.getOrNull(0) + val currentVersion = packageName?.let { + packageManager.getPackageInfo(it, 0) } - private suspend fun Activity.getPreReleaseUpdate(): Update { - val tagUrl = "https://api.github.com/repos/$GITHUB_USER_NAME/$GITHUB_REPO/git/ref/tags/pre-release" - val releaseUrl = "https://api.github.com/repos/$GITHUB_USER_NAME/$GITHUB_REPO/releases" - val headers = mapOf("Accept" to "application/vnd.github.v3+json") - val response = parseJson>( - app.get(releaseUrl, headers = headers).text - ) - - val found = response.lastOrNull { rel -> - rel.prerelease || rel.tagName == "pre-release" - } - - val foundAsset = found?.assets?.filter { it -> - it.contentType == "application/vnd.android.package-archive" - }?.getOrNull(0) - - return if (foundAsset != null) { - val tagResponse = parseJson(app.get(tagUrl, headers = headers).text) - val updateCommitHash = tagResponse.githubObject.sha.trim().take(7) - Log.d(LOG_TAG, "Fetched GitHub tag: $updateCommitHash") - + foundAsset?.name?.let { assetName -> + val foundVersion = versionRegex.find(assetName) + val shouldUpdate = + if (foundAsset.browserDownloadUrl != "" && foundVersion != null) { + currentVersion?.versionName?.let { versionName -> + versionRegexLocal.find(versionName)?.groupValues?.let { + it[3].toInt() * 100_000_000 + it[4].toInt() * 10_000 + it[5].toInt() + } + }?.compareTo( + foundVersion.groupValues.let { + it[3].toInt() * 100_000_000 + it[4].toInt() * 10_000 + it[5].toInt() + } + )!! < 0 + } else false + return if (foundVersion != null) { Update( - getString(R.string.commit_hash) != updateCommitHash, + shouldUpdate, foundAsset.browserDownloadUrl, - updateCommitHash, + foundVersion.groupValues[2], found.body, found.nodeId ) } else Update(false, null, null, null, null) } - private val updateLock = Mutex() + return Update(false, null, null, null, null) + } - private suspend fun Activity.downloadUpdate(url: String): Boolean { - try { - Log.d(LOG_TAG, "Downloading update: $url") - val appUpdateName = "CloudStream" - val appUpdateSuffix = "apk" + private suspend fun Activity.getPreReleaseUpdate(): Update { + val tagUrl = "https://api.github.com/repos/$GITHUB_USER_NAME/$GITHUB_REPO/git/ref/tags/pre-release" + val releaseUrl = "https://api.github.com/repos/$GITHUB_USER_NAME/$GITHUB_REPO/releases" + val headers = mapOf("Accept" to "application/vnd.github.v3+json") + val response = parseJson>( + app.get(releaseUrl, headers = headers).text + ) - // Delete all old updates - this.cacheDir.listFiles()?.filter { - it.name.startsWith(appUpdateName) && it.extension == appUpdateSuffix - }?.forEach { deleteFileOnExit(it) } - - val downloadedFile = File.createTempFile(appUpdateName, ".$appUpdateSuffix") - val sink: BufferedSink = downloadedFile.sink().buffer() - - updateLock.withLock { - sink.writeAll(app.get(url).body.source()) - sink.close() - openApk(this, Uri.fromFile(downloadedFile)) - } - - return true - } catch (e: Exception) { - logError(e) - return false - } + val found = response.lastOrNull { rel -> + rel.prerelease || rel.tagName == "pre-release" } - private fun openApk(context: Context, uri: Uri) { - try { - uri.path?.let { - val contentUri = FileProvider.getUriForFile( - context, - BuildConfig.APPLICATION_ID + ".provider", - File(it) - ) - val installIntent = Intent(Intent.ACTION_VIEW).apply { - addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) - addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true) - data = contentUri - } - context.startActivity(installIntent) - } - } catch (e: Exception) { - logError(e) - } - } + val foundAsset = found?.assets?.filter { it -> + it.contentType == "application/vnd.android.package-archive" + }?.getOrNull(0) - /** - * @param checkAutoUpdate if the update check was launched automatically - */ - suspend fun Activity.runAutoUpdate(checkAutoUpdate: Boolean = true): Boolean { - val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) - if (!checkAutoUpdate || settingsManager.getBoolean( - getString(R.string.auto_update_key), - true + return if (foundAsset != null) { + val tagResponse = parseJson(app.get(tagUrl, headers = headers).text) + val updateCommitHash = tagResponse.githubObject.sha.trim().take(7) + Log.d(LOG_TAG, "Fetched GitHub tag: $updateCommitHash") + + Update( + getString(R.string.commit_hash) != updateCommitHash, + foundAsset.browserDownloadUrl, + updateCommitHash, + found.body, + found.nodeId + ) + } else Update(false, null, null, null, null) + } + + private val updateLock = Mutex() + + private suspend fun Activity.downloadUpdate(url: String): Boolean { + try { + Log.d(LOG_TAG, "Downloading update: $url") + val appUpdateName = "CloudStream" + val appUpdateSuffix = "apk" + + // Delete all old updates + this.cacheDir.listFiles()?.filter { + it.name.startsWith(appUpdateName) && it.extension == appUpdateSuffix + }?.forEach { deleteFileOnExit(it) } + + val downloadedFile = File.createTempFile(appUpdateName, ".$appUpdateSuffix") + val sink: BufferedSink = downloadedFile.sink().buffer() + + updateLock.withLock { + sink.writeAll(app.get(url).body.source()) + sink.close() + openApk(this, Uri.fromFile(downloadedFile)) + } + + return true + } catch (e: Exception) { + logError(e) + return false + } + } + + private fun openApk(context: Context, uri: Uri) { + try { + uri.path?.let { + val contentUri = FileProvider.getUriForFile( + context, + BuildConfig.APPLICATION_ID + ".provider", + File(it) ) - ) { - val update = getAppUpdate() - if (update.shouldUpdate && update.updateURL != null) { - // Check if update should be skipped - val updateNodeId = settingsManager.getString( - getString(R.string.skip_update_key), "" - ) + val installIntent = Intent(Intent.ACTION_VIEW).apply { + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true) + data = contentUri + } + context.startActivity(installIntent) + } + } catch (e: Exception) { + logError(e) + } + } - // Skips the update if its an automatic update and the update is skipped - // This allows updating manually - if (update.updateNodeId.equals(updateNodeId) && checkAutoUpdate) { - return false - } + /** + * @param checkAutoUpdate if the update check was launched automatically + */ + suspend fun Activity.runAutoUpdate(checkAutoUpdate: Boolean = true): Boolean { + val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) + if (!checkAutoUpdate || settingsManager.getBoolean( + getString(R.string.auto_update_key), + true + ) + ) { + val update = getAppUpdate() + if (update.shouldUpdate && update.updateURL != null) { + // Check if update should be skipped + val updateNodeId = settingsManager.getString( + getString(R.string.skip_update_key), "" + ) - runOnUiThread { - try { - val currentVersion = packageName?.let { - packageManager.getPackageInfo(it, 0) - } + // Skips the update if its an automatic update and the update is skipped + // This allows updating manually + if (update.updateNodeId.equals(updateNodeId) && checkAutoUpdate) { + return false + } - val builder = AlertDialog.Builder(this, R.style.AlertDialogCustom) - builder.setTitle( - getString(R.string.new_update_format).format( - currentVersion?.versionName, - update.updateVersion - ) + runOnUiThread { + try { + val currentVersion = packageName?.let { + packageManager.getPackageInfo(it, 0) + } + + val builder = AlertDialog.Builder(this, R.style.AlertDialogCustom) + builder.setTitle( + getString(R.string.new_update_format).format( + currentVersion?.versionName, + update.updateVersion ) + ) - val logRegex = Regex("\\[(.*?)\\]\\((.*?)\\)") - val sanitizedChangelog = update.changelog?.replace(logRegex) { matchResult -> - matchResult.groupValues[1] - } // Sanitized because it looks cluttered + val logRegex = Regex("\\[(.*?)\\]\\((.*?)\\)") + val sanitizedChangelog = update.changelog?.replace(logRegex) { matchResult -> + matchResult.groupValues[1] + } // Sanitized because it looks cluttered - builder.setMessage(sanitizedChangelog) - builder.apply { - setPositiveButton(R.string.update) { _, _ -> - // Forcefully start any delayed installations - if (ApkInstaller.delayedInstaller?.startInstallation() == true) return@setPositiveButton + builder.setMessage(sanitizedChangelog) + builder.apply { + setPositiveButton(R.string.update) { _, _ -> + // Forcefully start any delayed installations + if (ApkInstaller.delayedInstaller?.startInstallation() == true) return@setPositiveButton - showToast(R.string.download_started, Toast.LENGTH_LONG) + showToast(R.string.download_started, Toast.LENGTH_LONG) - // Check if the setting hasn't been changed - if ( - settingsManager.getInt( - getString(R.string.apk_installer_key), - -1 - ) == -1 - ) { - // Set to legacy installer if using MIUI - if (isMiUi()) { - settingsManager.edit { - putInt(getString(R.string.apk_installer_key), 1) - } + // Check if the setting hasn't been changed + if ( + settingsManager.getInt( + getString(R.string.apk_installer_key), + -1 + ) == -1 + ) { + // Set to legacy installer if using MIUI + if (isMiUi()) { + settingsManager.edit { + putInt(getString(R.string.apk_installer_key), 1) } } + } - val currentInstaller = settingsManager.getInt( - getString(R.string.apk_installer_key), - 0 - ) + val currentInstaller = settingsManager.getInt( + getString(R.string.apk_installer_key), + 0 + ) - when (currentInstaller) { - // New method - 0 -> { - val intent = PackageInstallerService.Companion.getIntent( - this@runAutoUpdate, - update.updateURL - ) - ContextCompat.startForegroundService(this@runAutoUpdate, intent) - } - // Legacy - 1 -> { - ioSafe { - if (!downloadUpdate(update.updateURL)) { - runOnUiThread { - showToast( - R.string.download_failed, - Toast.LENGTH_LONG - ) - } + when (currentInstaller) { + // New method + 0 -> { + val intent = PackageInstallerService.Companion.getIntent( + this@runAutoUpdate, + update.updateURL + ) + ContextCompat.startForegroundService(this@runAutoUpdate, intent) + } + // Legacy + 1 -> { + ioSafe { + if (!downloadUpdate(update.updateURL)) { + runOnUiThread { + showToast( + R.string.download_failed, + Toast.LENGTH_LONG + ) } } } } } + } - setNegativeButton(R.string.cancel) { _, _ -> } + setNegativeButton(R.string.cancel) { _, _ -> } - if (checkAutoUpdate) { - setNeutralButton(R.string.skip_update) { _, _ -> - settingsManager.edit { - putString( - getString(R.string.skip_update_key), - update.updateNodeId ?: "" - ) - } + if (checkAutoUpdate) { + setNeutralButton(R.string.skip_update) { _, _ -> + settingsManager.edit { + putString( + getString(R.string.skip_update_key), + update.updateNodeId ?: "" + ) } } } - builder.show().setDefaultFocus() - } catch (e: Exception) { - logError(e) } + builder.show().setDefaultFocus() + } catch (e: Exception) { + logError(e) } - return true } - return false + return true } return false } + return false + } - private fun isMiUi(): Boolean { - return !TextUtils.isEmpty(getSystemProperty("ro.miui.ui.version.name")) - } + private fun isMiUi(): Boolean { + return !TextUtils.isEmpty(getSystemProperty("ro.miui.ui.version.name")) + } - private fun getSystemProperty(propName: String): String? { - return try { - val p = Runtime.getRuntime().exec("getprop $propName") - BufferedReader(InputStreamReader(p.inputStream), 1024).use { - it.readLine() - } - } catch (_: IOException) { - null + private fun getSystemProperty(propName: String): String? { + return try { + val p = Runtime.getRuntime().exec("getprop $propName") + BufferedReader(InputStreamReader(p.inputStream), 1024).use { + it.readLine() } + } catch (_: IOException) { + null } } } From eaf2ac07921af26d69285f9127ea6f13fd6d3b54 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 11 Dec 2025 13:04:11 -0700 Subject: [PATCH 195/513] Add some tools:targetApi to styles to appease lint (#2319) Part of my work to fix all error level lint issues, in order to eventually enable `failOnError` and ensure better compatability with older API levels and a more consistent reporting of issues. --- app/src/main/res/values/styles.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 486872657..f0d937ea5 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,4 +1,4 @@ - + + + + + + + From 0d77f7b91ae1bb0f878d425934a63f5481e64af7 Mon Sep 17 00:00:00 2001 From: "recloudstream[bot]" <111277985+recloudstream[bot]@users.noreply.github.com> Date: Sun, 21 Dec 2025 01:27:09 +0000 Subject: [PATCH 227/513] chore(locales): fix locale issues --- app/src/main/res/values-b+af/strings.xml | 2 +- app/src/main/res/values-b+am/strings.xml | 2 +- app/src/main/res/values-b+apc/strings.xml | 2 +- app/src/main/res/values-b+ar/strings.xml | 2 +- app/src/main/res/values-b+ars/strings.xml | 2 +- app/src/main/res/values-b+as/strings.xml | 2 +- app/src/main/res/values-b+az/strings.xml | 2 +- app/src/main/res/values-b+bg/strings.xml | 2 +- app/src/main/res/values-b+bn/strings.xml | 2 +- app/src/main/res/values-b+ckb/strings.xml | 2 +- app/src/main/res/values-b+cs/strings.xml | 2 +- app/src/main/res/values-b+de/strings.xml | 2 +- app/src/main/res/values-b+el/strings.xml | 2 +- app/src/main/res/values-b+eo/strings.xml | 2 +- app/src/main/res/values-b+es/strings.xml | 2 +- app/src/main/res/values-b+fa/strings.xml | 2 +- app/src/main/res/values-b+fil/strings.xml | 2 +- app/src/main/res/values-b+fr/strings.xml | 2 +- app/src/main/res/values-b+gl/strings.xml | 2 +- app/src/main/res/values-b+hi/strings.xml | 2 +- app/src/main/res/values-b+hr/strings.xml | 2 +- app/src/main/res/values-b+hu/strings.xml | 2 +- app/src/main/res/values-b+in/strings.xml | 2 +- app/src/main/res/values-b+it/strings.xml | 2 +- app/src/main/res/values-b+iw/strings.xml | 2 +- app/src/main/res/values-b+ja/strings.xml | 2 +- app/src/main/res/values-b+kn/strings.xml | 2 +- app/src/main/res/values-b+ko/strings.xml | 2 +- app/src/main/res/values-b+lt/strings.xml | 2 +- app/src/main/res/values-b+lv/strings.xml | 2 +- app/src/main/res/values-b+mk/strings.xml | 2 +- app/src/main/res/values-b+ml/strings.xml | 2 +- app/src/main/res/values-b+ms/strings.xml | 2 +- app/src/main/res/values-b+mt/strings.xml | 2 +- app/src/main/res/values-b+my/strings.xml | 2 +- app/src/main/res/values-b+ne/strings.xml | 2 +- app/src/main/res/values-b+nl/strings.xml | 2 +- app/src/main/res/values-b+nn/strings.xml | 2 +- app/src/main/res/values-b+no/strings.xml | 2 +- app/src/main/res/values-b+or/strings.xml | 2 +- app/src/main/res/values-b+pl/strings.xml | 2 +- app/src/main/res/values-b+pt+BR/strings.xml | 2 +- app/src/main/res/values-b+pt/strings.xml | 2 +- app/src/main/res/values-b+qt/strings.xml | 2 +- app/src/main/res/values-b+ro/strings.xml | 2 +- app/src/main/res/values-b+ru/strings.xml | 2 +- app/src/main/res/values-b+sk/strings.xml | 2 +- app/src/main/res/values-b+so/strings.xml | 2 +- app/src/main/res/values-b+sv/strings.xml | 2 +- app/src/main/res/values-b+ta/strings.xml | 2 +- app/src/main/res/values-b+ti/strings.xml | 2 +- app/src/main/res/values-b+tl/strings.xml | 2 +- app/src/main/res/values-b+tr/strings.xml | 2 +- app/src/main/res/values-b+uk/strings.xml | 2 +- app/src/main/res/values-b+ur/strings.xml | 2 +- app/src/main/res/values-b+vi/strings.xml | 2 +- app/src/main/res/values-b+zh+TW/strings.xml | 2 +- app/src/main/res/values-b+zh/strings.xml | 2 +- 58 files changed, 58 insertions(+), 58 deletions(-) diff --git a/app/src/main/res/values-b+af/strings.xml b/app/src/main/res/values-b+af/strings.xml index 9bcfb3f63..71a18f7a5 100644 --- a/app/src/main/res/values-b+af/strings.xml +++ b/app/src/main/res/values-b+af/strings.xml @@ -121,4 +121,4 @@ PIN moet 4 karakters bevat Verkeerde PIN. Probeer weer. Verskaffers - \ No newline at end of file + diff --git a/app/src/main/res/values-b+am/strings.xml b/app/src/main/res/values-b+am/strings.xml index 34b5c3433..26fb84dd3 100644 --- a/app/src/main/res/values-b+am/strings.xml +++ b/app/src/main/res/values-b+am/strings.xml @@ -109,4 +109,4 @@ ዓይነቶችን በመጠቀም ይፈልጉ ቅርጸ-ቁምፊዎችን በ%s ውስጥ በማስቀመጥ ያጫኑ hide_player_control_names_key - \ No newline at end of file + diff --git a/app/src/main/res/values-b+apc/strings.xml b/app/src/main/res/values-b+apc/strings.xml index b911207ad..7d3263652 100644 --- a/app/src/main/res/values-b+apc/strings.xml +++ b/app/src/main/res/values-b+apc/strings.xml @@ -718,4 +718,4 @@ عدّل صورة الملف ادخل لينك ( عنوان ال URL ) تبع صورة الملف تم تعديل الصورة بنجاح - \ No newline at end of file + diff --git a/app/src/main/res/values-b+ar/strings.xml b/app/src/main/res/values-b+ar/strings.xml index c86e91132..ff697d99f 100644 --- a/app/src/main/res/values-b+ar/strings.xml +++ b/app/src/main/res/values-b+ar/strings.xml @@ -765,4 +765,4 @@ اعلى وسط اعلى يمين شاهد المسلسل كاملاً - \ No newline at end of file + diff --git a/app/src/main/res/values-b+ars/strings.xml b/app/src/main/res/values-b+ars/strings.xml index dabedeed1..b8240dc2e 100644 --- a/app/src/main/res/values-b+ars/strings.xml +++ b/app/src/main/res/values-b+ars/strings.xml @@ -346,4 +346,4 @@ عنوان مشغل الفيديو بحد أقصى لعدد الأحرف hide_player_control_names_key DNS عبر HTTPS - \ No newline at end of file + diff --git a/app/src/main/res/values-b+as/strings.xml b/app/src/main/res/values-b+as/strings.xml index fd6c35842..68fc2e163 100644 --- a/app/src/main/res/values-b+as/strings.xml +++ b/app/src/main/res/values-b+as/strings.xml @@ -665,4 +665,4 @@ সংহতিসমূহ/প্ৰদানকাৰী/পছন্দৰ মাধ্যমত টৰেণ্ট সামৰ্থবান কৰক চফ্টৱেৰ ডিকোডিং চফ্টৱেৰ ডিকোডিঙে প্লেয়াৰক আপোনাৰ ফোন দ্বাৰা সমৰ্থিত নোহোৱা ভিডিঅ\' ফাইলসমূহ চলাবলৈ সামৰ্থবান কৰে, কিন্তু উচ্চ ৰিজ\'লিউচনত লেগি বা অস্থিৰ প্লেবেকৰ সৃষ্টি কৰিব পাৰে - \ No newline at end of file + diff --git a/app/src/main/res/values-b+az/strings.xml b/app/src/main/res/values-b+az/strings.xml index 430cd4593..ffbd9d37d 100644 --- a/app/src/main/res/values-b+az/strings.xml +++ b/app/src/main/res/values-b+az/strings.xml @@ -144,4 +144,4 @@ Dəstəklənməyən xəta Gözlənilməyən oynadıcı xətası Ekran yansıtma - \ No newline at end of file + diff --git a/app/src/main/res/values-b+bg/strings.xml b/app/src/main/res/values-b+bg/strings.xml index 4116724d1..9eb439c88 100644 --- a/app/src/main/res/values-b+bg/strings.xml +++ b/app/src/main/res/values-b+bg/strings.xml @@ -703,4 +703,4 @@ Винаги изпращай запитване Задръжте, за да удвоите скоростта Дълго задържане за смяна на скоростта - \ No newline at end of file + diff --git a/app/src/main/res/values-b+bn/strings.xml b/app/src/main/res/values-b+bn/strings.xml index 4208f70f0..f65d673ae 100644 --- a/app/src/main/res/values-b+bn/strings.xml +++ b/app/src/main/res/values-b+bn/strings.xml @@ -352,4 +352,4 @@ প্রস্থান %1$d%2$s hide_player_control_names_key - \ No newline at end of file + diff --git a/app/src/main/res/values-b+ckb/strings.xml b/app/src/main/res/values-b+ckb/strings.xml index c47af36a3..b38a7956c 100644 --- a/app/src/main/res/values-b+ckb/strings.xml +++ b/app/src/main/res/values-b+ckb/strings.xml @@ -83,4 +83,4 @@ کۆپی داخستن سەیڤ - \ No newline at end of file + diff --git a/app/src/main/res/values-b+cs/strings.xml b/app/src/main/res/values-b+cs/strings.xml index 9da634e73..07a37beb8 100644 --- a/app/src/main/res/values-b+cs/strings.xml +++ b/app/src/main/res/values-b+cs/strings.xml @@ -757,4 +757,4 @@ Uprostřed nahoře Vpravo nahoře Přehrát celý seriál - \ No newline at end of file + diff --git a/app/src/main/res/values-b+de/strings.xml b/app/src/main/res/values-b+de/strings.xml index a6cb66b52..08b76d927 100644 --- a/app/src/main/res/values-b+de/strings.xml +++ b/app/src/main/res/values-b+de/strings.xml @@ -729,4 +729,4 @@ Oben links Oben mitte Oben rechts - \ No newline at end of file + diff --git a/app/src/main/res/values-b+el/strings.xml b/app/src/main/res/values-b+el/strings.xml index c5d3e5444..96da7f206 100644 --- a/app/src/main/res/values-b+el/strings.xml +++ b/app/src/main/res/values-b+el/strings.xml @@ -684,4 +684,4 @@ Κάντε όλους τους υπότιτλους πλάγιους Ακτίνα φόντου Σύρετε ξανά προς τα πάνω για να υπερβείτε το 100% - \ No newline at end of file + diff --git a/app/src/main/res/values-b+eo/strings.xml b/app/src/main/res/values-b+eo/strings.xml index 4a23a93da..e3e428075 100644 --- a/app/src/main/res/values-b+eo/strings.xml +++ b/app/src/main/res/values-b+eo/strings.xml @@ -128,4 +128,4 @@ Elŝutante Elŝuto Malsukcesite hide_player_control_names_key - \ No newline at end of file + diff --git a/app/src/main/res/values-b+es/strings.xml b/app/src/main/res/values-b+es/strings.xml index 35343b9ad..c4fcc75dc 100644 --- a/app/src/main/res/values-b+es/strings.xml +++ b/app/src/main/res/values-b+es/strings.xml @@ -722,4 +722,4 @@ Inferior izquierda Inferior central Inferior derecho - \ No newline at end of file + diff --git a/app/src/main/res/values-b+fa/strings.xml b/app/src/main/res/values-b+fa/strings.xml index ae6ffae39..146236651 100644 --- a/app/src/main/res/values-b+fa/strings.xml +++ b/app/src/main/res/values-b+fa/strings.xml @@ -352,4 +352,4 @@ ­همه افزونه ها را تست کنید خودکار رنگ اصلی - \ No newline at end of file + diff --git a/app/src/main/res/values-b+fil/strings.xml b/app/src/main/res/values-b+fil/strings.xml index 7ea370852..f8ba8fa47 100644 --- a/app/src/main/res/values-b+fil/strings.xml +++ b/app/src/main/res/values-b+fil/strings.xml @@ -53,4 +53,4 @@ Itago ang napiling quality ng video sa mga resulta ng paghahanap Pumili ng mode upang i-filter ang pag-download ng mga plugin Awtomatikong i-install ang lahat ng hindi pa naka-install na plugin mula sa mga idinagdag na repository. - \ No newline at end of file + diff --git a/app/src/main/res/values-b+fr/strings.xml b/app/src/main/res/values-b+fr/strings.xml index 3edc7fa88..d8ecc4dae 100644 --- a/app/src/main/res/values-b+fr/strings.xml +++ b/app/src/main/res/values-b+fr/strings.xml @@ -723,4 +723,4 @@ En haut au centre En haut à droite Jouer la série complète - \ No newline at end of file + diff --git a/app/src/main/res/values-b+gl/strings.xml b/app/src/main/res/values-b+gl/strings.xml index a5ad765d0..aeb76080e 100644 --- a/app/src/main/res/values-b+gl/strings.xml +++ b/app/src/main/res/values-b+gl/strings.xml @@ -293,4 +293,4 @@ Redimensionar Omitir introducción Non volver a amosar - \ No newline at end of file + diff --git a/app/src/main/res/values-b+hi/strings.xml b/app/src/main/res/values-b+hi/strings.xml index c0ee55e70..e4eec65f3 100644 --- a/app/src/main/res/values-b+hi/strings.xml +++ b/app/src/main/res/values-b+hi/strings.xml @@ -340,4 +340,4 @@ टीवी में देखे Play mirror" कितना hd है वो वाला लेबल - \ No newline at end of file + diff --git a/app/src/main/res/values-b+hr/strings.xml b/app/src/main/res/values-b+hr/strings.xml index e5ae7752d..902a75500 100644 --- a/app/src/main/res/values-b+hr/strings.xml +++ b/app/src/main/res/values-b+hr/strings.xml @@ -743,4 +743,4 @@ Ukloni gledano do ove epizode Ponovo učitano Usluga ponovnog učitavanja - \ No newline at end of file + diff --git a/app/src/main/res/values-b+hu/strings.xml b/app/src/main/res/values-b+hu/strings.xml index 13210d6dd..1e97719c0 100644 --- a/app/src/main/res/values-b+hu/strings.xml +++ b/app/src/main/res/values-b+hu/strings.xml @@ -592,4 +592,4 @@ Elérhető offline megtekintésre Mindet Kiválaszt Mindent Kijelölés Eltávolítása - \ No newline at end of file + diff --git a/app/src/main/res/values-b+in/strings.xml b/app/src/main/res/values-b+in/strings.xml index 6f57647b8..ca3a39906 100644 --- a/app/src/main/res/values-b+in/strings.xml +++ b/app/src/main/res/values-b+in/strings.xml @@ -753,4 +753,4 @@ Atas tengah Atas kanan Putar Seri Penuh - \ No newline at end of file + diff --git a/app/src/main/res/values-b+it/strings.xml b/app/src/main/res/values-b+it/strings.xml index 331cdf061..56defcbcd 100644 --- a/app/src/main/res/values-b+it/strings.xml +++ b/app/src/main/res/values-b+it/strings.xml @@ -753,4 +753,4 @@ In alto a destra In centro a sinistra Riproduci serie completa - \ No newline at end of file + diff --git a/app/src/main/res/values-b+iw/strings.xml b/app/src/main/res/values-b+iw/strings.xml index 910b1ee0d..558d98a4b 100644 --- a/app/src/main/res/values-b+iw/strings.xml +++ b/app/src/main/res/values-b+iw/strings.xml @@ -560,4 +560,4 @@ הראה המלצות מוסיף אפשרות מהירות בנגן תדירות גיבוי - \ No newline at end of file + diff --git a/app/src/main/res/values-b+ja/strings.xml b/app/src/main/res/values-b+ja/strings.xml index dddecc389..614fe14b9 100644 --- a/app/src/main/res/values-b+ja/strings.xml +++ b/app/src/main/res/values-b+ja/strings.xml @@ -705,4 +705,4 @@ 上中央 右上 全シリーズを再生 - \ No newline at end of file + diff --git a/app/src/main/res/values-b+kn/strings.xml b/app/src/main/res/values-b+kn/strings.xml index fcfaa9045..3a77aeef0 100644 --- a/app/src/main/res/values-b+kn/strings.xml +++ b/app/src/main/res/values-b+kn/strings.xml @@ -130,4 +130,4 @@ ಈಗಿನ ಎಪಿಸೋಡ್ ಮುಗಿದಾಗ ಮುಂದಿನ ಎಪಿಸೋಡ್ ಅನ್ನು ಪ್ರಾರಂಭಿಸಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಸ್ವೈಪ್ ಮಾಡಿ hide_player_control_names_key - \ No newline at end of file + diff --git a/app/src/main/res/values-b+ko/strings.xml b/app/src/main/res/values-b+ko/strings.xml index 77e6ec748..7ab550913 100644 --- a/app/src/main/res/values-b+ko/strings.xml +++ b/app/src/main/res/values-b+ko/strings.xml @@ -659,4 +659,4 @@ %1$d시간 %2$d분 %3$d초 %1$d분 %2$d초 %1$d초 - \ No newline at end of file + diff --git a/app/src/main/res/values-b+lt/strings.xml b/app/src/main/res/values-b+lt/strings.xml index 6493e33e2..357192018 100644 --- a/app/src/main/res/values-b+lt/strings.xml +++ b/app/src/main/res/values-b+lt/strings.xml @@ -255,4 +255,4 @@ Pašalinti iš žiūrimų Garso takelis hide_player_control_names_key - \ No newline at end of file + diff --git a/app/src/main/res/values-b+lv/strings.xml b/app/src/main/res/values-b+lv/strings.xml index 1aae0639c..287d79048 100644 --- a/app/src/main/res/values-b+lv/strings.xml +++ b/app/src/main/res/values-b+lv/strings.xml @@ -590,4 +590,4 @@ Nepareizs URL vai nederīgs attēls Profila attēls veiksmīgi nomainīts Rādīt ieteikumus - \ No newline at end of file + diff --git a/app/src/main/res/values-b+mk/strings.xml b/app/src/main/res/values-b+mk/strings.xml index c70f62fc5..bccc2a00d 100644 --- a/app/src/main/res/values-b+mk/strings.xml +++ b/app/src/main/res/values-b+mk/strings.xml @@ -709,4 +709,4 @@ Горе во центар Горе на десно Пушти ја целата серија - \ No newline at end of file + diff --git a/app/src/main/res/values-b+ml/strings.xml b/app/src/main/res/values-b+ml/strings.xml index fb956d011..dcb9e5270 100644 --- a/app/src/main/res/values-b+ml/strings.xml +++ b/app/src/main/res/values-b+ml/strings.xml @@ -273,4 +273,4 @@ ഔട്ട്ലൈൻ നിറം പശ്ചാത്തല നിറം hide_player_control_names_key - \ No newline at end of file + diff --git a/app/src/main/res/values-b+ms/strings.xml b/app/src/main/res/values-b+ms/strings.xml index 6905abed4..8bbb2a7e0 100644 --- a/app/src/main/res/values-b+ms/strings.xml +++ b/app/src/main/res/values-b+ms/strings.xml @@ -538,4 +538,4 @@ Siaran Langsung Audio Podcast - \ No newline at end of file + diff --git a/app/src/main/res/values-b+mt/strings.xml b/app/src/main/res/values-b+mt/strings.xml index bd605bb37..ca62a043b 100644 --- a/app/src/main/res/values-b+mt/strings.xml +++ b/app/src/main/res/values-b+mt/strings.xml @@ -123,4 +123,4 @@ Neħħi Falla t-tniżżil hide_player_control_names_key - \ No newline at end of file + diff --git a/app/src/main/res/values-b+my/strings.xml b/app/src/main/res/values-b+my/strings.xml index b982e2717..1d35cbaa0 100644 --- a/app/src/main/res/values-b+my/strings.xml +++ b/app/src/main/res/values-b+my/strings.xml @@ -538,4 +538,4 @@ လိုက်ဘရီရွေးချယ်ရန် ဖြင့်ဖွင့်မည် hide_player_control_names_key - \ No newline at end of file + diff --git a/app/src/main/res/values-b+ne/strings.xml b/app/src/main/res/values-b+ne/strings.xml index 4eea78b9c..9345cab2b 100644 --- a/app/src/main/res/values-b+ne/strings.xml +++ b/app/src/main/res/values-b+ne/strings.xml @@ -128,4 +128,4 @@ रिपोजिटरी को नाम र यूआरएल कपी गरियो! hide_player_control_names_key - \ No newline at end of file + diff --git a/app/src/main/res/values-b+nl/strings.xml b/app/src/main/res/values-b+nl/strings.xml index e1078212c..6e0982c79 100644 --- a/app/src/main/res/values-b+nl/strings.xml +++ b/app/src/main/res/values-b+nl/strings.xml @@ -634,4 +634,4 @@ Fout: wordt niet ondersteund Beveiliging Accounts - \ No newline at end of file + diff --git a/app/src/main/res/values-b+nn/strings.xml b/app/src/main/res/values-b+nn/strings.xml index 6989a85da..2cf83c183 100644 --- a/app/src/main/res/values-b+nn/strings.xml +++ b/app/src/main/res/values-b+nn/strings.xml @@ -192,4 +192,4 @@ Fortsett å sjå Prøv tilkopling på nytt… hide_player_control_names_key - \ No newline at end of file + diff --git a/app/src/main/res/values-b+no/strings.xml b/app/src/main/res/values-b+no/strings.xml index eea8a95fa..a981609cf 100644 --- a/app/src/main/res/values-b+no/strings.xml +++ b/app/src/main/res/values-b+no/strings.xml @@ -526,4 +526,4 @@ Hjelp Profilbakgrunn hide_player_control_names_key - \ No newline at end of file + diff --git a/app/src/main/res/values-b+or/strings.xml b/app/src/main/res/values-b+or/strings.xml index 8d0f604fb..807a3bcc6 100644 --- a/app/src/main/res/values-b+or/strings.xml +++ b/app/src/main/res/values-b+or/strings.xml @@ -159,4 +159,4 @@ ଏପିସୋଡ୍ %d ମୁକ୍ତିଲାଭ କରିବ ସିଜିନ୍ %1$d ଏପିସୋଡ୍ %2$d ମୁକ୍ତିଲାଭ କରିବ %1$dଘଣ୍ଟା %2$dମିନିଟ୍ %3$dସେକେଣ୍ଡ - \ No newline at end of file + diff --git a/app/src/main/res/values-b+pl/strings.xml b/app/src/main/res/values-b+pl/strings.xml index 0a234db96..5d67069be 100644 --- a/app/src/main/res/values-b+pl/strings.xml +++ b/app/src/main/res/values-b+pl/strings.xml @@ -734,4 +734,4 @@ Górne środkowe Górne prawe Odtwórz całą serię - \ No newline at end of file + diff --git a/app/src/main/res/values-b+pt+BR/strings.xml b/app/src/main/res/values-b+pt+BR/strings.xml index cb2e4b730..53df149ba 100644 --- a/app/src/main/res/values-b+pt+BR/strings.xml +++ b/app/src/main/res/values-b+pt+BR/strings.xml @@ -745,4 +745,4 @@ Superior direito Assistir à série completa Resolução e nome - \ No newline at end of file + diff --git a/app/src/main/res/values-b+pt/strings.xml b/app/src/main/res/values-b+pt/strings.xml index 31e01661d..a789e9739 100644 --- a/app/src/main/res/values-b+pt/strings.xml +++ b/app/src/main/res/values-b+pt/strings.xml @@ -731,4 +731,4 @@ Centro em cima Direita em cima Reproduzir Série Inteira - \ No newline at end of file + diff --git a/app/src/main/res/values-b+qt/strings.xml b/app/src/main/res/values-b+qt/strings.xml index 258a30df7..3de0f32df 100644 --- a/app/src/main/res/values-b+qt/strings.xml +++ b/app/src/main/res/values-b+qt/strings.xml @@ -654,4 +654,4 @@ Boo Oo-ahh oo-chit ar-ar Boooooo - \ No newline at end of file + diff --git a/app/src/main/res/values-b+ro/strings.xml b/app/src/main/res/values-b+ro/strings.xml index b97397919..642eea0c3 100644 --- a/app/src/main/res/values-b+ro/strings.xml +++ b/app/src/main/res/values-b+ro/strings.xml @@ -656,4 +656,4 @@ Încărcați prima disponibilă Șterge pluginul Închide - \ No newline at end of file + diff --git a/app/src/main/res/values-b+ru/strings.xml b/app/src/main/res/values-b+ru/strings.xml index 7589647f6..a37b0f373 100644 --- a/app/src/main/res/values-b+ru/strings.xml +++ b/app/src/main/res/values-b+ru/strings.xml @@ -719,4 +719,4 @@ Вверху центр Вверху правый Смотреть полностью - \ No newline at end of file + diff --git a/app/src/main/res/values-b+sk/strings.xml b/app/src/main/res/values-b+sk/strings.xml index 1b1cba51b..fb65841f2 100644 --- a/app/src/main/res/values-b+sk/strings.xml +++ b/app/src/main/res/values-b+sk/strings.xml @@ -458,4 +458,4 @@ Podcast Všetko Chyba kódovania - \ No newline at end of file + diff --git a/app/src/main/res/values-b+so/strings.xml b/app/src/main/res/values-b+so/strings.xml index 8366f1eea..fc42c63f7 100644 --- a/app/src/main/res/values-b+so/strings.xml +++ b/app/src/main/res/values-b+so/strings.xml @@ -473,4 +473,4 @@ Bilow isku qasan Qoraalka dhamaadka hide_player_control_names_key - \ No newline at end of file + diff --git a/app/src/main/res/values-b+sv/strings.xml b/app/src/main/res/values-b+sv/strings.xml index 6b62e66a0..dfbfce4b5 100644 --- a/app/src/main/res/values-b+sv/strings.xml +++ b/app/src/main/res/values-b+sv/strings.xml @@ -680,4 +680,4 @@ Betyg%s Uppdatera Plugins Gå till Hämtade filer - \ No newline at end of file + diff --git a/app/src/main/res/values-b+ta/strings.xml b/app/src/main/res/values-b+ta/strings.xml index 368717dfb..94b6f717a 100644 --- a/app/src/main/res/values-b+ta/strings.xml +++ b/app/src/main/res/values-b+ta/strings.xml @@ -677,4 +677,4 @@ %1$d மணி %2$d நிமிடம் %3$d விநாடி %1$d நிமிடம் %2$d விநாடி %1$d விநாடி - \ No newline at end of file + diff --git a/app/src/main/res/values-b+ti/strings.xml b/app/src/main/res/values-b+ti/strings.xml index 99e083351..6c154c8d8 100644 --- a/app/src/main/res/values-b+ti/strings.xml +++ b/app/src/main/res/values-b+ti/strings.xml @@ -4,4 +4,4 @@ ክፋል %d በ ላይ ይወጣል ተዋሳእቲ፡ %s hide_player_control_names_key - \ No newline at end of file + diff --git a/app/src/main/res/values-b+tl/strings.xml b/app/src/main/res/values-b+tl/strings.xml index cf63eceb6..94bb8ea1d 100644 --- a/app/src/main/res/values-b+tl/strings.xml +++ b/app/src/main/res/values-b+tl/strings.xml @@ -258,4 +258,4 @@ Mga setting ng mga subtitle ng Chromecast Maglaro ng Trailer hide_player_control_names_key - \ No newline at end of file + diff --git a/app/src/main/res/values-b+tr/strings.xml b/app/src/main/res/values-b+tr/strings.xml index 1e49ba60a..f6a125b91 100644 --- a/app/src/main/res/values-b+tr/strings.xml +++ b/app/src/main/res/values-b+tr/strings.xml @@ -777,4 +777,4 @@ Sağ üst Altyazı Hizalama Tüm Seriyi Oynat - \ No newline at end of file + diff --git a/app/src/main/res/values-b+uk/strings.xml b/app/src/main/res/values-b+uk/strings.xml index 2cb4e5da5..519e311c3 100644 --- a/app/src/main/res/values-b+uk/strings.xml +++ b/app/src/main/res/values-b+uk/strings.xml @@ -705,4 +705,4 @@ Верхній центр Угорі праворуч Відтворити повну серію - \ No newline at end of file + diff --git a/app/src/main/res/values-b+ur/strings.xml b/app/src/main/res/values-b+ur/strings.xml index 563bf085d..d2c3d9f1c 100644 --- a/app/src/main/res/values-b+ur/strings.xml +++ b/app/src/main/res/values-b+ur/strings.xml @@ -621,4 +621,4 @@ آواز تاریخ %s اپنے اسمارٹ فون یا کمپیوٹر پر یہ %s وزٹ کریں اور مندرجہ بالا کوڈ ڈالیں - \ No newline at end of file + diff --git a/app/src/main/res/values-b+vi/strings.xml b/app/src/main/res/values-b+vi/strings.xml index 8804e0876..aa9caffd1 100644 --- a/app/src/main/res/values-b+vi/strings.xml +++ b/app/src/main/res/values-b+vi/strings.xml @@ -746,4 +746,4 @@ Giữa trái Giữa phải Phát trọn bộ loạt phim - \ No newline at end of file + diff --git a/app/src/main/res/values-b+zh+TW/strings.xml b/app/src/main/res/values-b+zh+TW/strings.xml index 7979c9d95..251df543c 100644 --- a/app/src/main/res/values-b+zh+TW/strings.xml +++ b/app/src/main/res/values-b+zh+TW/strings.xml @@ -703,4 +703,4 @@ 軟體解碼 不接受的種子 載入第一個可用的 - \ No newline at end of file + diff --git a/app/src/main/res/values-b+zh/strings.xml b/app/src/main/res/values-b+zh/strings.xml index 2b149356e..0b893327f 100644 --- a/app/src/main/res/values-b+zh/strings.xml +++ b/app/src/main/res/values-b+zh/strings.xml @@ -777,4 +777,4 @@ 顶部居中 右上 播放全剧 - \ No newline at end of file + From 0593cfbc01c9e3ff7b5bc7f4a6d41adb6aa9367f Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 20 Dec 2025 19:11:54 -0700 Subject: [PATCH 228/513] Add linting to library (#2301) --- build.gradle.kts | 1 + gradle/libs.versions.toml | 1 + library/build.gradle.kts | 1 + library/lint.xml | 6 +++ .../com/lagradost/cloudstream3/MainAPI.kt | 2 +- .../extractors/ContentXExtractor.kt | 6 +-- .../cloudstream3/extractors/DoodExtractor.kt | 29 +++++++-------- .../cloudstream3/extractors/Filegram.kt | 37 +++++++++---------- .../extractors/RapidVidExtractor.kt | 6 +-- .../cloudstream3/extractors/TRsTXExtractor.kt | 9 ++--- .../extractors/VidMoxyExtractor.kt | 6 +-- .../lagradost/cloudstream3/extractors/Vtbe.kt | 28 +++++++------- .../extractors/helper/CryptoJSHelper.kt | 8 ++-- .../cloudstream3/utils/HlsPlaylistParser.kt | 4 +- 14 files changed, 73 insertions(+), 71 deletions(-) create mode 100644 library/lint.xml diff --git a/build.gradle.kts b/build.gradle.kts index defd28515..cca263dd4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,6 @@ plugins { alias(libs.plugins.android.application) apply false + alias(libs.plugins.android.lint) apply false alias(libs.plugins.android.multiplatform.library) apply false alias(libs.plugins.buildkonfig) apply false // Universal build config alias(libs.plugins.dokka) apply false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1d29aab04..24f69824c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -112,6 +112,7 @@ work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "w [plugins] android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } +android-lint = { id = "com.android.lint", version.ref = "androidGradlePlugin" } android-multiplatform-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "androidGradlePlugin" } buildkonfig = { id = "com.codingfeline.buildkonfig", version.ref = "buildkonfigGradlePlugin" } dokka = { id = "org.jetbrains.dokka", version.ref = "dokkaGradlePlugin" } diff --git a/library/build.gradle.kts b/library/build.gradle.kts index 5e2b59098..392552739 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -7,6 +7,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile plugins { id("maven-publish") // Gradle core plugin + alias(libs.plugins.android.lint) alias(libs.plugins.kotlin.multiplatform) alias(libs.plugins.android.multiplatform.library) alias(libs.plugins.buildkonfig) diff --git a/library/lint.xml b/library/lint.xml new file mode 100644 index 000000000..6f4e20222 --- /dev/null +++ b/library/lint.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt index 43f7f4070..ada8d5cd8 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt @@ -2502,7 +2502,7 @@ constructor( fun Episode.addDate(date: String?, format: String = "yyyy-MM-dd") { try { - this.date = SimpleDateFormat(format).parse(date ?: return)?.time + this.date = SimpleDateFormat(format, Locale.getDefault()).parse(date ?: return)?.time } catch (e: Exception) { logError(e) } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt index 06c5ec321..dba2e9267 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/ContentXExtractor.kt @@ -17,12 +17,12 @@ open class ContentX : ExtractorApi() { val iSource = app.get(url, referer=extRef).text val iExtract = Regex("""window\.openPlayer\('([^']+)'""").find(iSource)!!.groups[1]?.value ?: throw ErrorLoadingException("iExtract is null") - val subUrls = mutableSetOf() + val subUrls = mutableSetOf() Regex("""\"file\":\"([^\"]+)\",\"label\":\"([^\"]+)\"""").findAll(iSource).forEach { val (subUrl, subLang) = it.destructured - if (subUrl in subUrls) { return@forEach } - subUrls.add(subUrl) + if (subUrl in subUrls) { return@forEach } + subUrls.add(subUrl) subtitleCallback.invoke( newSubtitleFile( diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/DoodExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/DoodExtractor.kt index 58b6396a8..e1fd47fff 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/DoodExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/DoodExtractor.kt @@ -77,7 +77,7 @@ open class DoodLaExtractor : ExtractorApi() { override var name = "DoodStream" override var mainUrl = "https://dood.la" override val requiresReferer = false - + private val alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" override suspend fun getUrl( @@ -87,18 +87,17 @@ open class DoodLaExtractor : ExtractorApi() { callback: (ExtractorLink) -> Unit ) { val embedUrl = url.replace("/d/", "/e/") - val req = app.get(embedUrl) + val req = app.get(embedUrl) val host = getBaseUrl(req.url) val response0 = req.text - val md5 = host + (Regex("/pass_md5/[^']*").find(response0)?.value ?: return) + val md5 = host + (Regex("/pass_md5/[^']*").find(response0)?.value ?: return) val trueUrl = app.get(md5, referer = req.url).text + createHashTable() + "?token=" + md5.substringAfterLast("/") - - val quality = Regex("\\d{3,4}p") + val quality = Regex("\\d{3,4}p") .find(response0.substringAfter("").substringBefore("")) ?.groupValues ?.getOrNull(0) - - callback.invoke( + + callback.invoke( newExtractorLink( this.name, this.name, @@ -108,19 +107,17 @@ open class DoodLaExtractor : ExtractorApi() { this.quality = getQualityFromName(quality) } ) - } - -private fun createHashTable(): String { - return buildString { - repeat(10) { - append(alphabet.random()) + + private fun createHashTable(): String { + return buildString { + repeat(10) { + append(alphabet.random()) + } } } -} - -private fun getBaseUrl(url: String): String { + private fun getBaseUrl(url: String): String { return URI(url).let { "${it.scheme}://${it.host}" } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Filegram.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Filegram.kt index df7e03373..7baa62710 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Filegram.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Filegram.kt @@ -32,32 +32,29 @@ open class Filegram : ExtractorApi() { "Sec-Fetch-Site" to "same-site", "user-agent" to USER_AGENT, ) - + val doc = app.get(getEmbedUrl(url), referer = referer).document val unpackedJs = unpackJs(doc).toString() - val videoUrl = Regex("""file:\s*"([^"]+\.m3u8[^"]*)"""").find(unpackedJs)?.groupValues?.get(1) + val videoUrl = Regex("""file:\s*"([^"]+\.m3u8[^"]*)"""").find(unpackedJs)?.groupValues?.get(1) if (videoUrl != null) { M3u8Helper.generateM3u8( - this.name, - fixUrl(videoUrl), - "$mainUrl/", - headers = header - ).forEach(callback) + this.name, + fixUrl(videoUrl), + "$mainUrl/", + headers = header + ).forEach(callback) } } - private fun unpackJs(script: Element): String? { - return script.select("script").find { it.data().contains("eval(function(p,a,c,k,e,d)") } - ?.data()?.let { getAndUnpack(it) } - } - - private fun getEmbedUrl(url: String): String { - return if (!url.contains("/embed-")) { - val videoId = url.substringAfter("$mainUrl/") - "$mainUrl/embed-$videoId" - } else { - url - } - } + private fun unpackJs(script: Element): String? { + return script.select("script").find { it.data().contains("eval(function(p,a,c,k,e,d)") } + ?.data()?.let { getAndUnpack(it) } + } + private fun getEmbedUrl(url: String): String { + return if (!url.contains("/embed-")) { + val videoId = url.substringAfter("$mainUrl/") + "$mainUrl/embed-$videoId" + } else url + } } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/RapidVidExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/RapidVidExtractor.kt index bacd658bb..9654e5f38 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/RapidVidExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/RapidVidExtractor.kt @@ -15,12 +15,12 @@ open class RapidVid : ExtractorApi() { val extRef = referer ?: "" val videoReq = app.get(url, referer=extRef).text - val subUrls = mutableSetOf() + val subUrls = mutableSetOf() Regex("""captions\",\"file\":\"([^\"]+)\",\"label\":\"([^\"]+)\"""").findAll(videoReq).forEach { val (subUrl, subLang) = it.destructured - if (subUrl in subUrls) { return@forEach } - subUrls.add(subUrl) + if (subUrl in subUrls) { return@forEach } + subUrls.add(subUrl) subtitleCallback.invoke( newSubtitleFile( diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/TRsTXExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/TRsTXExtractor.kt index c8796896c..1348f74d5 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/TRsTXExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/TRsTXExtractor.kt @@ -29,7 +29,7 @@ open class TRsTX : ExtractorApi() { ) } - val vidLinks = mutableSetOf() + val vidLinks = mutableSetOf() val vidMap = mutableListOf>() for (item in postJson) { if (item.file == null || item.title == null) continue @@ -37,8 +37,8 @@ open class TRsTX : ExtractorApi() { val fileUrl = "${mainUrl}/playlist/" + item.file.substring(1) + ".txt" val videoData = app.post(fileUrl, referer=extRef).text - if (videoData in vidLinks) { continue } - vidLinks.add(videoData) + if (videoData in vidLinks) { continue } + vidLinks.add(videoData) vidMap.add(mapOf( "title" to item.title, @@ -46,12 +46,11 @@ open class TRsTX : ExtractorApi() { )) } - for (mapEntry in vidMap) { val title = mapEntry["title"] ?: continue val m3uLink = mapEntry["videoData"] ?: continue - callback.invoke( + callback.invoke( newExtractorLink( source = this.name, name = "${this.name} - ${title}", diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VidMoxyExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VidMoxyExtractor.kt index e4cb69603..36acf7f7a 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VidMoxyExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VidMoxyExtractor.kt @@ -15,12 +15,12 @@ open class VidMoxy : ExtractorApi() { val extRef = referer ?: "" val videoReq = app.get(url, referer=extRef).text - val subUrls = mutableSetOf() + val subUrls = mutableSetOf() Regex("""captions\",\"file\":\"([^\"]+)\",\"label\":\"([^\"]+)\"""").findAll(videoReq).forEach { val (subUrl, subLang) = it.destructured - if (subUrl in subUrls) { return@forEach } - subUrls.add(subUrl) + if (subUrl in subUrls) { return@forEach } + subUrls.add(subUrl) subtitleCallback.invoke( newSubtitleFile( diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vtbe.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vtbe.kt index 0f078b3bb..37b8ecb23 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vtbe.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vtbe.kt @@ -20,20 +20,20 @@ open class Vtbe : ExtractorApi() { override suspend fun getUrl(url: String, referer: String?): List? { val response = app.get(url,referer=mainUrl).document val extractedpack =response.selectFirst("script:containsData(function(p,a,c,k,e,d))")?.data().toString() - JsUnpacker(extractedpack).unpack()?.let { unPacked -> - Regex("sources:\\[\\{file:\"(.*?)\"").find(unPacked)?.groupValues?.get(1)?.let { link -> - return listOf( - newExtractorLink( - this.name, - this.name, - link, - ) { - this.referer = referer ?: "" - this.quality = Qualities.Unknown.value - } - ) - } + JsUnpacker(extractedpack).unpack()?.let { unPacked -> + Regex("sources:\\[\\{file:\"(.*?)\"").find(unPacked)?.groupValues?.get(1)?.let { link -> + return listOf( + newExtractorLink( + this.name, + this.name, + link, + ) { + this.referer = referer ?: "" + this.quality = Qualities.Unknown.value + } + ) } - return null + } + return null } } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/CryptoJSHelper.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/CryptoJSHelper.kt index a13db65cc..af59b6f7d 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/CryptoJSHelper.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/CryptoJSHelper.kt @@ -1,7 +1,8 @@ package com.lagradost.cloudstream3.extractors.helper +import com.lagradost.cloudstream3.base64DecodeArray +import com.lagradost.cloudstream3.base64Encode import java.util.Arrays -import java.util.Base64 import java.security.MessageDigest import java.security.SecureRandom import javax.crypto.Cipher @@ -51,8 +52,7 @@ object CryptoJS { System.arraycopy(saltBytes, 0, b, sBytes.size, saltBytes.size) System.arraycopy(cipherText, 0, b, sBytes.size + saltBytes.size, cipherText.size) - val bEncode = Base64.getEncoder().encode(b) - return String(bEncode) + return base64Encode(b) } /** @@ -62,7 +62,7 @@ object CryptoJS { * @param cipherText encrypted string */ fun decrypt(password: String, cipherText: String): String { - val ctBytes = Base64.getDecoder().decode(cipherText.toByteArray()) + val ctBytes = base64DecodeArray(cipherText) val saltBytes = Arrays.copyOfRange(ctBytes, 8, 16) val cipherTextBytes = Arrays.copyOfRange(ctBytes, 16, ctBytes.size) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/HlsPlaylistParser.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/HlsPlaylistParser.kt index dbc3c92f6..01e5bb862 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/HlsPlaylistParser.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/HlsPlaylistParser.kt @@ -222,7 +222,7 @@ object HlsPlaylistParser { if (codecs.isNullOrEmpty()) { return arrayOf() } - return split(codecs.trim { it <= ' ' }, "(\\s*,\\s*)") + return split(codecs.trim(), "(\\s*,\\s*)") } fun getCodecsOfType( @@ -928,7 +928,7 @@ object HlsPlaylistParser { fun getMediaMimeType(codecOrNull: String?): String? { var codec = codecOrNull ?: return null - codec = codec.trim { it <= ' ' }.lowercase() + codec = codec.trim().lowercase() if (codec.startsWith("avc1") || codec.startsWith("avc3")) { return MimeTypes.VIDEO_H264 } else if (codec.startsWith("hev1") || codec.startsWith("hvc1")) { From bc68b3d7c69bdf8e203a6303e1734398b2d90524 Mon Sep 17 00:00:00 2001 From: "recloudstream[bot]" <111277985+recloudstream[bot]@users.noreply.github.com> Date: Sun, 21 Dec 2025 02:19:29 +0000 Subject: [PATCH 229/513] chore(locales): fix locale issues --- app/src/main/res/values-b+hi/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-b+hi/strings.xml b/app/src/main/res/values-b+hi/strings.xml index 7fdb37c28..8b7c79650 100644 --- a/app/src/main/res/values-b+hi/strings.xml +++ b/app/src/main/res/values-b+hi/strings.xml @@ -314,7 +314,7 @@ खोज परिणामों में चयनित वीडियो गुणवत्ता छुपाएं प्रकरण - + %1$d-%2$d @string/home_play From be78306c553dabb83ed19c8d02d668aba2b1d03d Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 20 Dec 2025 19:22:07 -0700 Subject: [PATCH 230/513] Minor order fix for lint plugin (#2355) --- library/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/build.gradle.kts b/library/build.gradle.kts index 392552739..e73ed970d 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -7,8 +7,8 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile plugins { id("maven-publish") // Gradle core plugin - alias(libs.plugins.android.lint) alias(libs.plugins.kotlin.multiplatform) + alias(libs.plugins.android.lint) alias(libs.plugins.android.multiplatform.library) alias(libs.plugins.buildkonfig) alias(libs.plugins.dokka) From 6c2228b964a097e0cf558fea638b1a260a3309a7 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 20 Dec 2025 19:48:37 -0700 Subject: [PATCH 231/513] Improve caching system for actions (#2249) --- .github/workflows/build_to_archive.yml | 6 +++++- .github/workflows/generate_dokka.yml | 6 +++++- .github/workflows/prerelease.yml | 6 +++++- .github/workflows/pull_request.yml | 7 ++++++- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build_to_archive.yml b/.github/workflows/build_to_archive.yml index ce920002e..07096014a 100644 --- a/.github/workflows/build_to_archive.yml +++ b/.github/workflows/build_to_archive.yml @@ -40,7 +40,6 @@ jobs: with: distribution: temurin java-version: 17 - cache: gradle - name: Grant execute permission for gradlew run: chmod +x gradlew @@ -56,6 +55,11 @@ jobs: echo "::add-mask::${KEY_PWD}" echo "key_pwd=$KEY_PWD" >> $GITHUB_OUTPUT + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + with: + cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + - name: Run Gradle run: ./gradlew assemblePrerelease env: diff --git a/.github/workflows/generate_dokka.yml b/.github/workflows/generate_dokka.yml index e082b79f4..e3dac3857 100644 --- a/.github/workflows/generate_dokka.yml +++ b/.github/workflows/generate_dokka.yml @@ -45,7 +45,11 @@ jobs: with: distribution: temurin java-version: 17 - cache: gradle + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + with: + cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} - name: Set up Android SDK uses: android-actions/setup-android@v3 diff --git a/.github/workflows/prerelease.yml b/.github/workflows/prerelease.yml index cee9538bd..c7dee13eb 100644 --- a/.github/workflows/prerelease.yml +++ b/.github/workflows/prerelease.yml @@ -31,7 +31,6 @@ jobs: with: distribution: temurin java-version: 17 - cache: gradle - name: Grant execute permission for gradlew run: chmod +x gradlew @@ -47,6 +46,11 @@ jobs: echo "::add-mask::${KEY_PWD}" echo "key_pwd=$KEY_PWD" >> $GITHUB_OUTPUT + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + with: + cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + - name: Run Gradle run: ./gradlew assemblePrerelease build androidSourcesJar makeJar env: diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 381331f0b..090e7a2ec 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -13,11 +13,16 @@ jobs: with: distribution: temurin java-version: 17 - cache: gradle - name: Grant execute permission for gradlew run: chmod +x gradlew + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + with: + cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + cache-read-only: false + - name: Run Gradle run: ./gradlew assemblePrereleaseDebug From 7fd490218039a64251d221fe5ce455de87afc755 Mon Sep 17 00:00:00 2001 From: Hosted Weblate Date: Tue, 23 Dec 2025 20:00:28 +0100 Subject: [PATCH 232/513] Translated using Weblate (Belarusian) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently translated at 33.4% (277 of 828 strings) Translated using Weblate (Arabic (Levantine)) Currently translated at 100.0% (828 of 828 strings) Translated using Weblate (Belarusian) Currently translated at 27.5% (228 of 828 strings) Translated using Weblate (Latvian) Currently translated at 84.9% (703 of 828 strings) Translated using Weblate (Belarusian) Currently translated at 25.4% (211 of 828 strings) Translated using Weblate (Portuguese) Currently translated at 100.0% (828 of 828 strings) Translated using Weblate (Chinese (Simplified Han script)) Currently translated at 100.0% (828 of 828 strings) Translated using Weblate (Belarusian) Currently translated at 23.0% (191 of 828 strings) Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (828 of 828 strings) Translated using Weblate (Italian) Currently translated at 100.0% (828 of 828 strings) Translated using Weblate (Ukrainian) Currently translated at 100.0% (828 of 828 strings) Co-authored-by: Hosted Weblate Co-authored-by: Juan Rubin Co-authored-by: Massimo Pissarello Co-authored-by: Pizza Party Co-authored-by: Sasha Glazko Co-authored-by: soldado-do-wolfenstein Co-authored-by: Максим Горпиніч Co-authored-by: ℂ𝕠𝕠𝕠𝕝 (𝕘𝕚𝕥𝕙𝕦𝕓.𝕔𝕠𝕞/ℂ𝕠𝕠𝕠𝕝) Co-authored-by: 大王叫我来巡山 Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/apc/ Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/be/ Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/it/ Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/lv/ Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt/ Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/pt_BR/ Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/uk/ Translate-URL: https://hosted.weblate.org/projects/cloudstream/app/zh_Hans/ Translation: Cloudstream/App --- app/src/main/res/values-b+apc/strings.xml | 28 +++++- app/src/main/res/values-b+it/strings.xml | 1 + app/src/main/res/values-b+lv/strings.xml | 2 +- app/src/main/res/values-b+pt+BR/strings.xml | 4 + app/src/main/res/values-b+pt/strings.xml | 4 + app/src/main/res/values-b+uk/strings.xml | 1 + app/src/main/res/values-b+zh/strings.xml | 1 + app/src/main/res/values-be/strings.xml | 104 ++++++++++++++++++++ 8 files changed, 142 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-b+apc/strings.xml b/app/src/main/res/values-b+apc/strings.xml index 7d3263652..56e1a7e34 100644 --- a/app/src/main/res/values-b+apc/strings.xml +++ b/app/src/main/res/values-b+apc/strings.xml @@ -75,7 +75,7 @@ تلقائيًا نَزِل كل الإضافات من الريپويات يللي نزادِت. محي بلش - فيه تِلِفونات م فيها تعوز الطريقة الجديدة لتجديد الآپات. جربو \"الطريقة القديمة\" إزا م عم تنزل التجديدات. + فيه أجهزة م فيها تعوز الطريقة الجديدة لتجديد الآپات. جربو \"الطريقة القديمة\" إزا م عم تنزل التجديدات. بعد ما تسكر \"كلود ستريم\"، بكفي الڤيديو بشِباك زغير فوق غير آپ هيدا المصدر م بيدعم \"كروم كاست\" تنبيش منظّم @@ -670,7 +670,7 @@ أفّي اللودينگ تلقائيًا سماح ب إستعمال الـTorrent بال سَتِنگز/المصادر/المحتوى المفضل سكر الآپ و رجاع فتحه، و قبال دعم التورنت ت تكفي. - السوفتوار ديكودينگ بخلي مشغل الڤيديو يمشّي أنواع فيلات ڤيديو م بيدعمها جهازك، بس هال شي معقول يخلي الڤيديو يعلق، خاصتًا إزا كانت الجودة عالية + السوفتوار ديكودينگ بخلي مشغل الڤيديو يمشّي أنواع فيلات ڤيديو م بيدعمها جهازك، بس هال شي معقول يخلي الڤيديو يعلق، خاصتًا إزا كانت الجودة عالية. سوفتوار ديكودينگ رايتينگ (أوطا) نهار اللي نزل (أجدد) @@ -718,4 +718,28 @@ عدّل صورة الملف ادخل لينك ( عنوان ال URL ) تبع صورة الملف تم تعديل الصورة بنجاح + بلّش كل المسلسل + نزل النسخة التجريبية من الآپ + أصلًا عندك النسخة التجريبية. + فشل تنزيل النسخة التجريبية. + ستعمل مصدر بديل" + كتيبة الحلقة + م لقينا الرابط + الرابط أو الصورة مش صالحة + عتبر الحلقات محدورة لحد هون + وقف إعتبار الحلقات محدورة لحد هون + عملنا ري-لوود + عمول ري-لوود للمصدر + اسم + الجودة وال اسم + ميلة الترجمة + تحت، عال شمال + تحت، بال نُص + تحت، عال يمين + نُص، شمال + نُص النُص + نُص، عال يمين + فوق، عال شمال + فوق، بال نُص + فوق، عال يمين diff --git a/app/src/main/res/values-b+it/strings.xml b/app/src/main/res/values-b+it/strings.xml index 4ea21be51..fee5b56f3 100644 --- a/app/src/main/res/values-b+it/strings.xml +++ b/app/src/main/res/values-b+it/strings.xml @@ -756,4 +756,5 @@ Installa la versione pre-release La versione pre-release è già installata. Impossibile installare la versione pre-release. + Testo dell\'episodio diff --git a/app/src/main/res/values-b+lv/strings.xml b/app/src/main/res/values-b+lv/strings.xml index e8fb46baa..444a59a5f 100644 --- a/app/src/main/res/values-b+lv/strings.xml +++ b/app/src/main/res/values-b+lv/strings.xml @@ -85,7 +85,7 @@ Settingi Žanrs Dalities - Atvērt internetā + Atvērt pārlūkā Ieladēts Lādējas Aizvērt diff --git a/app/src/main/res/values-b+pt+BR/strings.xml b/app/src/main/res/values-b+pt+BR/strings.xml index 6a6ba2111..3fbc4fb28 100644 --- a/app/src/main/res/values-b+pt+BR/strings.xml +++ b/app/src/main/res/values-b+pt+BR/strings.xml @@ -745,4 +745,8 @@ Superior direito Assistir à série completa Resolução e nome + Falha ao instalar a versão antecipada. + Versão antecipada instalada. + Instalar versão antecipada + Episódio Text diff --git a/app/src/main/res/values-b+pt/strings.xml b/app/src/main/res/values-b+pt/strings.xml index a789e9739..23b49195f 100644 --- a/app/src/main/res/values-b+pt/strings.xml +++ b/app/src/main/res/values-b+pt/strings.xml @@ -731,4 +731,8 @@ Centro em cima Direita em cima Reproduzir Série Inteira + Instalar versão de pré-lançamento + Versão de pré-lançamento já instalada. + Falha ao instalar pré-lançamento. + Texto do Episódio diff --git a/app/src/main/res/values-b+uk/strings.xml b/app/src/main/res/values-b+uk/strings.xml index f5c9c2c18..54562f263 100644 --- a/app/src/main/res/values-b+uk/strings.xml +++ b/app/src/main/res/values-b+uk/strings.xml @@ -708,4 +708,5 @@ Встановити передрелізну версію Попередня версія вже встановлена. Не вдалося встановити попередню версію. + Текст епізоду diff --git a/app/src/main/res/values-b+zh/strings.xml b/app/src/main/res/values-b+zh/strings.xml index 243b56a47..224041e49 100644 --- a/app/src/main/res/values-b+zh/strings.xml +++ b/app/src/main/res/values-b+zh/strings.xml @@ -780,4 +780,5 @@ 安装预发行版 已安装预发行版。 安装预发行版失败。 + 剧集文本 diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml index a81f30ef7..2111713d6 100644 --- a/app/src/main/res/values-be/strings.xml +++ b/app/src/main/res/values-be/strings.xml @@ -52,4 +52,108 @@ Прайграць фільм Прайграць трэйлер Прайграць трансляцыю + Трансліраваць Torrent + Прайграць серыял поўнасцю + Гэта відэа — Torrent, гэта значыць, што ваша актыўнасць можа быць адсочана.\nУпэўніцеся, што вы ведаеце, як працуюць Torrent-файлы, перад працягам. + Крыніцы + Субцітры + Паспрабаваць перападлучыцца… + Назад + Прайграць серыю + Спампаваць + Спампавана + Ідзе спампоўванне + Спампоўванне прыпынена + Спампоўванне пачалося + Не ўдалося спампаваць + Спампоўванне скасавана + Спампоўванне завершана + Выберыце элементы для выдалення + Спамповак пакуль што няма. + Даступна для прагляду па-за сеткай + Выбраць ўсё + Зняць выбар + Пачалося абнаўленне + Сеткавая трансляцыя + Адкрыць лакальнае відэа + Памылка пры загрузцы спасылак + Спасылкі перазагружаны + Унутранае сховішча + Дуб + Суб + Выдаліць файл + Прайграць файл + Узнавіць спампоўванне + Прыпыніць спампоўванне + Дадатковыя звесткі + Схаваць + Прайграць + Звесткі + Фільтр закладак + Закладкі + Выдаліць + Задаць статус прагляду + Прымяніць + Скапіраваць + Закрыць + Ачысціць + Захаваць + Назва рэпазіторыя і спасылка + скапіравана! + Паведамленне аб новай серыі + Пошук у іншых пашырэннях + Паказваць рэкамендацыі + Хуткасць прайгравальніка + Налады субцітраў + Колер тэксту + Колер контуру + Колер фону + Колер акна + Тып контуру + Уздым субцітраў + Шрыфт + Памер шрыфту + Пошук праз пастаўшчыкоў + Пошук праз тыпы + %d бенена(ў) дадзена распрацоўшчыкам + Бененаў не дадзена + Выбраць мову аўтаматычна + Спампаваць мовы + Мова субцітраў + Утрымайце, каб скінуць + Усталёўвайце шрыфты, перацягваючы іх да %s + Працягнуць прагляд + Выдаліць + Больш інфармацыі + \@string/home_play + Для карэктнай працы гэтага пастаўшчыка можа спатрэбіцца VPN + Гэты пастаўшчык — Torrent, рэкамендуецца VPN + Сайт не пастаўляе метаданых, загрузіць відэа не ўдасца, калі на сайце яго няма. + Апісанне + Сюжэту не знойдзена + Апісання не знойдзена + Паказаць Logcat 🐈 + Журнал + Відарыс у відарысе + Працягвае прайграванне ў мініяцюры зверху іншых праграм + Кнопка змены памеру прайгравальніка + Прыбраць чорныя межы + Субцітры + Налады субцітраў прайгравальніка + Субцітры Chromecast + Налады субцітраў Chromecast + Хуткасць прайгравання + Дадаць параметр хуткасці да прайгравальніка + Чырканне для перамоткі + Правядзіце пальцам з боку ў бок, каб кіраваць пазіцыяй у відэа + Чырканне для змены налад + Правядзіце пальцам уверх або ўніз злева ці справа, каб змяніць яркасць або гучнасць + Аўтаматычнае прайграванне наступнай серыі + Прайграць наступную серыю пасля сканчэння бягучай + Падвойнае націсканне для перамоткі + Падвойнае націсканне для прыпынення + Крок перамоткі (у секундах) + Двойчы націсніце справа ці злева, каб перайсці наперад ці назад + Двойчы націсніце пасярэдзіне, каб прыпыніць прайграванне + Выкарыстоўваць сістэмную яркасць From 063d960c3a0d3c19eef2c38b8b86cf6371c81e68 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Dec 2025 18:57:28 -0700 Subject: [PATCH 233/513] Pin rhino version (#2369) --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 24f69824c..692fd3b4c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -37,7 +37,7 @@ paletteKtx = "1.0.0" preferenceKtx = "1.2.1" previewseekbarMedia3 = "1.1.1.0" qrcodeKotlin = "4.5.0" -rhino = "1.8.1" +rhino = { strictly = "1.8.1" } # Requires minSdk 26 or later beginning at version 1.9.0 safefile = "0.0.8" shimmer = "0.5.0" tmdbJava = "2.13.0" From 3fe6a7853ae08e8df4ccf319e19d87b2d6ba8b01 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Dec 2025 19:07:08 -0700 Subject: [PATCH 234/513] Replace QuickJS with Zipline (#2256) QuickJS was renamed to Zipline all the way back in 2021. Unlike old QuickJS, newer Zipline versions are 16kb aligned. Current Zipline is also compatible back to minSdk 21. --- app/build.gradle.kts | 2 +- gradle/libs.versions.toml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a7536da0d..e8a07b571 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -204,12 +204,12 @@ dependencies { // Extensions & Other Libs implementation(libs.jsoup) // HTML Parser implementation(libs.rhino) // Run JavaScript - implementation(libs.quickjs) implementation(libs.fuzzywuzzy) // Library/Ext Searching with Levenshtein Distance implementation(libs.safefile) // To Prevent the URI File Fu*kery coreLibraryDesugaring(libs.desugar.jdk.libs.nio) // NIO Flavor Needed for NewPipeExtractor implementation(libs.conscrypt.android) // To Fix SSL Fu*kery on Android 9 implementation(libs.jackson.module.kotlin) // JSON Parser + implementation(libs.zipline) // Torrent Support implementation(libs.torrentserver) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 692fd3b4c..f03f2d868 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -45,6 +45,7 @@ torrentserver = "7861970e038b35cd8c6918384e49caf26903e09e" tvprovider = "1.1.0" video = "1.0.0" workRuntimeKtx = "2.10.5" +zipline = "1.24.0" jvmTarget = "1.8" jdkToolchain = "17" @@ -100,7 +101,6 @@ palette-ktx = { module = "androidx.palette:palette-ktx", version.ref = "paletteK preference-ktx = { module = "androidx.preference:preference-ktx", version.ref = "preferenceKtx" } previewseekbar-media3 = { module = "com.github.rubensousa:previewseekbar-media3", version.ref = "previewseekbarMedia3" } qrcode-kotlin = { module = "io.github.g0dkar:qrcode-kotlin", version.ref = "qrcodeKotlin" } -quickjs = { module = "app.cash.quickjs:quickjs-android", version = "0.9.2" } rhino = { module = "org.mozilla:rhino", version.ref = "rhino" } safefile = { module = "com.github.LagradOst:SafeFile", version.ref = "safefile" } shimmer = { module = "com.facebook.shimmer:shimmer", version.ref = "shimmer" } @@ -109,6 +109,7 @@ torrentserver = { module = "com.github.recloudstream:torrentserver", version.ref tvprovider = { module = "androidx.tvprovider:tvprovider", version.ref = "tvprovider" } video = { module = "com.google.android.mediahome:video", version.ref = "video" } work-runtime-ktx = { module = "androidx.work:work-runtime-ktx", version.ref = "workRuntimeKtx" } +zipline = { module = "app.cash.zipline:zipline-android", version.ref = "zipline" } [plugins] android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } From 81d9ecde674e23ad2d53b335230369aedaea4a51 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Dec 2025 19:21:59 -0700 Subject: [PATCH 235/513] Move untranslatable strings to seperate file (#2273) This could cause crashes or poisoned data on some languages as some untranslatable strings were being translated, including keys and format strings that shouldn't be translatable. Also when translating the episodes key on weblate it caused a conflict between the plural version (which weblate does support) and the actual episodes key, meaning the episodes key was translating as the singular version of the plural episodes version in some cases. Moving to a separate resource file should hopefully prevent these issues. --- app/src/main/res/values-b+af/strings.xml | 1 - app/src/main/res/values-b+am/strings.xml | 1 - app/src/main/res/values-b+apc/strings.xml | 3 - app/src/main/res/values-b+ar/strings.xml | 22 --- app/src/main/res/values-b+ars/strings.xml | 1 - app/src/main/res/values-b+as/strings.xml | 1 - app/src/main/res/values-b+bg/strings.xml | 3 - app/src/main/res/values-b+bn/strings.xml | 2 - app/src/main/res/values-b+cs/strings.xml | 12 -- app/src/main/res/values-b+de/strings.xml | 1 - app/src/main/res/values-b+el/strings.xml | 1 - app/src/main/res/values-b+eo/strings.xml | 1 - app/src/main/res/values-b+es/array.xml | 44 ----- app/src/main/res/values-b+es/strings.xml | 3 - app/src/main/res/values-b+fa/strings.xml | 1 - app/src/main/res/values-b+fil/strings.xml | 1 - app/src/main/res/values-b+fr/strings.xml | 1 - app/src/main/res/values-b+gl/strings.xml | 5 - app/src/main/res/values-b+hi/strings.xml | 5 - app/src/main/res/values-b+hr/strings.xml | 13 -- app/src/main/res/values-b+hu/strings.xml | 1 - app/src/main/res/values-b+in/strings.xml | 10 -- app/src/main/res/values-b+it/strings.xml | 1 - app/src/main/res/values-b+iw/strings.xml | 1 - app/src/main/res/values-b+ja/strings.xml | 1 - app/src/main/res/values-b+kn/strings.xml | 1 - app/src/main/res/values-b+ko/strings.xml | 1 - app/src/main/res/values-b+lt/strings.xml | 1 - app/src/main/res/values-b+lv/strings.xml | 1 - app/src/main/res/values-b+mk/strings.xml | 1 - app/src/main/res/values-b+ml/strings.xml | 1 - app/src/main/res/values-b+ms/strings.xml | 4 - app/src/main/res/values-b+mt/strings.xml | 1 - app/src/main/res/values-b+my/strings.xml | 1 - app/src/main/res/values-b+ne/strings.xml | 1 - app/src/main/res/values-b+nl/strings.xml | 9 -- app/src/main/res/values-b+nn/strings.xml | 1 - app/src/main/res/values-b+no/strings.xml | 3 - app/src/main/res/values-b+or/strings.xml | 1 - app/src/main/res/values-b+pl/array.xml | 44 ----- app/src/main/res/values-b+pl/strings.xml | 1 - app/src/main/res/values-b+pt+BR/strings.xml | 10 -- app/src/main/res/values-b+pt/strings.xml | 1 - app/src/main/res/values-b+qt/strings.xml | 1 - app/src/main/res/values-b+ro/strings.xml | 2 - app/src/main/res/values-b+ru/strings.xml | 3 - app/src/main/res/values-b+sk/strings.xml | 1 - app/src/main/res/values-b+so/strings.xml | 1 - app/src/main/res/values-b+sv/strings.xml | 3 - app/src/main/res/values-b+ta/strings.xml | 1 - app/src/main/res/values-b+ti/strings.xml | 1 - app/src/main/res/values-b+tl/strings.xml | 1 - app/src/main/res/values-b+tr/array.xml | 44 ----- app/src/main/res/values-b+tr/strings.xml | 35 ---- app/src/main/res/values-b+uk/strings.xml | 3 - app/src/main/res/values-b+ur/strings.xml | 1 - app/src/main/res/values-b+vi/array.xml | 44 ----- app/src/main/res/values-b+vi/strings.xml | 1 - app/src/main/res/values-b+zh+TW/strings.xml | 35 ---- app/src/main/res/values-b+zh/strings.xml | 33 ---- .../res/values/donottranslate-strings.xml | 152 ++++++++++++++++++ app/src/main/res/values/strings.xml | 152 +----------------- 62 files changed, 153 insertions(+), 580 deletions(-) create mode 100644 app/src/main/res/values/donottranslate-strings.xml diff --git a/app/src/main/res/values-b+af/strings.xml b/app/src/main/res/values-b+af/strings.xml index 71a18f7a5..81d7a96ae 100644 --- a/app/src/main/res/values-b+af/strings.xml +++ b/app/src/main/res/values-b+af/strings.xml @@ -105,7 +105,6 @@ Voer lettertipes in deur dit in %s te plaas Rolverdeling: %s Nuwe episode notifikasie - hide_player_control_names_key Gratis Gebruik Wis Uit diff --git a/app/src/main/res/values-b+am/strings.xml b/app/src/main/res/values-b+am/strings.xml index 26fb84dd3..7fd3274b9 100644 --- a/app/src/main/res/values-b+am/strings.xml +++ b/app/src/main/res/values-b+am/strings.xml @@ -108,5 +108,4 @@ ተጨማሪ መረጃ ዓይነቶችን በመጠቀም ይፈልጉ ቅርጸ-ቁምፊዎችን በ%s ውስጥ በማስቀመጥ ያጫኑ - hide_player_control_names_key diff --git a/app/src/main/res/values-b+apc/strings.xml b/app/src/main/res/values-b+apc/strings.xml index 56e1a7e34..9bc697acf 100644 --- a/app/src/main/res/values-b+apc/strings.xml +++ b/app/src/main/res/values-b+apc/strings.xml @@ -573,8 +573,6 @@ حطو الأرقام السرية الحالية صوت حط كبسة لبرم إتجاه الشاشة - rotate_video_key - auto_rotate_video_key برم الشاشة أوتوماتيكيًا برومو غير إتجاه الشاشة أوتوماتيكيًا حسب شكل الڤيديو @@ -625,7 +623,6 @@ تجاهل فتاح الريپو فتاح %s ع تلفونك أو كمپيوترك، وحط الكود اللي فوق - hide_player_control_names_key بلشه من الأول تحذير فتاح الڤيديو اللي ع جهازك diff --git a/app/src/main/res/values-b+ar/strings.xml b/app/src/main/res/values-b+ar/strings.xml index ff697d99f..487b29d84 100644 --- a/app/src/main/res/values-b+ar/strings.xml +++ b/app/src/main/res/values-b+ar/strings.xml @@ -235,10 +235,6 @@ ملصق مدبلج ملصق مترجم العنوان - show_hd_key - show_dub_key - show_sub_key - show_title_key التحكم في عناصر الواجهة على الملصق لم يتم العثور على تحديثات تحقق من التحديثات @@ -270,8 +266,6 @@ امتداد تكبير إخلاء مسؤولية - legal_notice_key - Any legal issues regarding the content on this application should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. In case of copyright infringement, please directly contact the responsible parties or the streaming websites. The app is purely for educational and personal use. CloudStream 3 does not host any content on the app, and has no control over what media is put up or taken down. CloudStream 3 functions like any other search engine, such as Google. CloudStream 3 does not host, upload or manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient, user-friendly interface. It merely scrapes 3rd-party websites that are publicly accessable via any regular web browser. It is the responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use CloudStream 3 at your own risk. عام زر العشوائي إظهار زر عشوائي على الصفحة الرئيسية والمكتبة @@ -291,10 +285,6 @@ مكان عنوان الملصق وضع العنوان تحت الملصق - anilist_key - mal_key - opensubtitles_key - nginx_key كلمة المرور إسم المستخدم البريد الإلكتروني @@ -302,14 +292,6 @@ إسم الموقع الجديد رابط الموقع مثلا : https://example.com اللغة (الإنجليزية) - %1$s %2$s حساب تسجيل الخروج @@ -332,7 +314,6 @@ الكل الحد الاقصي الحد الأدنى - @string/none الخطوط المحيطة النمط المنخفض ظل @@ -602,8 +583,6 @@ تعديل الحساب تم إعادة تحميل الروابط عرض زر تبديل لاتجاه الشاشة - تدوير الفيديو - مفتاح تدوير الفيديو التلقائي الدوران التلقائي تدوير تمكين التبديل التلقائي لاتجاه الشاشة بناءً على اتجاه الفيديو @@ -652,7 +631,6 @@ قم بزيارة %s على هاتفك الذكي أو جهاز الكمبيوتر وأدخل الرمز أعلاه لا يمكن الحصول على رمز PIN للجهاز، حاول المصادقة المحلية تنتهي صلاحية الرمز خلال %1$dm %2$ds - hide_player_control_names_key تشغيل من البداية فتح فيديو محلي تحذير diff --git a/app/src/main/res/values-b+ars/strings.xml b/app/src/main/res/values-b+ars/strings.xml index b8240dc2e..3104e6a9a 100644 --- a/app/src/main/res/values-b+ars/strings.xml +++ b/app/src/main/res/values-b+ars/strings.xml @@ -344,6 +344,5 @@ وثائقي موقع عنوان مشغل الفيديو بحد أقصى لعدد الأحرف - hide_player_control_names_key DNS عبر HTTPS diff --git a/app/src/main/res/values-b+as/strings.xml b/app/src/main/res/values-b+as/strings.xml index 68fc2e163..eb6ad4aa4 100644 --- a/app/src/main/res/values-b+as/strings.xml +++ b/app/src/main/res/values-b+as/strings.xml @@ -607,7 +607,6 @@ চাবটাইটলসমূহ এপিচ\'ড প্লে কৰক প্ৰয়োগ কৰক - hide_player_control_names_key ফাইলসমূহ ডিলিট কৰক ডিলিট (%1$d | %2$s) আপুনি স্থায়ীভাৱে তলত দিয়া আইটেমসমূহ ডিলিট কৰিবলৈ নিশ্চিত নেকি? diff --git a/app/src/main/res/values-b+bg/strings.xml b/app/src/main/res/values-b+bg/strings.xml index 9eb439c88..2c238b968 100644 --- a/app/src/main/res/values-b+bg/strings.xml +++ b/app/src/main/res/values-b+bg/strings.xml @@ -296,8 +296,6 @@ НовоИмеНаСайт example.com Езиков код (en) - %1$s %2$s Акаунт Излизане @@ -588,7 +586,6 @@ Покажи предложения Добавя опция за промяна на скоростта в плеъра Този тест е направен за програмисти и не проверява работата на никакви добавки. - hide_player_control_names_key Предстоящо в %s Име на хранилището и URL адрес копирани! diff --git a/app/src/main/res/values-b+bn/strings.xml b/app/src/main/res/values-b+bn/strings.xml index f65d673ae..2e37f43f3 100644 --- a/app/src/main/res/values-b+bn/strings.xml +++ b/app/src/main/res/values-b+bn/strings.xml @@ -238,7 +238,6 @@ অ্যান্ড্রয়েড টিভির মতো, কম মেমরির ডিভাইসে খুব বেশি সেট করা হলে সমস্যা করবে। ক্লোন সাইট প্লেয়ারের ফিচার - MAL AniList TMDB IMDB Kitsu Trakt %1$s%2$s অ্যাপ থিম রিকমেন্ডেশনগুলো দেখাও প্লেয়ারে গতির বিকল্প যোগ কর @@ -351,5 +350,4 @@ অ্যাকাউন্ট প্রস্থান %1$d%2$s - hide_player_control_names_key diff --git a/app/src/main/res/values-b+cs/strings.xml b/app/src/main/res/values-b+cs/strings.xml index c42cb4c18..e553ccd73 100644 --- a/app/src/main/res/values-b+cs/strings.xml +++ b/app/src/main/res/values-b+cs/strings.xml @@ -253,7 +253,6 @@ Roztáhnout Přiblížit Odmítnutí odpovědnosti - Jakékoli právní otázky týkající se obsahu této aplikace je třeba řešit se samotnými hostiteli a poskytovateli souborů, protože s nimi nejsme nijak spojeni. V případě porušení autorských práv se obraťte přímo na odpovědné strany nebo na webové stránky, na kterých se streamování odehrává. Aplikace je určena výhradně pro vzdělávací a osobní účely. CloudStream 3 v aplikaci nehostuje žádný obsah a nemá žádnou kontrolu nad tím, jaká média jsou v aplikaci umístěna nebo odstraněna. CloudStream 3 funguje jako jakýkoli jiný vyhledávač, například Google. Služba CloudStream 3 nehostuje, nenahrává ani nespravuje žádná videa, filmy ani obsah. Pouze vyhledává, agreguje a zobrazuje odkazy v pohodlném, uživatelsky přívětivém rozhraní. Pouze shromažďuje webové stránky třetích stran, které jsou veřejně přístupné prostřednictvím jakéhokoli běžného webového prohlížeče. Je odpovědností uživatele, aby se vyvaroval jakýchkoli akcí, které by mohly porušovat zákony platné v jeho lokalitě. Použijte CloudStream 3 na vlastní nebezpečí. Obecné Náhodné tlačítko Zobrazit na domovské stránce a v knihovně náhodné tlačítko @@ -275,14 +274,6 @@ Uživatelské jméno ahoj@svete.cz 127.0.0.1 - %1$s %2$s účet Odhlásit se @@ -594,8 +585,6 @@ Upravit účet Odkazy znovu načteny Zobrazit tlačítko pro přepnutí otočení obrazovky - rotate_video_key - auto_rotate_video_key Automatické otáčení Otočení Zapnout automatické otáčení obrazovky v závislosti na orientaci videa @@ -644,7 +633,6 @@ Účty Lokální ověření PIN kód vypršel! - hide_player_control_names_key Přehrát od začátku Aktuálně neprobíhají žádná stahování. Otevřít místní video diff --git a/app/src/main/res/values-b+de/strings.xml b/app/src/main/res/values-b+de/strings.xml index eb5734ca1..67cf55fd7 100644 --- a/app/src/main/res/values-b+de/strings.xml +++ b/app/src/main/res/values-b+de/strings.xml @@ -602,7 +602,6 @@ Zurücksetzen Akkuverbrauch der App ist bereits auf unbeschränkt eingestellt CloudStreams App-Info kann nicht geöffnet werden. - hide_player_control_names_key Staffel %1$d Episode %2$d wird veröffentlicht in Wird veröffentlicht in %s Sicherheit diff --git a/app/src/main/res/values-b+el/strings.xml b/app/src/main/res/values-b+el/strings.xml index 96da7f206..4b671644b 100644 --- a/app/src/main/res/values-b+el/strings.xml +++ b/app/src/main/res/values-b+el/strings.xml @@ -611,7 +611,6 @@ Τα δεδομένα σας στο CloudStream έχουν κάνει back up. Αν και η πιθανότητα είναι πολύ χαμηλή, όλες οι συσκευές συμπεριφέρονται διαφορετικά. Στη σπάνια περίπτωση, που απαγορευτεί η πρόσβασή σας από την εφαρμογή, διαγράψτε τα δεδομένα εφαρμογής και επαναφέρετέ τα από ένα ήδη υπάρχον backup. Συγνώμη για οποιαδήποτε ταλαιπωρία. Λογαριασμοί Ασφάλεια - hide_player_control_names_key Απόρριψη Ενσωματωμένο Συνδεμένοι diff --git a/app/src/main/res/values-b+eo/strings.xml b/app/src/main/res/values-b+eo/strings.xml index e3e428075..f957da076 100644 --- a/app/src/main/res/values-b+eo/strings.xml +++ b/app/src/main/res/values-b+eo/strings.xml @@ -127,5 +127,4 @@ Elŝutite Elŝutante Elŝuto Malsukcesite - hide_player_control_names_key diff --git a/app/src/main/res/values-b+es/array.xml b/app/src/main/res/values-b+es/array.xml index 376519bf3..1a7ca4608 100644 --- a/app/src/main/res/values-b+es/array.xml +++ b/app/src/main/res/values-b+es/array.xml @@ -290,48 +290,4 @@ Vietnamita (VISCII) Vietnamita (Windows-1258) - - - UTF-8 - UTF-16 - UTF-16BE - UTF-16LE - GB18030 - ISO-8859-15 - Windows-1252 - IBM850 - ISO-8859-2 - Windows-1250 - ISO-8859-3 - ISO-8859-10 - Windows-1251 - KOI8-R - KOI8-U - ISO-8859-6 - Windows-1256 - ISO-8859-7 - Windows-1253 - ISO-8859-8 - Windows-1255 - ISO-8859-9 - Windows-1254 - ISO-8859-11 - Windows-874 - ISO-8859-13 - Windows-1257 - ISO-8859-14 - ISO-8859-16 - ISO-2022-CN-EXT - EUC-CN - ISO-2022-JP-2 - EUC-JP - Shift_JIS - CP949 - ISO-2022-KR - Big5 - ISO-2022-TW - Big5-HKSCS - VISCII - Windows-1258 - diff --git a/app/src/main/res/values-b+es/strings.xml b/app/src/main/res/values-b+es/strings.xml index 8cd37933b..390c2df58 100644 --- a/app/src/main/res/values-b+es/strings.xml +++ b/app/src/main/res/values-b+es/strings.xml @@ -567,8 +567,6 @@ Editar la cuenta Enlaces recargados Mostrar un botón para cambiar la orientación de la pantalla - rotate_video_key - auto_rotate_video_key Giro automático Girar Activar el cambio automático de la orientación de la pantalla en función de la orientación del vídeo @@ -617,7 +615,6 @@ ¡El código PIN ya ha caducado! El código caduca en %1$d mín y %2$d s No puedo obtener el código PIN del dispositivo; intente con la autenticación local - hide_player_control_names_key Reproducir desde el principio Abrir vídeo de forma local Advertencia diff --git a/app/src/main/res/values-b+fa/strings.xml b/app/src/main/res/values-b+fa/strings.xml index 146236651..da6f04d8e 100644 --- a/app/src/main/res/values-b+fa/strings.xml +++ b/app/src/main/res/values-b+fa/strings.xml @@ -190,7 +190,6 @@ پیش‌فرض کارتون تورنت - hide_player_control_names_key این ارائه‌دهنده تورنتی است، استفاده از VPN توصیه می‌شود بارگزاری پرونده پشتیبانی‌ ارتفاع زیرنویس diff --git a/app/src/main/res/values-b+fil/strings.xml b/app/src/main/res/values-b+fil/strings.xml index f8ba8fa47..d4844d1d7 100644 --- a/app/src/main/res/values-b+fil/strings.xml +++ b/app/src/main/res/values-b+fil/strings.xml @@ -1,6 +1,5 @@ - hide_player_control_names_key Maling PIN. Pakisubukang muli. Alisin ang napanood hanggang sa episode na ito Walang koneksyon sa internet.\n\nKumonekta sa internet at subukang muli, o panoorin ang iyong mga na-download habang ikaw ay offline. diff --git a/app/src/main/res/values-b+fr/strings.xml b/app/src/main/res/values-b+fr/strings.xml index d8ecc4dae..a4e669ccf 100644 --- a/app/src/main/res/values-b+fr/strings.xml +++ b/app/src/main/res/values-b+fr/strings.xml @@ -606,7 +606,6 @@ Verrouillage biométrique Sélectionnez un appareil de diffusion Saison %1$d Episode %2$d sera publié dans - hide_player_control_names_key Regarder depuis le début Ouvrir une vidéo locale Attention diff --git a/app/src/main/res/values-b+gl/strings.xml b/app/src/main/res/values-b+gl/strings.xml index aeb76080e..1b8f068e3 100644 --- a/app/src/main/res/values-b+gl/strings.xml +++ b/app/src/main/res/values-b+gl/strings.xml @@ -161,7 +161,6 @@ Selecciona o modo para filtrar a descarga dos complementos Instala automáticamente todos os complementos aínda non instalados dos repositorios engadidos. Mostrar actualizacións da aplicación - hide_player_control_names_key Reiniciar aos valores predefinidos -30 Audiolibro @@ -274,10 +273,6 @@ Ligazón copiada ó portapapeis Reproducir capítulo Temporada - - Capítulos - - %1$d-%2$d %1$d %2$s T diff --git a/app/src/main/res/values-b+hi/strings.xml b/app/src/main/res/values-b+hi/strings.xml index 8b7c79650..2c5247238 100644 --- a/app/src/main/res/values-b+hi/strings.xml +++ b/app/src/main/res/values-b+hi/strings.xml @@ -202,7 +202,6 @@ रूपरेखा रंग उपशीर्षक ऊंचाई मुद्रलिपि - hide_player_control_names_key वर्तमान में कोई डाउनलोड नहीं है। आरम्भ से शुरू करें मिटाने के लिए वस्तु चुनें @@ -312,10 +311,6 @@ लाइब्रेरी मीडिया खोज परिणामों में चयनित वीडियो गुणवत्ता छुपाएं - - प्रकरण - - %1$d-%2$d @string/home_play प्लेयर में आगे पीछे जाने का समय (सेकंड्स) diff --git a/app/src/main/res/values-b+hr/strings.xml b/app/src/main/res/values-b+hr/strings.xml index 902a75500..1e2c344ab 100644 --- a/app/src/main/res/values-b+hr/strings.xml +++ b/app/src/main/res/values-b+hr/strings.xml @@ -1,15 +1,6 @@ - %d %s | %s - %s • %s - %s / %s - %s %s - +%d - -%d - %d - %d - %d %1$s epizoda %2$d Glumačka postava: %s Epizoda %d će izaći za @@ -285,7 +276,6 @@ Rastegni Zoom Pravna obavijest - Any legal issues regarding the content on this application should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. In case of copyright infringement, please directly contact the responsible parties or the streaming websites. The app is purely for educational and personal use. CloudStream 3 does not host any content on the app, and has no control over what media is put up or taken down. CloudStream 3 functions like any other search engine, such as Google. CloudStream 3 does not host, upload or manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient, user-friendly interface. It merely scrapes 3rd-party websites that are publicly accessable via any regular web browser. It is the responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use CloudStream 3 at your own risk. Općenito Gumb za slučajni odabir Prikaži gumb za slučajni odabir na početnoj stranici i biblioteci @@ -597,8 +587,6 @@ Prikaži gumb za prebacivanje orijentacije zaslona Omogućuje automatsko mijenjanje orijentacije zaslona na temelju orijentacije videa Automatsko rotiranje - rotiraj_video_tipka - automatski_rotiraj_video_tipka Obavijest za novu epizodu Traži u drugim proširenjima Dodaje opciju za brzinu u playeru @@ -636,7 +624,6 @@ CloudStream Wiki Računi Sigurnost - hide_player_control_names_key Lokalna autentifikacija Otvori lokalni video Posjeti %s na svom mobitelu ili računalu i unesi gore navedeni kod diff --git a/app/src/main/res/values-b+hu/strings.xml b/app/src/main/res/values-b+hu/strings.xml index 1e97719c0..ae018207b 100644 --- a/app/src/main/res/values-b+hu/strings.xml +++ b/app/src/main/res/values-b+hu/strings.xml @@ -579,7 +579,6 @@ A PIN 4 karakter hosszú kell legyen Auto elforgatás Az automatikus videó orientáció alapján való képernyő elforgatás bekapcsolása - hide_player_control_names_key Helyi videó megnyitása Tárhely név és URL Ez a videó egy Torrent, ami azt jelenti, hogy a videótevékenységed nyomon követhető.\nGyőződj meg róla, hogy megérted a torrentezés működését, mielőtt folytatnád. diff --git a/app/src/main/res/values-b+in/strings.xml b/app/src/main/res/values-b+in/strings.xml index ca3a39906..17b4f075d 100644 --- a/app/src/main/res/values-b+in/strings.xml +++ b/app/src/main/res/values-b+in/strings.xml @@ -250,7 +250,6 @@ Regang Zoom Disclaimer - Any legal issues regarding the content on this application should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. In case of copyright infringement, please directly contact the responsible parties or the streaming websites. The app is purely for educational and personal use. CloudStream 3 does not host any content on the app, and has no control over what media is put up or taken down. CloudStream 3 functions like any other search engine, such as Google. CloudStream 3 does not host, upload or manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient, user-friendly interface. It merely scrapes 3rd-party websites that are publicly accessable via any regular web browser. It is the responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use CloudStream 3 at your own risk. Umum Tombol Acak Tampilkan tombol acak di Beranda dan Pustaka @@ -267,14 +266,6 @@ Lokasi judul poster Meletakkan judul di bawah poster - %1$s %2$s akun Keluar @@ -632,7 +623,6 @@ CloudStream Wiki Keamanan Akun - hide_player_control_names_key Hati hati Kode PIN kini telah kedaluwarsa! Gambar Kode QR diff --git a/app/src/main/res/values-b+it/strings.xml b/app/src/main/res/values-b+it/strings.xml index fee5b56f3..3962f5d23 100644 --- a/app/src/main/res/values-b+it/strings.xml +++ b/app/src/main/res/values-b+it/strings.xml @@ -640,7 +640,6 @@ Impossibile ottenere il codice PIN del dispositivo, prova l\'autenticazione locale Il codice PIN è scaduto! Il codice scadrà tra %1$dm %2$ds - hide_player_control_names_key Apri il video locale Al momento non ci sono download. Riproduci dall\'inizio diff --git a/app/src/main/res/values-b+iw/strings.xml b/app/src/main/res/values-b+iw/strings.xml index 558d98a4b..ef4cb9202 100644 --- a/app/src/main/res/values-b+iw/strings.xml +++ b/app/src/main/res/values-b+iw/strings.xml @@ -537,7 +537,6 @@ \nיגרמו לעדיפות הסרטון להיות 10. \n \nשימו לב: אם הסכום הוא 10 או יותר, הנגן ידלג על טעינת הסרטון כאשר הלינק נטען! - hide_player_control_names_key עונה %1$d פרק %2$d תשודר ב: %1$d שעות %2$d דקות %3$d שניות %1$d דקות %2$d שניות diff --git a/app/src/main/res/values-b+ja/strings.xml b/app/src/main/res/values-b+ja/strings.xml index df0559ef7..e246c6f27 100644 --- a/app/src/main/res/values-b+ja/strings.xml +++ b/app/src/main/res/values-b+ja/strings.xml @@ -234,7 +234,6 @@ 現在のエピソードが終了したら次のエピソードを開始する 長押しするとデフォルトにリセットされます ダウンロードを再開 - hide_player_control_names_key ブックマークのフィルタ プロットが見つかりません ダブルタップで一時停止 diff --git a/app/src/main/res/values-b+kn/strings.xml b/app/src/main/res/values-b+kn/strings.xml index 3a77aeef0..22a45b906 100644 --- a/app/src/main/res/values-b+kn/strings.xml +++ b/app/src/main/res/values-b+kn/strings.xml @@ -129,5 +129,4 @@ Brightness ಅಥವಾ volume ಬದಲಾಯಿಸಲು ಎಡ ಅಥವಾ ಬಲಭಾಗದಲ್ಲಿ ಮೇಲಕ್ಕೆ ಅಥವಾ ಕೆಳಕ್ಕೆ ಸ್ಲೈಡ್ ಮಾಡಿ ಈಗಿನ ಎಪಿಸೋಡ್ ಮುಗಿದಾಗ ಮುಂದಿನ ಎಪಿಸೋಡ್ ಅನ್ನು ಪ್ರಾರಂಭಿಸಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಸ್ವೈಪ್ ಮಾಡಿ - hide_player_control_names_key diff --git a/app/src/main/res/values-b+ko/strings.xml b/app/src/main/res/values-b+ko/strings.xml index 7ab550913..af84eb3a9 100644 --- a/app/src/main/res/values-b+ko/strings.xml +++ b/app/src/main/res/values-b+ko/strings.xml @@ -620,7 +620,6 @@ %s의 PIN 입력 즐겨찾기에서 제거 캐스트미러 - hide_player_control_names_key 플러그인 삭제 경고 탐색바 미리보기 diff --git a/app/src/main/res/values-b+lt/strings.xml b/app/src/main/res/values-b+lt/strings.xml index 357192018..cb2d816f3 100644 --- a/app/src/main/res/values-b+lt/strings.xml +++ b/app/src/main/res/values-b+lt/strings.xml @@ -254,5 +254,4 @@ Ar tikrai norite išeiti? Pašalinti iš žiūrimų Garso takelis - hide_player_control_names_key diff --git a/app/src/main/res/values-b+lv/strings.xml b/app/src/main/res/values-b+lv/strings.xml index 444a59a5f..b87e9e4fe 100644 --- a/app/src/main/res/values-b+lv/strings.xml +++ b/app/src/main/res/values-b+lv/strings.xml @@ -509,7 +509,6 @@ Abonēto šovu atjaunināšana Abonēts Abonēts %s - hide_player_control_names_key %1$d. sezona un %2$d. sērija tiks izlaista pēc %1$dh %2$dm %3$ds %1$dm %2$ds diff --git a/app/src/main/res/values-b+mk/strings.xml b/app/src/main/res/values-b+mk/strings.xml index bccc2a00d..6998c49db 100644 --- a/app/src/main/res/values-b+mk/strings.xml +++ b/app/src/main/res/values-b+mk/strings.xml @@ -593,7 +593,6 @@ Грешка при пристапот до таблата со исечоци, обиди се повторно. Грешка при копирање, молам копирај го логот и контактирај ја поддршката на апликацијата. Аудио книга - hide_player_control_names_key Безбедност Отфрли Отвори извор diff --git a/app/src/main/res/values-b+ml/strings.xml b/app/src/main/res/values-b+ml/strings.xml index dcb9e5270..d1c9409a3 100644 --- a/app/src/main/res/values-b+ml/strings.xml +++ b/app/src/main/res/values-b+ml/strings.xml @@ -272,5 +272,4 @@ എഡ്ജ് തരം ഔട്ട്ലൈൻ നിറം പശ്ചാത്തല നിറം - hide_player_control_names_key diff --git a/app/src/main/res/values-b+ms/strings.xml b/app/src/main/res/values-b+ms/strings.xml index 8bbb2a7e0..83492a5ff 100644 --- a/app/src/main/res/values-b+ms/strings.xml +++ b/app/src/main/res/values-b+ms/strings.xml @@ -54,7 +54,6 @@ Kongsi Tetapan Tutup - hide_player_control_names_key Pratonton Resensi:%.1f Kemas kini baru dijumpai! @@ -516,9 +515,6 @@ Sandarkan data Gagal pulihkan data dari fail %s Ralat sandaran %s - - Episode - Akan datang pada %s Ini akan memadamkan secara kekal %s\nAdakah anda pasti? Adakah anda pasti mahu memadamkan item berikut secara kekal?\n\n%s diff --git a/app/src/main/res/values-b+mt/strings.xml b/app/src/main/res/values-b+mt/strings.xml index ca62a043b..ea859ee29 100644 --- a/app/src/main/res/values-b+mt/strings.xml +++ b/app/src/main/res/values-b+mt/strings.xml @@ -122,5 +122,4 @@ Bookmarks Neħħi Falla t-tniżżil - hide_player_control_names_key diff --git a/app/src/main/res/values-b+my/strings.xml b/app/src/main/res/values-b+my/strings.xml index 1d35cbaa0..4a7a50aa7 100644 --- a/app/src/main/res/values-b+my/strings.xml +++ b/app/src/main/res/values-b+my/strings.xml @@ -537,5 +537,4 @@ သင်နဂိုတည်းကသတ်မှတ်ပြီး လိုက်ဘရီရွေးချယ်ရန် ဖြင့်ဖွင့်မည် - hide_player_control_names_key diff --git a/app/src/main/res/values-b+ne/strings.xml b/app/src/main/res/values-b+ne/strings.xml index 9345cab2b..8a432a505 100644 --- a/app/src/main/res/values-b+ne/strings.xml +++ b/app/src/main/res/values-b+ne/strings.xml @@ -127,5 +127,4 @@ प्लेयरको उपशीर्षकको सेटिङ रिपोजिटरी को नाम र यूआरएल कपी गरियो! - hide_player_control_names_key diff --git a/app/src/main/res/values-b+nl/strings.xml b/app/src/main/res/values-b+nl/strings.xml index 6e0982c79..54508e652 100644 --- a/app/src/main/res/values-b+nl/strings.xml +++ b/app/src/main/res/values-b+nl/strings.xml @@ -292,14 +292,6 @@ MyCoolSite voorbeeld.com Taalcode (nl) - %1$s %2$s account Log uit @@ -594,7 +586,6 @@ Link opnieuw geladen Autoroteer Roteer - hide_player_control_names_key Er zijn momenteel geen downloads beschikbaar. Gekopieerd! Verbergen diff --git a/app/src/main/res/values-b+nn/strings.xml b/app/src/main/res/values-b+nn/strings.xml index 2cf83c183..245bf6618 100644 --- a/app/src/main/res/values-b+nn/strings.xml +++ b/app/src/main/res/values-b+nn/strings.xml @@ -191,5 +191,4 @@ Bilde i bilde Fortsett å sjå Prøv tilkopling på nytt… - hide_player_control_names_key diff --git a/app/src/main/res/values-b+no/strings.xml b/app/src/main/res/values-b+no/strings.xml index a981609cf..374b033c6 100644 --- a/app/src/main/res/values-b+no/strings.xml +++ b/app/src/main/res/values-b+no/strings.xml @@ -192,8 +192,6 @@ Primær Farge App Tema Foretrukket Videoinnhold - Disclaimer - Any legal issues regarding the content on this application should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. In case of copyright infringement, please directly contact the responsible parties or the streaming websites. The app is purely for educational and personal use. CloudStream 3 does not host any content on the app, and has no control over what media is put up or taken down. CloudStream 3 functions like any other search engine, such as Google. CloudStream 3 does not host, upload or manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient, user-friendly interface. It merely scrapes 3rd-party websites that are publicly accessable via any regular web browser. It is the responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use CloudStream 3 at your own risk. Besetning: %s %dm Tøm @@ -525,5 +523,4 @@ Bruk Hjelp Profilbakgrunn - hide_player_control_names_key diff --git a/app/src/main/res/values-b+or/strings.xml b/app/src/main/res/values-b+or/strings.xml index 807a3bcc6..8c9379f5b 100644 --- a/app/src/main/res/values-b+or/strings.xml +++ b/app/src/main/res/values-b+or/strings.xml @@ -155,7 +155,6 @@ କୌଣସି ତଥ୍ୟ ନାହିଁ %1$s ଅ %2$d ଆଦ୍ୟ ବାଦ୍ ଦିଅ - hide_player_control_names_key ଏପିସୋଡ୍ %d ମୁକ୍ତିଲାଭ କରିବ ସିଜିନ୍ %1$d ଏପିସୋଡ୍ %2$d ମୁକ୍ତିଲାଭ କରିବ %1$dଘଣ୍ଟା %2$dମିନିଟ୍ %3$dସେକେଣ୍ଡ diff --git a/app/src/main/res/values-b+pl/array.xml b/app/src/main/res/values-b+pl/array.xml index 7b1683b41..466066852 100644 --- a/app/src/main/res/values-b+pl/array.xml +++ b/app/src/main/res/values-b+pl/array.xml @@ -299,48 +299,4 @@ Vietnamese (VISCII) Vietnamese (Windows-1258) - - - UTF-8 - UTF-16 - UTF-16BE - UTF-16LE - GB18030 - ISO-8859-15 - Windows-1252 - IBM850 - ISO-8859-2 - Windows-1250 - ISO-8859-3 - ISO-8859-10 - Windows-1251 - KOI8-R - KOI8-U - ISO-8859-6 - Windows-1256 - ISO-8859-7 - Windows-1253 - ISO-8859-8 - Windows-1255 - ISO-8859-9 - Windows-1254 - ISO-8859-11 - Windows-874 - ISO-8859-13 - Windows-1257 - ISO-8859-14 - ISO-8859-16 - ISO-2022-CN-EXT - EUC-CN - ISO-2022-JP-2 - EUC-JP - Shift_JIS - CP949 - ISO-2022-KR - Big5 - ISO-2022-TW - Big5-HKSCS - VISCII - Windows-1258 - diff --git a/app/src/main/res/values-b+pl/strings.xml b/app/src/main/res/values-b+pl/strings.xml index e067b391c..59ac0db4b 100644 --- a/app/src/main/res/values-b+pl/strings.xml +++ b/app/src/main/res/values-b+pl/strings.xml @@ -621,7 +621,6 @@ Odrzuć Otwórz repozytorium Odwiedź %s na swoim smartfonie lub komputerze i wprowadź powyższy kod - hide_player_control_names_key Odtwarzaj od początku Usuń wtyczkę Uwaga diff --git a/app/src/main/res/values-b+pt+BR/strings.xml b/app/src/main/res/values-b+pt+BR/strings.xml index 3fbc4fb28..e74a7db74 100644 --- a/app/src/main/res/values-b+pt+BR/strings.xml +++ b/app/src/main/res/values-b+pt+BR/strings.xml @@ -266,7 +266,6 @@ Esticar Zoom Aviso Legal - Any legal issues regarding the content on this application should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. In case of copyright infringement, please directly contact the responsible parties or the streaming websites. The app is purely for educational and personal use. CloudStream 3 does not host any content on the app, and has no control over what media is put up or taken down. CloudStream 3 functions like any other search engine, such as Google. CloudStream 3 does not host, upload or manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient, user-friendly interface. It merely scrapes 3rd-party websites that are publicly accessable via any regular web browser. It is the responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use CloudStream 3 at your own risk. Geral Botão Aleatório Mostrar botão aleatório na página inicial e na biblioteca @@ -291,14 +290,6 @@ NovoNomedoSite https://example.com Codigo da Língua (bp) - %1$s %2$s Conta Sair @@ -640,7 +631,6 @@ Não é possível obter o código PIN do dispositivo, tente a autenticação local O código PIN expirou! O código expira em %1$dm %2$ds - hide_player_control_names_key Reproduzir do começo Reprovou alguns testes Excluir plugin diff --git a/app/src/main/res/values-b+pt/strings.xml b/app/src/main/res/values-b+pt/strings.xml index 23b49195f..e7b3623e6 100644 --- a/app/src/main/res/values-b+pt/strings.xml +++ b/app/src/main/res/values-b+pt/strings.xml @@ -606,7 +606,6 @@ Temporada %1$d Episódio %2$d será lançado em Escolha o dispositivo Transmitir - hide_player_control_names_key Abrir vídeo local Não é possível receber o PIN do dispositivo, tentando autenticação local Pré-visualização na barra de progresso diff --git a/app/src/main/res/values-b+qt/strings.xml b/app/src/main/res/values-b+qt/strings.xml index 3de0f32df..d60a4e32c 100644 --- a/app/src/main/res/values-b+qt/strings.xml +++ b/app/src/main/res/values-b+qt/strings.xml @@ -239,7 +239,6 @@ oooooh uuaagh @string/home_play oouuhhh ahhooo-ahah - hide_player_control_names_key uuuugg aaaahh oogg aagg uuuuggg og %1$dm %2$ds aaaahhh ag diff --git a/app/src/main/res/values-b+ro/strings.xml b/app/src/main/res/values-b+ro/strings.xml index 642eea0c3..e2dbd0e32 100644 --- a/app/src/main/res/values-b+ro/strings.xml +++ b/app/src/main/res/values-b+ro/strings.xml @@ -261,7 +261,6 @@ Întindere Mărire Aviz juridic (declinarea responsabilității și drepturi de autor) - Orice probleme legale privind conținutul acestei aplicații ar trebui să fie rezolvate cu furnizorii și gazdele actuale de fișiere, întrucât noi nu suntem afiliați cu aceștia. În caz de încălcare a drepturilor de autor, vă rugăm să contactați direct părțile responsabile sau site-urile de streaming. Aplicația este destinată exclusiv utilizării educaționale și personale. CloudStream 3 nu găzduiește niciun fel de conținut în aplicație și nu are niciun control asupra conținutului media care este pus sau retras. CloudStream 3 funcționează ca orice alt motor de căutare, cum ar fi Google. CloudStream 3 nu găzduiește, nu încarcă și nu gestionează niciun videoclip, film sau conținut. Pur și simplu navighează, adună și afișează linkuri într-o interfață convenabilă și ușor de utilizat. Pur și simplu, acesta extrage paginile web ale unor terțe părți care sunt accesibile publicului prin intermediul oricărui browser web obișnuit. Este responsabilitatea utilizatorului de a evita orice acțiune care ar putea încălca legile care guvernează locația sa. Utilizați CloudStream 3 pe propria răspundere. General Aleatoriu Afișează butonul pentru aleatoriu pe Pagina Principală și în Bibliotecă @@ -627,7 +626,6 @@ Sezonul %1$d Episod %2$d va fi lansat în Selectați divece-ul pe care doriți să faceți cast Cast mirror - hide_player_control_names_key Redă de la început Nu există descărcări. Selectionati elementele de sters diff --git a/app/src/main/res/values-b+ru/strings.xml b/app/src/main/res/values-b+ru/strings.xml index d25f7e274..d8b369a3d 100644 --- a/app/src/main/res/values-b+ru/strings.xml +++ b/app/src/main/res/values-b+ru/strings.xml @@ -555,12 +555,10 @@ Добавить в любимое Включить автоматическую смену ориентации экрана на основе ориентации видео Автоповорот - rotate_video_key Использовать учётную запись по умолчанию Отписаться Заменить Введите текущий ПИН-код - auto_rotate_video_key Любимые %s добавлено в любимые Введите ПИН-код от %s @@ -600,7 +598,6 @@ Сезон %1$d серия %2$d выйдет Выйдет %s Выберите устройство для трансляции - hide_player_control_names_key В данный момент скачиваний нет. Играть с самого начала Открыть локальное видео diff --git a/app/src/main/res/values-b+sk/strings.xml b/app/src/main/res/values-b+sk/strings.xml index fb65841f2..93505971c 100644 --- a/app/src/main/res/values-b+sk/strings.xml +++ b/app/src/main/res/values-b+sk/strings.xml @@ -369,7 +369,6 @@ Pridať repozitár Názov repozitára Zobraziť komunitné repozitáre - hide_player_control_names_key HD Prehrávač Rozlíšenie a titul diff --git a/app/src/main/res/values-b+so/strings.xml b/app/src/main/res/values-b+so/strings.xml index fc42c63f7..09499af00 100644 --- a/app/src/main/res/values-b+so/strings.xml +++ b/app/src/main/res/values-b+so/strings.xml @@ -472,5 +472,4 @@ Bilowga Bilow isku qasan Qoraalka dhamaadka - hide_player_control_names_key diff --git a/app/src/main/res/values-b+sv/strings.xml b/app/src/main/res/values-b+sv/strings.xml index dfbfce4b5..75c7efda4 100644 --- a/app/src/main/res/values-b+sv/strings.xml +++ b/app/src/main/res/values-b+sv/strings.xml @@ -465,7 +465,6 @@ Redigera konto Loggat in som %s Hoppa över val av konto vid start - auto_rotera_video_nyckel Gå förbi blockering av rå GitHub-URL:er med jsDelivr. Kan göra att uppdateringar försenas med några dagar. Funktion Önskad media @@ -557,7 +556,6 @@ %s togs bort från favoriter %s har lagts till i favoriter Använd standard konto - rotera_video_nyckel PIN-kod Sök mängden som används när spelaren är dold Det verkar som om ett potentiellt duplicerat objekt redan finns i ditt bibliotek: @@ -612,7 +610,6 @@ CloudStream Wiki Konton Säkerhet - hide_player_control_names_key Avfärda Öppna databasen Koden löper ut om %1$dm %2$ds diff --git a/app/src/main/res/values-b+ta/strings.xml b/app/src/main/res/values-b+ta/strings.xml index 94b6f717a..e223f6c60 100644 --- a/app/src/main/res/values-b+ta/strings.xml +++ b/app/src/main/res/values-b+ta/strings.xml @@ -576,7 +576,6 @@ ஆதாரங்கள் எவ்வாறு உத்தரவிடப்படுகின்றன என்பதை இங்கே மாற்றலாம். ஒரு வீடியோவுக்கு அதிக முன்னுரிமை இருந்தால், அது மூல தேர்வில் அதிகமாகத் தோன்றும். மூல முன்னுரிமையின் தொகை மற்றும் தரமான முன்னுரிமை ஆகியவை வீடியோ முன்னுரிமை. \n\n சான்று A: 3 \n தகுதி பி: 7 \n 10 இன் ஒருங்கிணைந்த வீடியோ முன்னுரிமை இருக்கும். \n\n குறிப்பு: தொகை 10 அல்லது அதற்கு மேற்பட்டதாக இருந்தால், அந்த இணைப்பு ஏற்றப்படும்போது பிளேயர் தானாகவே ஏற்றுவதைத் தவிர்க்கும்! உங்கள் கிளவுட்ச்ட்ரீம் தரவு இப்போது காப்புப் பிரதி எடுக்கப்பட்டுள்ளது. இதன் சாத்தியம் மிகக் குறைவு என்றாலும், எல்லா சாதனங்களும் வித்தியாசமாக நடந்து கொள்ளலாம். அரிய விசயத்தில், பயன்பாட்டை அணுகுவதிலிருந்து நீங்கள் பூட்டப்படுகிறீர்கள், பயன்பாட்டு தரவை முழுவதுமாக அழித்து, காப்புப்பிரதியிலிருந்து மீட்டெடுக்கவும். இதிலிருந்து எழும் ஏதேனும் சிரமத்திற்கு நாங்கள் மிகவும் வருந்துகிறோம். ஊடகம் - hide_player_control_names_key கணக்குகள் எச்சரிக்கை தற்போது பதிவிறக்கங்கள் எதுவும் இல்லை. diff --git a/app/src/main/res/values-b+ti/strings.xml b/app/src/main/res/values-b+ti/strings.xml index 6c154c8d8..46235bbd7 100644 --- a/app/src/main/res/values-b+ti/strings.xml +++ b/app/src/main/res/values-b+ti/strings.xml @@ -3,5 +3,4 @@ %1$s ክፋል %2$d ክፋል %d በ ላይ ይወጣል ተዋሳእቲ፡ %s - hide_player_control_names_key diff --git a/app/src/main/res/values-b+tl/strings.xml b/app/src/main/res/values-b+tl/strings.xml index 94bb8ea1d..4050ddbd7 100644 --- a/app/src/main/res/values-b+tl/strings.xml +++ b/app/src/main/res/values-b+tl/strings.xml @@ -257,5 +257,4 @@ Mga Subtitle ng Chromecast Mga setting ng mga subtitle ng Chromecast Maglaro ng Trailer - hide_player_control_names_key diff --git a/app/src/main/res/values-b+tr/array.xml b/app/src/main/res/values-b+tr/array.xml index 56cea4c9c..dbc2d3e66 100644 --- a/app/src/main/res/values-b+tr/array.xml +++ b/app/src/main/res/values-b+tr/array.xml @@ -319,48 +319,4 @@ Vietnamese (VISCII) Vietnamese (Windows-1258) - - - UTF-8 - UTF-16 - UTF-16BE - UTF-16LE - GB18030 - ISO-8859-15 - Windows-1252 - IBM850 - ISO-8859-2 - Windows-1250 - ISO-8859-3 - ISO-8859-10 - Windows-1251 - KOI8-R - KOI8-U - ISO-8859-6 - Windows-1256 - ISO-8859-7 - Windows-1253 - ISO-8859-8 - Windows-1255 - ISO-8859-9 - Windows-1254 - ISO-8859-11 - Windows-874 - ISO-8859-13 - Windows-1257 - ISO-8859-14 - ISO-8859-16 - ISO-2022-CN-EXT - EUC-CN - ISO-2022-JP-2 - EUC-JP - Shift_JIS - CP949 - ISO-2022-KR - Big5 - ISO-2022-TW - Big5-HKSCS - VISCII - Windows-1258 - diff --git a/app/src/main/res/values-b+tr/strings.xml b/app/src/main/res/values-b+tr/strings.xml index f6a125b91..10137e7b5 100644 --- a/app/src/main/res/values-b+tr/strings.xml +++ b/app/src/main/res/values-b+tr/strings.xml @@ -1,15 +1,6 @@ - %d %s | %s - %s • %s - %s / %s - %s %s - +%d - -%d - %d - %d - %d %1$s B. %2$d Cast: %s Bölüm %d şu tarihte yayınlanacak @@ -22,9 +13,7 @@ Bölüm Afişi Ana Afiş Sonraki Rastgele - @string/play_episode Geri git - @string/home_change_provider_img_des Sağlayıcıyı Değiştir Arkaplanı Önizle @@ -45,7 +34,6 @@ Veri Yok Daha Fazla Seçenek Sonraki bölüm - @string/synopsis Türler Paylaş Tarayıcıda aç @@ -74,7 +62,6 @@ İndirme Başarısız İndirme İptal Edildi İndirme Tamamlandı - %s - %s Ağ akışı Bağlantılar yüklenirken hata oluştu Dahili Depolama @@ -258,10 +245,6 @@ Dublaj etiketi Altyazı etiketi Başlık - show_hd_key - show_dub_key - show_sub_key - show_title_key Afiş üzerindeki öğeleri değiştir Güncelleme bulunamadı Güncellemeleri denetle @@ -293,8 +276,6 @@ Uzat Yakınlaştır Yasal uyarı - legal_notice_key - Any legal issues regarding the content on this application should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. In case of copyright infringement, please directly contact the responsible parties or the streaming websites. The app is purely for educational and personal use. CloudStream 3 does not host any content on the app, and has no control over what media is put up or taken down. CloudStream 3 functions like any other search engine, such as Google. CloudStream 3 does not host, upload or manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient, user-friendly interface. It merely scrapes 3rd-party websites that are publicly accessable via any regular web browser. It is the responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use CloudStream 3 at your own risk. Genel Rastgele düğmesi Ana sayfa ve kütüphane üstünde rastgele düğmesini göster @@ -314,10 +295,6 @@ Afiş başlık konumu Başlığı afişin altına yerleştir - anilist_key - mal_key - opensubtitles_key - nginx_key şifre123 Kullanıcı Adı hello@world.com @@ -325,14 +302,6 @@ YeniSiteAdı https://ornek.com Dil kodu (tr) - %1$s %2$s hesap Çıkış yap @@ -355,7 +324,6 @@ Tümü Azami Asgari - @string/none Dış hat Çökmüş Gölge @@ -614,8 +582,6 @@ PIN Geçerli PIN\'i Giriniz Ekran yönü için bir geçiş düğmesi göster - rotate_video_key - auto_rotate_video_key Otomatik döndür Döndür Video yönüne göre ekran yönünün otomatik olarak değişmesini sağla @@ -664,7 +630,6 @@ Cihaz PIN kodu alınamıyor, yerel kimlik doğrulamayı deneyin PIN kodunun süresi doldu! Kodun süresi %1$dm %2$ds içinde doluyor - hide_player_control_names_key Şu an hiç bir indirme bulunmamaktadır. Eklentiyi sil Yerel videoyu aç diff --git a/app/src/main/res/values-b+uk/strings.xml b/app/src/main/res/values-b+uk/strings.xml index 54562f263..20bd9e6e2 100644 --- a/app/src/main/res/values-b+uk/strings.xml +++ b/app/src/main/res/values-b+uk/strings.xml @@ -550,10 +550,8 @@ Керувати обліковими записами Редагувати обліковий запис Показувати кнопку перемикання орієнтації екрана - rotate_video_key Обернути Покликання перезавантажено - auto_rotate_video_key Автообертання Увімкнути автоматичну зміну орієнтації екрана відповідно до відео Додати налаштування швидкості до програвача @@ -600,7 +598,6 @@ Термін дії коду закінчується через %1$dхв %2$dс Локальна автентифікація Відхилити - hide_player_control_names_key Відтворити з початку Попередження Видалити розширення diff --git a/app/src/main/res/values-b+ur/strings.xml b/app/src/main/res/values-b+ur/strings.xml index d2c3d9f1c..5f6d8aa14 100644 --- a/app/src/main/res/values-b+ur/strings.xml +++ b/app/src/main/res/values-b+ur/strings.xml @@ -604,7 +604,6 @@ دیگر ایکسٹینشنز میں تلاش کریں سفارشات دکھائیں آپ کے CloudStream ڈیٹا کا اب بیک اپ لیا گیا ہے۔ اگرچہ اس کا امکان بہت کم ہے، لیکن مختلف ڈیوائس مختلف طریقے سے کام کر سکتے ہیں۔ اگر آپ ایپ تک رسائی حاصل کرنے سے قاصر ہیں تو، ایپ کا ڈیٹا مکمل طور پر صاف کریں اور بیک اپ سے بحال کریں۔ اس سے ہونے والی کسی بھی تکلیف کے لیے ہم بہت معذرت خواہ ہیں۔ - hide_player_control_names_key سیزن %1$d کی قسط %2$d جاری ہوگی شروع سےپلے کریں کلام شناسی دستیاب نہیں diff --git a/app/src/main/res/values-b+vi/array.xml b/app/src/main/res/values-b+vi/array.xml index d1887505e..16d45e516 100644 --- a/app/src/main/res/values-b+vi/array.xml +++ b/app/src/main/res/values-b+vi/array.xml @@ -291,48 +291,4 @@ Vietnamese (VISCII) Vietnamese (Windows-1258) - - - UTF-8 - UTF-16 - UTF-16BE - UTF-16LE - GB18030 - ISO-8859-15 - Windows-1252 - IBM850 - ISO-8859-2 - Windows-1250 - ISO-8859-3 - ISO-8859-10 - Windows-1251 - KOI8-R - KOI8-U - ISO-8859-6 - Windows-1256 - ISO-8859-7 - Windows-1253 - ISO-8859-8 - Windows-1255 - ISO-8859-9 - Windows-1254 - ISO-8859-11 - Windows-874 - ISO-8859-13 - Windows-1257 - ISO-8859-14 - ISO-8859-16 - ISO-2022-CN-EXT - EUC-CN - ISO-2022-JP-2 - EUC-JP - Shift_JIS - CP949 - ISO-2022-KR - Big5 - ISO-2022-TW - Big5-HKSCS - VISCII - Windows-1258 - diff --git a/app/src/main/res/values-b+vi/strings.xml b/app/src/main/res/values-b+vi/strings.xml index aa9caffd1..b26c715f3 100644 --- a/app/src/main/res/values-b+vi/strings.xml +++ b/app/src/main/res/values-b+vi/strings.xml @@ -630,7 +630,6 @@ Truy cập %s trên điện thoại hoặc máy tính và nhập mã bên trên Mã PIN đã hết hạn! Mã sẽ hết hạn trong %1$dm %2$ds - hide_player_control_names_key Không lấy được mã PIN, hãy thử xác thực cục bộ Hiện không có bản tải xuống nào. Xác thực cục bộ diff --git a/app/src/main/res/values-b+zh+TW/strings.xml b/app/src/main/res/values-b+zh+TW/strings.xml index 251df543c..7dc4b48f2 100644 --- a/app/src/main/res/values-b+zh+TW/strings.xml +++ b/app/src/main/res/values-b+zh+TW/strings.xml @@ -1,15 +1,6 @@ - %d %s | %s - %s • %s - %s / %s - %s %s - +%d - -%d - %d - %d - %d %1$s 共 %2$d 集 演員:%s 第 %d 集即將發佈於 @@ -22,9 +13,7 @@ 劇集封面 主封面 隨機下一個 - @string/play_episode 返回 - @string/home_change_provider_img_des 更改片源 預覽背景 @@ -45,7 +34,6 @@ 無資料 更多選項 下一集 - @string/synopsis 類型 分享 在瀏覽器中打開 @@ -74,7 +62,6 @@ 下載失敗 下載取消 下載完畢 - %s - %s 網路串流 載入連結錯誤 內部儲存空間 @@ -259,10 +246,6 @@ 配音標籤 字幕標籤 標題 - show_hd_key - show_dub_key - show_sub_key - show_title_key 封面內容 未找到更新 檢查更新 @@ -294,8 +277,6 @@ 拉伸 縮放 免責聲明 - legal_notice_key - Any legal issues regarding the content on this application should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. In case of copyright infringement, please directly contact the responsible parties or the streaming websites. The app is purely for educational and personal use. CloudStream 3 does not host any content on the app, and has no control over what media is put up or taken down. CloudStream 3 functions like any other search engine, such as Google. CloudStream 3 does not host, upload or manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient, user-friendly interface. It merely scrapes 3rd-party websites that are publicly accessable via any regular web browser. It is the responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use CloudStream 3 at your own risk. 通用 隨機按鈕 在主畫面與媒體庫中顯示隨機按鈕 @@ -315,10 +296,6 @@ 封面標題位置 將標題移到封面下方 - anilist_key - mal_key - opensubtitles_key - nginx_key 密碼 使用者名稱 電子郵件 @@ -326,14 +303,6 @@ 新網站名稱 https://example.com 語言代號 (zh_TW) - %1$s %2$s 帳號 登出 @@ -356,7 +325,6 @@ 全部 最大 最小 - @string/none 輪廓 凹陷 陰影 @@ -614,9 +582,7 @@ \n注意:如果加總達到 10 或更高,則載入該連結時播放器將自動跳過載入! 輸入目前的 PIN 碼 顯示切換畫面方向的按鈕 - rotate_video_key 選擇篩選外掛程式下載的模式 - auto_rotate_video_key 自動旋轉 旋轉 根據影片方向自動切換畫面方向 @@ -656,7 +622,6 @@ 為了確保下載與通知已訂閱的電視節目的不間斷,CloudStream 需要取得在背景執行的權限。若點選「確定」,將移至「應用程式資訊」,請找到「應用程式電池使用」並將電池用量設置為「無限制」。請注意,取得此權限並不表示 CS3 會明顯增加電池用量,而是只在必要時在背景執行,例如取得通知或使用官方擴充功能下載影片時。若選擇「取消」,您可以稍後在「一般設定」中調整此設定。 CloudStream Wiki 此裝置不支援生物特徵認證 - hide_player_control_names_key 無法取得裝置 PIN 碼,請嘗試本機驗證 刪除外掛程式 開啟資源庫 diff --git a/app/src/main/res/values-b+zh/strings.xml b/app/src/main/res/values-b+zh/strings.xml index 224041e49..0301a3a2d 100644 --- a/app/src/main/res/values-b+zh/strings.xml +++ b/app/src/main/res/values-b+zh/strings.xml @@ -1,15 +1,6 @@ - %d %s | %s - %s • %s - %s / %s - %s %s - +%d - -%d - %d - %d - %d %1$s 共 %2$d 集 演员:%s 第 %d 集将发布于 @@ -22,9 +13,7 @@ 剧集封面 主封面 随机下一个 - @string/play_episode 返回 - @string/home_change_provider_img_des 更改片源 预览背景 @@ -45,7 +34,6 @@ 无数据 更多选项 下一集 - @string/synopsis 类型 分享 在浏览器中打开 @@ -74,7 +62,6 @@ 下载失败 下载取消 下载完毕 - %s - %s 播放 加载链接错误 内部存储 @@ -260,10 +247,6 @@ 配音标签 字幕标签 标题 - show_hd_key - show_dub_key - show_sub_key - show_title_key 封面内容 未找到更新 检查更新 @@ -295,8 +278,6 @@ 拉伸 缩放 免责声明 - legal_notice_key - Any legal issues regarding the content on this application should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. In case of copyright infringement, please directly contact the responsible parties or the streaming websites. The app is purely for educational and personal use. CloudStream 3 does not host any content on the app, and has no control over what media is put up or taken down. CloudStream 3 functions like any other search engine, such as Google. CloudStream 3 does not host, upload or manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient, user-friendly interface. It merely scrapes 3rd-party websites that are publicly accessable via any regular web browser. It is the responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use CloudStream 3 at your own risk. 通用 随机按钮 在主页和库中显示随机按钮 @@ -316,10 +297,6 @@ 封面标题位置 将标题移至封面下方 - anilist_key - mal_key - opensubtitles_key - nginx_key 密码 用户名 邮箱 @@ -327,14 +304,6 @@ 网站名称 网站链接 语言代码 (zh) - %1$s %2$s 账户 注销 @@ -357,7 +326,6 @@ 全部 最大 最小 - @string/none 轮廓 凹陷 阴影 @@ -654,7 +622,6 @@ 选择投射设备 %1$d季%2$d集将在 投射镜像 - hide_player_control_names_key 目前尚无下载。 打开本地视频 安全 diff --git a/app/src/main/res/values/donottranslate-strings.xml b/app/src/main/res/values/donottranslate-strings.xml new file mode 100644 index 000000000..5f2186fae --- /dev/null +++ b/app/src/main/res/values/donottranslate-strings.xml @@ -0,0 +1,152 @@ + + + + search_providers_list + app_locale + search_type_list + auto_update + auto_update_plugins + auto_download_plugins_key2 + skip_update_key + install_prerelease_key + manual_check_update + fast_forward_button_time + benene_count + subtitle_settings_key + test_providers_key + subtitle_settings_chromecast_key + quality_pref_key + quality_pref_mobile_data_key + player_default_key + prefer_limit_title_key + prefer_limit_title_rez_key + apk_installer_key + video_buffer_size_key + video_buffer_length_key + video_buffer_clear_key + video_buffer_disk_key + use_system_brightness_key + swipe_enabled_key + playback_speed_enabled_key + player_resize_enabled_key + pip_enabled_key + double_tap_enabled_key + double_tap_pause_enabled_key + double_tap_seek_time_key2 + android_tv_interface_off_seek_key + android_tv_interface_on_seek_key + swipe_vertical_enabled_key + autoplay_next_key + display_sub_key + show_fillers_key + show_trailers_key + show_kitsu_posters_key + random_button_key + provider_lang_key + dns_key + jsdelivr_proxy_key + download_path_key + download_parallel_key + download_concurrent_key + download_path_key_visual + Cloudstream + app_layout_key + primary_color_key + restore_key + backup_key + automatic_backup_key + prefer_media_type_key_2 + app_theme_key + episode_sync_enabled_key + log_enabled_key + show_logcat_key + bottom_title_key + poster_ui_key + overscan_key + poster_size_key + subtitles_encoding_key + override_site_key + redo_setup_key + filter_sub_lang_key + pref_filter_search_quality_key + enable_nsfw_on_providers_key + skip_startup_account_select_key + enable_skip_op_from_database + rotate_video_key + auto_rotate_video_key + biometric_key + battery_optimisation + show_hd_key + show_dub_key + show_sub_key + show_rating_key + show_title_key + show_episode_text_key + hide_player_control_names_key + preview_seekbar_key + backup_path_key + backup_dir_key + confirm_exit_key + software_decoding_key2 + manual_update_plugins + legal_notice_key + speedup_key + anilist_key + simkl_key + mal_key + opensubtitles_key + subdl_key + + pref_category_security_key + pref_category_gestures_key + pref_category_android_tv_key + + tv_no_focus_tag + + + %1$d %2$s | %3$s + %1$s • %2$s + %1$s - %2$s + %1$s / %2$s + %1$s %2$s + S1E1 + +%d + -%d + %d + %d + %s/10.0 + %d + + @string/play_episode + @string/home_change_provider_img_des + @string/synopsis + + @string/none + @string/none + @string/cancel + @string/cancel + @string/action_default + @string/action_default + + Any legal issues regarding the content on this application + should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. + + In case of copyright infringement, please directly contact the responsible parties or the streaming websites. + + The app is purely for educational and personal use. + + CloudStream does not host any content on the app, and has no control over what media is put up or taken down. + CloudStream functions like any other search engine, such as Google. CloudStream does not host, upload or + manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient, + user-friendly interface. + + It merely scrapes 3rd-party websites that are publicly accessible via any regular web browser. It is the + responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use + CloudStream at your own risk. + + + + @string/episode + @string/episodes + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9aa586e8a..8ad0ec423 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,91 +1,6 @@ - - search_providers_list - app_locale - search_type_list - auto_update - auto_update_plugins - auto_download_plugins_key2 - skip_update_key - install_prerelease_key - manual_check_update - fast_forward_button_time - benene_count - subtitle_settings_key - test_providers_key - subtitle_settings_chromecast_key - quality_pref_key - quality_pref_mobile_data_key - player_default_key - prefer_limit_title_key - prefer_limit_title_rez_key - apk_installer_key - video_buffer_size_key - video_buffer_length_key - video_buffer_clear_key - video_buffer_disk_key - use_system_brightness_key - swipe_enabled_key - playback_speed_enabled_key - player_resize_enabled_key - pip_enabled_key - double_tap_enabled_key - double_tap_pause_enabled_key - double_tap_seek_time_key2 - android_tv_interface_off_seek_key - android_tv_interface_on_seek_key - swipe_vertical_enabled_key - autoplay_next_key - display_sub_key - show_fillers_key - show_trailers_key - show_kitsu_posters_key - random_button_key - provider_lang_key - dns_key - jsdelivr_proxy_key - download_path_key - download_parallel_key - download_concurrent_key - download_path_key_visual - Cloudstream - app_layout_key - primary_color_key - restore_key - backup_key - automatic_backup_key - prefer_media_type_key_2 - app_theme_key - episode_sync_enabled_key - log_enabled_key - show_logcat_key - bottom_title_key - poster_ui_key - overscan_key - poster_size_key - subtitles_encoding_key - override_site_key - redo_setup_key - filter_sub_lang_key - pref_filter_search_quality_key - enable_nsfw_on_providers_key - skip_startup_account_select_key - enable_skip_op_from_database - rotate_video_key - auto_rotate_video_key - biometric_key - %d %s | %s - %s • %s - %s / %s - %s %s - +%d - -%d - %d - %d - %s/10.0 - %d %1$s Ep %2$d Cast: %s Episode %d will be released in @@ -102,10 +17,8 @@ Episode Poster Main Poster Next Random - @string/play_episode Go back Play from the Beginning - @string/home_change_provider_img_des Change Provider Preview Background @@ -127,7 +40,6 @@ No Data More Options Next episode - @string/synopsis Genres Share Open In Browser @@ -139,7 +51,6 @@ Completed Dropped Plan to Watch - @string/none Rewatching Play Movie Play Trailer @@ -161,7 +72,6 @@ Download Failed Download Canceled Download Done - %s - %s Select Items to Delete There are currently no downloads. Available for watching offline @@ -188,7 +98,6 @@ Remove Set watch status Apply - @string/cancel Copy Close Clear @@ -342,8 +251,6 @@ queued No Subtitles Default - @string/action_default - @string/action_default Free Used App @@ -359,10 +266,6 @@ Livestreams NSFW Others - - @string/episode - @string/episodes - Movie Series @@ -403,12 +306,6 @@ Rating Label Title Episode Text - show_hd_key - show_dub_key - show_sub_key - show_rating_key - show_title_key - show_episode_text_key Toggle UI elements on poster No Update Found Check for Update @@ -448,23 +345,6 @@ Stretch Zoom Disclaimer - legal_notice_key - Any legal issues regarding the content on this application - should be taken up with the actual file hosts and providers themselves as we are not affiliated with them. - - In case of copyright infringement, please directly contact the responsible parties or the streaming websites. - - The app is purely for educational and personal use. - - CloudStream 3 does not host any content on the app, and has no control over what media is put up or taken down. - CloudStream 3 functions like any other search engine, such as Google. CloudStream 3 does not host, upload or - manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient, - user-friendly interface. - - It merely scrapes 3rd-party websites that are publicly accessable via any regular web browser. It is the - responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use - CloudStream 3 at your own risk. - ISP Bypasses Links App updates @@ -473,11 +353,8 @@ Actions Cache Android TV - pref_category_android_tv_key Gestures - pref_category_gestures_key Security - pref_category_security_key Accounts Player features Subtitles @@ -507,12 +384,6 @@ Poster title location Put the title under the poster - anilist_key - simkl_key - mal_key - opensubtitles_key - subdl_key - nginx_key password123 Username hello@world.com @@ -520,14 +391,6 @@ NewSiteName https://example.com Language code (en) - %1$s %2$s account Log out @@ -552,7 +415,6 @@ All Max Min - @string/none Outline Depressed Shadow @@ -653,7 +515,7 @@ View community repositories Public list Uppercase all subtitles - Warning: CloudStream 3 does not take any responsibility for using third-party extensions and does not provide any support for them! + Warning: CloudStream does not take any responsibility for using third-party extensions and does not provide any support for them! %s (Disabled) Tracks Audio tracks @@ -707,7 +569,6 @@ TV shows, CloudStream needs permission to run in background. By pressing "OK", you\'ll be shown a request dialog. Please press \'Allow\'.\n\nPlease note, this permission does not mean CS3 will drain your battery. It will only operate in the background when necessary, such as when receiving notifications or downloading videos from official extensions. - battery_optimisation App battery usage is already set to unrestricted Unable to open CloudStream\'s App info. Downloading app update… @@ -777,7 +638,6 @@ Add Replace Replace All - @string/cancel It appears that a potentially duplicate item already exists in your library: \'%s.\' @@ -790,7 +650,6 @@ \n\nWould you like to add this item anyway, replace the existing ones, or cancel the action? - tv_no_focus_tag Enter PIN Enter PIN for %s Enter Current PIN @@ -827,27 +686,21 @@ Code expires in %1$dm %2$ds Release Date (New to Old) Release Date (Old to New) - hide_player_control_names_key Hide names of the player\'s controls - preview_seekbar_key Seekbar preview Enable preview thumbnail on seekbar No subtitles loaded yet - backup_path_key Backup folder location - backup_dir_key Custom Confirm before exiting Show dialog before exiting the app - confirm_exit_key Show Don\'t Show Edge Size Enable torrent in Settings/Providers/Preferred media Restart app and accept Stream Torrent pop-up to proceed. - software_decoding_key2 Software decoding Software decoding enables the player to play video files not supported by your device, but may cause laggy or unstable playback on high resolution. Volume has exceeded 100% @@ -855,7 +708,6 @@ Update Plugins Update plugins manually - manual_update_plugins Starting plugin update process! Successfully updated %d plugin(s)! No plugins were updated. @@ -879,7 +731,6 @@ Overscan Changes size of posters Poster size - speedup_key LongPress Speed Toggle Hold to get 2x speed Edit Profile Image @@ -903,5 +754,4 @@ Top left Top center Top right - S1E1 From 2795e9e0e2856dfd4d43177eb0be4981da1270b3 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sun, 4 Jan 2026 10:08:15 +0100 Subject: [PATCH 236/513] feat(extractors): add vidnest extractor (#2390) --- .../lagradost/cloudstream3/extractors/AsianLoad.kt | 12 +++++++----- .../com/lagradost/cloudstream3/utils/ExtractorApi.kt | 2 ++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/AsianLoad.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/AsianLoad.kt index 256681679..70e869f55 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/AsianLoad.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/AsianLoad.kt @@ -4,9 +4,12 @@ import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.utils.ExtractorApi import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.M3u8Helper -import com.lagradost.cloudstream3.utils.getQualityFromName import com.lagradost.cloudstream3.utils.newExtractorLink -import java.net.URI + +class Vidnest : AsianLoad() { + override var name = "Vidnest" + override var mainUrl = "https://vidnest.io" +} open class AsianLoad : ExtractorApi() { override var name = "AsianLoad" @@ -20,7 +23,7 @@ open class AsianLoad : ExtractorApi() { sourceRegex.findAll(this.text).forEach { sourceMatch -> val extractedUrl = sourceMatch.groupValues[1] // Trusting this isn't mp4, may fuck up stuff - if (URI(extractedUrl).path.endsWith(".m3u8")) { + if (extractedUrl.contains(".m3u8")) { M3u8Helper.generateM3u8( name, extractedUrl, @@ -29,7 +32,7 @@ open class AsianLoad : ExtractorApi() { ).forEach { link -> extractedLinksList.add(link) } - } else if (extractedUrl.endsWith(".mp4")) { + } else if (extractedUrl.contains(".mp4")) { extractedLinksList.add( newExtractorLink( source = name, @@ -37,7 +40,6 @@ open class AsianLoad : ExtractorApi() { url = extractedUrl, ) { this.referer = url.replace(" ", "%20") - this.quality = getQualityFromName(sourceMatch.groupValues[2]) } ) } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt index 641c91319..b9a147fc7 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -263,6 +263,7 @@ import com.lagradost.cloudstream3.extractors.Vidguardto3 import com.lagradost.cloudstream3.extractors.VidhideExtractor import com.lagradost.cloudstream3.extractors.Vidmoly import com.lagradost.cloudstream3.extractors.Vidmolyme +import com.lagradost.cloudstream3.extractors.Vidnest import com.lagradost.cloudstream3.extractors.Vido import com.lagradost.cloudstream3.extractors.Vidstreamz import com.lagradost.cloudstream3.extractors.VinovoSi @@ -1169,6 +1170,7 @@ val extractorApis: MutableList = arrayListOf( FlaswishCom(), SfastwishCom(), Playerwish(), + Vidnest(), EmturbovidExtractor(), Vtbe(), EPlayExtractor(), From dc6b9f435d988cd09c7d101eb1c043ccdb4a4e3c Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sun, 4 Jan 2026 10:09:50 +0100 Subject: [PATCH 237/513] feat(extractors): add up4stream extractor (#2389) --- .../cloudstream3/extractors/Up4Stream.kt | 60 +++++++++++++++++++ .../cloudstream3/utils/ExtractorApi.kt | 4 ++ 2 files changed, 64 insertions(+) create mode 100644 library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Up4Stream.kt diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Up4Stream.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Up4Stream.kt new file mode 100644 index 000000000..91150992b --- /dev/null +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Up4Stream.kt @@ -0,0 +1,60 @@ +package com.lagradost.cloudstream3.extractors + +import com.lagradost.api.Log +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.utils.ExtractorApi +import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.JsUnpacker +import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.cloudstream3.utils.fixUrl +import com.lagradost.cloudstream3.utils.newExtractorLink +import kotlinx.coroutines.delay + +class Up4FunTop : Up4Stream() { + override var mainUrl: String = "https://up4fun.top" +} + +open class Up4Stream : ExtractorApi() { + override var name = "Up4Stream" + override var mainUrl = "https://up4stream.com" + override val requiresReferer = true + + override suspend fun getUrl(url: String, referer: String?): List? { + val movieId = url.substringAfterLast("/").substringBefore(".html") + + // redirect from "wait 5 seconds" page to actual movie page + val redirectResponse = app.get(url, cookies = mapOf("id" to movieId)) + val redirectForm = redirectResponse.document.selectFirst("form[method=POST]") ?: return null + val redirectUrl = fixUrl(redirectForm.attr("action")) + val redirectParams = redirectForm.select("input[type=hidden]").associate { input -> + input.attr("name") to input.attr("value") + } + + // wait for 5 seconds, otherwise the below md5 hash is invalid + delay(5000) + val response = app.post(redirectUrl, data = redirectParams).document + + // starting here, this works similar to many other extractors like StreamWish + val extractedpack = + response.selectFirst("script:containsData(function(p,a,c,k,e,d))")?.data() + if (extractedpack == null) { + Log.e("up4stream", "file not ready: delay too short") + } + + JsUnpacker(extractedpack).unpack()?.let { unPacked -> + Regex("sources:\\[\\{file:\"(.*?)\"").find(unPacked)?.groupValues?.get(1)?.let { link -> + return listOf( + newExtractorLink( + this.name, + this.name, + link, + ) { + this.referer = referer.orEmpty() + this.quality = Qualities.Unknown.value + } + ) + } + } + return null + } +} \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt index b9a147fc7..c0d5c5da7 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -230,6 +230,8 @@ import com.lagradost.cloudstream3.extractors.Techinmind import com.lagradost.cloudstream3.extractors.Tomatomatela import com.lagradost.cloudstream3.extractors.TomatomatelalClub import com.lagradost.cloudstream3.extractors.Tubeless +import com.lagradost.cloudstream3.extractors.Up4FunTop +import com.lagradost.cloudstream3.extractors.Up4Stream import com.lagradost.cloudstream3.extractors.Upstream import com.lagradost.cloudstream3.extractors.UpstreamExtractor import com.lagradost.cloudstream3.extractors.Uqload @@ -1223,6 +1225,8 @@ val extractorApis: MutableList = arrayListOf( VkExtractor(), Bysezejataos(), ByseSX(), + Up4Stream(), + Up4FunTop() ) From 5e54552338eca91ec7b792e54dd0e5da28d17bf5 Mon Sep 17 00:00:00 2001 From: rockhero1234 <149141736+rockhero1234@users.noreply.github.com> Date: Sun, 4 Jan 2026 15:59:04 +0530 Subject: [PATCH 238/513] remove check icon in tvtype chips (#2363) --- app/src/main/res/values/styles.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index eb5a57c03..8cf61eaea 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -102,6 +102,7 @@ @font/google_sans @string/tv_no_focus_tag 0dp + false + + +