Merge branch 'master' of https://github.com/recloudstream/cloudstream into recloudstream-master

# Conflicts:
#	app/src/main/ic_launcher-playstore.png
#	app/src/main/res/mipmap-hdpi/ic_launcher.png
#	app/src/main/res/mipmap-hdpi/ic_launcher_round.png
#	app/src/main/res/mipmap-mdpi/ic_launcher.png
#	app/src/main/res/mipmap-mdpi/ic_launcher_round.png
#	app/src/main/res/mipmap-xhdpi/ic_launcher.png
#	app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
#	app/src/main/res/mipmap-xxhdpi/ic_launcher.png
#	app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
#	app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
#	app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
#	app/src/prerelease/ic_launcher-playstore.png
#	app/src/prerelease/res/mipmap-hdpi/ic_launcher.png
#	app/src/prerelease/res/mipmap-hdpi/ic_launcher_round.png
#	app/src/prerelease/res/mipmap-mdpi/ic_launcher.png
#	app/src/prerelease/res/mipmap-mdpi/ic_launcher_round.png
#	app/src/prerelease/res/mipmap-xhdpi/ic_launcher.png
#	app/src/prerelease/res/mipmap-xhdpi/ic_launcher_round.png
#	app/src/prerelease/res/mipmap-xxhdpi/ic_launcher.png
#	app/src/prerelease/res/mipmap-xxhdpi/ic_launcher_round.png
#	app/src/prerelease/res/mipmap-xxxhdpi/ic_launcher.png
#	app/src/prerelease/res/mipmap-xxxhdpi/ic_launcher_round.png
This commit is contained in:
KillerDogeEmpire 2022-09-22 15:18:58 -07:00
commit c49c34ee92
31 changed files with 167 additions and 19 deletions

BIN
.github/downloads.jpg vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 58 KiB

BIN
.github/home.jpg vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 137 KiB

After

Width:  |  Height:  |  Size: 136 KiB

BIN
.github/player.jpg vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 48 KiB

BIN
.github/results.jpg vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 96 KiB

BIN
.github/search.jpg vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -150,7 +150,11 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
* @return true if the str has launched an app task (be it successful or not)
* @param isWebview does not handle providers and opening download page if true. Can still add repos and login.
* */
fun handleAppIntentUrl(activity: FragmentActivity?, str: String?, isWebview: Boolean): Boolean =
fun handleAppIntentUrl(
activity: FragmentActivity?,
str: String?,
isWebview: Boolean
): Boolean =
with(activity) {
if (str != null && this != null) {
if (str.startsWith("https://cs.repo")) {
@ -191,7 +195,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
val url = str.replaceFirst(appStringRepo, "https")
loadRepository(url)
return true
} else if (!isWebview){
} else if (!isWebview) {
if (str.startsWith(DOWNLOAD_NAVIGATE_TO)) {
this.navigate(R.id.navigation_downloads)
return true
@ -565,9 +569,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
for (api in accountManagers) {
api.init()
}
}
ioSafe {
inAppAuths.apmap { api ->
try {
api.initialize()

View File

@ -1,13 +1,19 @@
package com.lagradost.cloudstream3.plugins
import android.app.*
import dalvik.system.PathClassLoader
import com.google.gson.Gson
import android.content.res.AssetManager
import android.content.res.Resources
import android.os.Environment
import android.widget.Toast
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Build
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.net.toUri
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
@ -25,7 +31,9 @@ import com.lagradost.cloudstream3.MainActivity.Companion.afterPluginsLoadedEvent
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.plugins.RepositoryManager.PREBUILT_REPOSITORIES
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
import com.lagradost.cloudstream3.utils.extractorApis
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
@ -38,6 +46,9 @@ import java.util.*
const val PLUGINS_KEY = "PLUGINS_KEY"
const val PLUGINS_KEY_LOCAL = "PLUGINS_KEY_LOCAL"
const val EXTENSIONS_CHANNEL_ID = "cloudstream3.extensions"
const val EXTENSIONS_CHANNEL_NAME = "Extensions"
const val EXTENSIONS_CHANNEL_DESCRIPT = "Extension notification channel"
// Data class for internal storage
data class PluginData(
@ -78,6 +89,8 @@ object PluginManager {
const val TAG = "PluginManager"
private var hasCreatedNotChanel = false
/**
* Store data about the plugin for fetching later
* */
@ -220,8 +233,11 @@ object PluginManager {
"Outdated plugins: ${outdatedPlugins.filter { it.isOutdated }}"
}
val updatedPlugins = mutableListOf<String>()
outdatedPlugins.apmap { pluginData ->
if (pluginData.isDisabled) {
//updatedPlugins.add(activity.getString(R.string.single_plugin_disabled, pluginData.onlineData.second.name))
unloadPlugin(pluginData.savedData.filePath)
} else if (pluginData.isOutdated) {
downloadAndLoadPlugin(
@ -229,10 +245,17 @@ object PluginManager {
pluginData.onlineData.second.url,
pluginData.savedData.internalName,
pluginData.onlineData.first
)
).let { success ->
if (success)
updatedPlugins.add(pluginData.onlineData.second.name)
}
}
}
main {
createNotification(activity, updatedPlugins)
}
ioSafe {
afterPluginsLoadedEvent.invoke(true)
}
@ -438,4 +461,59 @@ object PluginManager {
false
}
}
private fun Context.createNotificationChannel() {
hasCreatedNotChanel = true
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = EXTENSIONS_CHANNEL_NAME //getString(R.string.channel_name)
val descriptionText = EXTENSIONS_CHANNEL_DESCRIPT//getString(R.string.channel_description)
val importance = NotificationManager.IMPORTANCE_LOW
val channel = NotificationChannel(EXTENSIONS_CHANNEL_ID, name, importance).apply {
description = descriptionText
}
// Register the channel with the system
val notificationManager: NotificationManager =
this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
private fun createNotification(
context: Context,
extensionNames: List<String>
): Notification? {
try {
if (extensionNames.isEmpty()) return null
val content = extensionNames.joinToString(", ")
// main { // DON'T WANT TO SLOW IT DOWN
val builder = NotificationCompat.Builder(context, EXTENSIONS_CHANNEL_ID)
.setAutoCancel(false)
.setColorized(true)
.setOnlyAlertOnce(true)
.setSilent(true)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setColor(context.colorFromAttribute(R.attr.colorPrimary))
.setContentTitle(context.getString(R.string.plugins_updated, extensionNames.size))
.setSmallIcon(R.drawable.ic_baseline_extension_24)
.setStyle(NotificationCompat.BigTextStyle()
.bigText(content))
.setContentText(content)
if (!hasCreatedNotChanel) {
context.createNotificationChannel()
}
val notification = builder.build()
with(NotificationManagerCompat.from(context)) {
// notificationId is a unique int for each notification that you must define
notify((System.currentTimeMillis()/1000).toInt(), notification)
}
return notification
} catch (e: Exception) {
logError(e)
return null
}
}
}

View File

@ -40,13 +40,15 @@ class WebviewFragment : Fragment() {
return super.shouldOverrideUrlLoading(view, request)
}
}
WebViewResolver.webViewUserAgent = web_view.settings.userAgentString
web_view.addJavascriptInterface(RepoApi(activity), "RepoApi")
web_view.settings.javaScriptEnabled = true
web_view.settings.userAgentString = USER_AGENT
web_view.settings.domStorageEnabled = true
// WebView.setWebContentsDebuggingEnabled(true)
WebViewResolver.webViewUserAgent = web_view.settings.userAgentString
// web_view.settings.userAgentString = USER_AGENT
web_view.loadUrl(url)
}

View File

@ -611,6 +611,7 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
player_lock?.isGone = !isShowing
//player_media_route_button?.isClickable = !isGone
player_go_back_holder?.isGone = isGone
player_sources_btt?.isGone = isGone
}
private fun updateLockUI() {

View File

@ -60,7 +60,7 @@ class EpisodeAdapter(
private val clickCallback: (EpisodeClickEvent) -> Unit,
private val downloadClickCallback: (DownloadClickEvent) -> Unit,
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var cardList: MutableList<ResultEpisode> = mutableListOf()
var cardList: MutableList<ResultEpisode> = mutableListOf()
private val mBoundViewHolders: HashSet<DownloadButtonViewHolder> = HashSet()
private fun getAllBoundViewHolders(): Set<DownloadButtonViewHolder?>? {
@ -239,7 +239,6 @@ class EpisodeAdapter(
itemView.setOnLongClickListener {
clickCallback.invoke(EpisodeClickEvent(ACTION_SHOW_OPTIONS, card))
return@setOnLongClickListener true
}

View File

@ -95,6 +95,7 @@ import kotlinx.android.synthetic.main.fragment_result.result_vpn
import kotlinx.android.synthetic.main.fragment_result_swipe.*
import kotlinx.android.synthetic.main.fragment_result_tv.*
import kotlinx.android.synthetic.main.result_sync.*
import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking
@ -293,7 +294,7 @@ open class ResultFragment : ResultTrailerPlayer() {
result_reload_connection_open_in_browser?.isVisible = true
}
2 -> {
result_bookmark_fab?.isGone = isTvSettings()
result_bookmark_fab?.isGone = isTrueTvSettings()
result_bookmark_fab?.extend()
//if (result_bookmark_button?.context?.isTrueTvSettings() == true) {
// when {
@ -412,7 +413,39 @@ open class ResultFragment : ResultTrailerPlayer() {
is ResourceSome.Success -> {
result_episodes?.isVisible = true
result_episode_loading?.isVisible = false
/*
* Okay so what is this fuckery?
* Basically Android TV will crash if you request a new focus while
* the adapter gets updated.
*
* This means that if you load thumbnails and request a next focus at the same time
* the app will crash without any way to catch it!
*
* How to bypass this?
* This code basically steals the focus for 500ms and puts it in an inescapable view
* then lets out the focus by requesting focus to result_episodes
*/
// Do not use this.isTv, that is the player
val isTv = isTvSettings()
val hasEpisodes =
!(result_episodes?.adapter as? EpisodeAdapter?)?.cardList.isNullOrEmpty()
if (isTv && hasEpisodes) {
// Make it impossible to focus anywhere else!
temporary_no_focus?.isFocusable = true
temporary_no_focus?.requestFocus()
}
(result_episodes?.adapter as? EpisodeAdapter?)?.updateList(episodes.value)
if (isTv && hasEpisodes) main {
delay(500)
temporary_no_focus?.isFocusable = false
// This might make some people sad as it changes the focus when leaving an episode :(
result_episodes?.requestFocus()
}
}
}
}
@ -458,7 +491,14 @@ open class ResultFragment : ResultTrailerPlayer() {
val storedData = getStoredData(activity ?: context ?: return) ?: return
//viewModel.clear()
viewModel.load(activity, storedData.url ?: return, storedData.apiName, storedData.showFillers, storedData.dubStatus, storedData.start)
viewModel.load(
activity,
storedData.url ?: return,
storedData.apiName,
storedData.showFillers,
storedData.dubStatus,
storedData.start
)
}
}
@ -916,7 +956,14 @@ open class ResultFragment : ResultTrailerPlayer() {
if (storedData?.url != null) {
result_reload_connectionerror.setOnClickListener {
viewModel.load(activity, storedData.url, storedData.apiName, storedData.showFillers, storedData.dubStatus, storedData.start)
viewModel.load(
activity,
storedData.url,
storedData.apiName,
storedData.showFillers,
storedData.dubStatus,
storedData.start
)
}
result_reload_connection_open_in_browser?.setOnClickListener {
@ -952,7 +999,14 @@ open class ResultFragment : ResultTrailerPlayer() {
if (restart || !viewModel.hasLoaded()) {
//viewModel.clear()
viewModel.load(activity, storedData.url, storedData.apiName, storedData.showFillers, storedData.dubStatus, storedData.start)
viewModel.load(
activity,
storedData.url,
storedData.apiName,
storedData.showFillers,
storedData.dubStatus,
storedData.start
)
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

View File

@ -420,14 +420,14 @@
<FrameLayout
android:nextFocusRight="@id/result_bookmark_button"
android:id="@+id/result_movie_progress_downloaded_holder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:layout_weight="1"
android:minWidth="250dp">
android:minWidth="250dp"
android:nextFocusRight="@id/result_bookmark_button">
<com.google.android.material.button.MaterialButton
android:id="@+id/result_download_movie"
@ -510,17 +510,17 @@
</FrameLayout>
<com.google.android.material.button.MaterialButton
android:nextFocusLeft="@id/result_movie_progress_downloaded_holder"
android:nextFocusDown="@id/result_resume_series_button_play"
android:id="@+id/result_bookmark_button"
style="@style/BlackButton"
android:layout_width="wrap_content"
android:layout_marginStart="5dp"
android:layout_marginEnd="5dp"
android:layout_marginBottom="10dp"
android:layout_weight="1"
android:minWidth="250dp"
android:nextFocusLeft="@id/result_movie_progress_downloaded_holder"
android:nextFocusDown="@id/result_resume_series_button_play"
android:text="@string/type_none"
android:visibility="visible" />
</LinearLayout>
@ -753,6 +753,16 @@
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
tools:listitem="@layout/result_episode" />
<View
android:id="@+id/temporary_no_focus"
android:layout_width="1dp"
android:layout_height="1dp"
android:focusable="false"
android:nextFocusLeft="@id/temporary_no_focus"
android:nextFocusRight="@id/temporary_no_focus"
android:nextFocusUp="@id/temporary_no_focus"
android:nextFocusDown="@id/temporary_no_focus" />
</LinearLayout>
</LinearLayout>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

View File

@ -455,4 +455,5 @@
<string name="extension_types">Wspierane</string>
<string name="extension_language">Język</string>
<string name="extension_install_first">Najpierw zainstaluj rozszerzenie</string>
<string name="plugins_updated">Zaaktualizowano %d rozszerzeń</string>
</resources>

View File

@ -601,6 +601,7 @@
<string name="plugins_downloaded" formatted="true">Downloaded: %d</string>
<string name="plugins_disabled" formatted="true">Disabled: %d</string>
<string name="plugins_not_downloaded" formatted="true">Not downloaded: %d</string>
<string name="plugins_updated" formatted="true">Updated %d plugins</string>
<string name="blank_repo_message">Add a repository to install site extensions</string>
<string name="view_public_repositories_button">View community repositories</string>
<string name="view_public_repositories_button_short">Public list</string>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB