mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Merge remote-tracking branch 'origin/master' into gradle
# Conflicts: # app/build.gradle.kts
This commit is contained in:
commit
69615d093e
17 changed files with 171 additions and 79 deletions
|
@ -233,6 +233,7 @@ dependencies {
|
|||
implementation("androidx.work:work-runtime:2.9.0")
|
||||
implementation("androidx.work:work-runtime-ktx:2.9.0")
|
||||
implementation("com.github.Blatzar:NiceHttp:0.4.11") // HTTP Lib
|
||||
implementation("com.github.Blatzar:NiceHttp:0.4.11") // HTTP Lib
|
||||
}
|
||||
|
||||
tasks.register<Exec>("retrieveCommitHash") {
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.lagradost.cloudstream3.extractors
|
|||
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.base64Decode
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
|
||||
open class Acefile : ExtractorApi() {
|
||||
|
@ -16,22 +15,19 @@ open class Acefile : ExtractorApi() {
|
|||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val script = getAndUnpack(app.get(url).text)
|
||||
val id = script.substringAfter("\"code\":\"").substringBefore("\",")
|
||||
val doc = app.get("https://drive.google.com/uc?id=${base64Decode(id)}&export=download").document
|
||||
val form = doc.select("form#download-form").attr("action")
|
||||
val uc = doc.select("input#uc-download-link").attr("value")
|
||||
val video = app.post(
|
||||
form, data = mapOf(
|
||||
"uc-download-link" to uc
|
||||
)
|
||||
).url
|
||||
val id = "/(?:d|download|player|f|file)/(\\w+)".toRegex().find(url)?.groupValues?.get(1)
|
||||
val script = getAndUnpack(app.get("$mainUrl/player/${id ?: return}").text)
|
||||
val service = """service\s*=\s*['"]([^'"]+)""".toRegex().find(script)?.groupValues?.get(1)
|
||||
val serverUrl = """['"](\S+check&id\S+?)['"]""".toRegex().find(script)?.groupValues?.get(1)
|
||||
?.replace("\"+service+\"", service ?: return)
|
||||
|
||||
val video = app.get(serverUrl ?: return, referer = "$mainUrl/").parsedSafe<Source>()?.data
|
||||
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
this.name,
|
||||
video,
|
||||
video ?: return,
|
||||
"",
|
||||
Qualities.Unknown.value,
|
||||
INFER_TYPE
|
||||
|
@ -40,4 +36,8 @@ open class Acefile : ExtractorApi() {
|
|||
|
||||
}
|
||||
|
||||
data class Source(
|
||||
val data: String? = null,
|
||||
)
|
||||
|
||||
}
|
|
@ -49,8 +49,23 @@ open class Chillx : ExtractorApi() {
|
|||
val decrypt = cryptoAESHandler(master ?: return, getKey().toByteArray(), false)?.replace("\\", "") ?: throw ErrorLoadingException("failed to decrypt")
|
||||
|
||||
val source = Regex(""""?file"?:\s*"([^"]+)""").find(decrypt)?.groupValues?.get(1)
|
||||
val tracks = Regex("""tracks:\s*\[(.+)]""").find(decrypt)?.groupValues?.get(1)
|
||||
|
||||
val subtitles = Regex("""subtitle"?:\s*"([^"]+)""").find(decrypt)?.groupValues?.get(1)
|
||||
val subtitlePattern = """\[(.*?)\](https?://[^\s,]+)""".toRegex()
|
||||
val matches = subtitlePattern.findAll(subtitles ?: "")
|
||||
val languageUrlPairs = matches.map { matchResult ->
|
||||
val (language, url) = matchResult.destructured
|
||||
decodeUnicodeEscape(language) to url
|
||||
}.toList()
|
||||
|
||||
languageUrlPairs.forEach{ (name, file) ->
|
||||
subtitleCallback.invoke(
|
||||
SubtitleFile(
|
||||
name,
|
||||
file
|
||||
)
|
||||
)
|
||||
}
|
||||
// required
|
||||
val headers = mapOf(
|
||||
"Accept" to "*/*",
|
||||
|
@ -67,16 +82,13 @@ open class Chillx : ExtractorApi() {
|
|||
"$mainUrl/",
|
||||
headers = headers
|
||||
).forEach(callback)
|
||||
}
|
||||
|
||||
AppUtils.tryParseJson<List<Tracks>>("[$tracks]")
|
||||
?.filter { it.kind == "captions" }?.map { track ->
|
||||
subtitleCallback.invoke(
|
||||
SubtitleFile(
|
||||
track.label ?: "",
|
||||
track.file ?: return@map null
|
||||
)
|
||||
)
|
||||
}
|
||||
private fun decodeUnicodeEscape(input: String): String {
|
||||
val regex = Regex("u([0-9a-fA-F]{4})")
|
||||
return regex.replace(input) {
|
||||
it.groupValues[1].toInt(16).toChar().toString()
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getKey() = key ?: fetchKey().also { key = it }
|
||||
|
|
|
@ -22,9 +22,9 @@ open class Gofile : ExtractorApi() {
|
|||
val id = Regex("/(?:\\?c=|d/)([\\da-zA-Z-]+)").find(url)?.groupValues?.get(1)
|
||||
val token = app.get("$mainApi/createAccount").parsedSafe<Account>()?.data?.get("token")
|
||||
val websiteToken = app.get("$mainUrl/dist/js/alljs.js").text.let {
|
||||
Regex("websiteToken\\s*=\\s*\"([^\"]+)").find(it)?.groupValues?.get(1)
|
||||
Regex("fetchData.wt\\s*=\\s*\"([^\"]+)").find(it)?.groupValues?.get(1)
|
||||
}
|
||||
app.get("$mainApi/getContent?contentId=$id&token=$token&websiteToken=$websiteToken")
|
||||
app.get("$mainApi/getContent?contentId=$id&token=$token&wt=$websiteToken")
|
||||
.parsedSafe<Source>()?.data?.contents?.forEach {
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
|
|
|
@ -11,3 +11,13 @@ class FourCX : ContentX() {
|
|||
override var name = "FourCX"
|
||||
override var mainUrl = "https://four.contentx.me"
|
||||
}
|
||||
|
||||
class PlayRu : ContentX() {
|
||||
override var name = "PlayRu"
|
||||
override var mainUrl = "https://playru.net"
|
||||
}
|
||||
|
||||
class FourPlayRu : ContentX() {
|
||||
override var name = "FourPlayRu"
|
||||
override var mainUrl = "https://four.playru.net"
|
||||
}
|
|
@ -5,6 +5,7 @@ import com.lagradost.cloudstream3.ErrorLoadingException
|
|||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.base64DecodeArray
|
||||
import com.lagradost.cloudstream3.base64Encode
|
||||
import com.lagradost.cloudstream3.utils.AppUtils
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
|
@ -16,13 +17,52 @@ import javax.crypto.Cipher
|
|||
import javax.crypto.spec.IvParameterSpec
|
||||
import javax.crypto.spec.SecretKeySpec
|
||||
|
||||
// Code found in https://github.com/theonlymo/keys
|
||||
// special credits to @theonlymo for providing key
|
||||
class Megacloud : Rabbitstream() {
|
||||
override val name = "Megacloud"
|
||||
override val mainUrl = "https://megacloud.tv"
|
||||
override val embed = "embed-2/ajax/e-1"
|
||||
override val key = "https://raw.githubusercontent.com/theonlymo/keys/e1/key"
|
||||
private val scriptUrl = "$mainUrl/js/player/a/prod/e1-player.min.js"
|
||||
|
||||
override suspend fun extractRealKey(sources: String): Pair<String, String> {
|
||||
val rawKeys = getKeys()
|
||||
val sourcesArray = sources.toCharArray()
|
||||
|
||||
var extractedKey = ""
|
||||
var currentIndex = 0
|
||||
for (index in rawKeys) {
|
||||
val start = index[0] + currentIndex
|
||||
val end = start + index[1]
|
||||
for (i in start until end) {
|
||||
extractedKey += sourcesArray[i].toString()
|
||||
sourcesArray[i] = ' '
|
||||
}
|
||||
currentIndex += index[1]
|
||||
}
|
||||
|
||||
return extractedKey to sourcesArray.joinToString("").replace(" ", "")
|
||||
}
|
||||
|
||||
private suspend fun getKeys(): List<List<Int>> {
|
||||
val script = app.get(scriptUrl).text
|
||||
fun matchingKey(value: String): String {
|
||||
return Regex(",$value=((?:0x)?([0-9a-fA-F]+))").find(script)?.groupValues?.get(1)
|
||||
?.removePrefix("0x") ?: throw ErrorLoadingException("Failed to match the key")
|
||||
}
|
||||
|
||||
val regex = Regex("case\\s*0x[0-9a-f]+:(?![^;]*=partKey)\\s*\\w+\\s*=\\s*(\\w+)\\s*,\\s*\\w+\\s*=\\s*(\\w+);")
|
||||
val indexPairs = regex.findAll(script).toList().map { match ->
|
||||
val matchKey1 = matchingKey(match.groupValues[1])
|
||||
val matchKey2 = matchingKey(match.groupValues[2])
|
||||
try {
|
||||
listOf(matchKey1.toInt(16), matchKey2.toInt(16))
|
||||
} catch (e: NumberFormatException) {
|
||||
emptyList()
|
||||
}
|
||||
}.filter { it.isNotEmpty() }
|
||||
|
||||
return indexPairs
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Dokicloud : Rabbitstream() {
|
||||
|
@ -30,12 +70,14 @@ class Dokicloud : Rabbitstream() {
|
|||
override val mainUrl = "https://dokicloud.one"
|
||||
}
|
||||
|
||||
// Code found in https://github.com/eatmynerds/key
|
||||
// special credits to @eatmynerds for providing key
|
||||
open class Rabbitstream : ExtractorApi() {
|
||||
override val name = "Rabbitstream"
|
||||
override val mainUrl = "https://rabbitstream.net"
|
||||
override val requiresReferer = false
|
||||
open val embed = "ajax/embed-4"
|
||||
open val key = "https://raw.githubusercontent.com/theonlymo/keys/e4/key"
|
||||
open val key = "https://raw.githubusercontent.com/eatmynerds/key/e4/key.txt"
|
||||
|
||||
override suspend fun getUrl(
|
||||
url: String,
|
||||
|
@ -56,7 +98,7 @@ open class Rabbitstream : ExtractorApi() {
|
|||
val decryptedSources = if (sources == null || encryptedMap.encrypted == false) {
|
||||
response.parsedSafe()
|
||||
} else {
|
||||
val (key, encData) = extractRealKey(sources, getRawKey())
|
||||
val (key, encData) = extractRealKey(sources)
|
||||
val decrypted = decryptMapped<List<Sources>>(encData, key)
|
||||
SourcesResponses(
|
||||
sources = decrypted,
|
||||
|
@ -75,8 +117,8 @@ open class Rabbitstream : ExtractorApi() {
|
|||
decryptedSources?.tracks?.map { track ->
|
||||
subtitleCallback.invoke(
|
||||
SubtitleFile(
|
||||
track?.label ?: "",
|
||||
track?.file ?: return@map
|
||||
track?.label ?: return@map,
|
||||
track.file ?: return@map
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -84,25 +126,10 @@ open class Rabbitstream : ExtractorApi() {
|
|||
|
||||
}
|
||||
|
||||
private suspend fun getRawKey(): String = app.get(key).text
|
||||
|
||||
private fun extractRealKey(sources: String, stops: String): Pair<String, String> {
|
||||
val decryptKey = parseJson<List<List<Int>>>(stops)
|
||||
val sourcesArray = sources.toCharArray()
|
||||
|
||||
var extractedKey = ""
|
||||
var currentIndex = 0
|
||||
for (index in decryptKey) {
|
||||
val start = index[0] + currentIndex
|
||||
val end = start + index[1]
|
||||
for (i in start until end) {
|
||||
extractedKey += sourcesArray[i].toString()
|
||||
sourcesArray[i] = ' '
|
||||
}
|
||||
currentIndex += index[1]
|
||||
}
|
||||
|
||||
return extractedKey to sourcesArray.joinToString("")
|
||||
open suspend fun extractRealKey(sources: String): Pair<String, String> {
|
||||
val rawKeys = parseJson<List<Int>>(app.get(key).text)
|
||||
val extractedKey = base64Encode(rawKeys.map { it.toByte() }.toByteArray())
|
||||
return extractedKey to sources
|
||||
}
|
||||
|
||||
private inline fun <reified T> decryptMapped(input: String, key: String): T? {
|
||||
|
|
|
@ -31,6 +31,7 @@ import java.net.URI
|
|||
* @param useOkhttp will try to use the okhttp client as much as possible, but this might cause some requests to fail. Disable for cloudflare.
|
||||
* @param script pass custom js to execute
|
||||
* @param scriptCallback will be called with the result from custom js
|
||||
* @param timeout close webview after timeout
|
||||
* */
|
||||
class WebViewResolver(
|
||||
val interceptUrl: Regex,
|
||||
|
@ -38,18 +39,29 @@ class WebViewResolver(
|
|||
val userAgent: String? = USER_AGENT,
|
||||
val useOkhttp: Boolean = true,
|
||||
val script: String? = null,
|
||||
val scriptCallback: ((String) -> Unit)? = null
|
||||
val scriptCallback: ((String) -> Unit)? = null,
|
||||
val timeout: Long = DEFAULT_TIMEOUT
|
||||
) :
|
||||
Interceptor {
|
||||
|
||||
constructor(
|
||||
interceptUrl: Regex,
|
||||
additionalUrls: List<Regex> = emptyList(),
|
||||
userAgent: String? = USER_AGENT,
|
||||
useOkhttp: Boolean = true,
|
||||
script: String? = null,
|
||||
scriptCallback: ((String) -> Unit)? = null,
|
||||
) : this(interceptUrl, additionalUrls, userAgent, useOkhttp, script, scriptCallback, DEFAULT_TIMEOUT)
|
||||
|
||||
constructor(
|
||||
interceptUrl: Regex,
|
||||
additionalUrls: List<Regex> = emptyList(),
|
||||
userAgent: String? = USER_AGENT,
|
||||
useOkhttp: Boolean = true
|
||||
) : this(interceptUrl, additionalUrls, userAgent, useOkhttp, null, null)
|
||||
) : this(interceptUrl, additionalUrls, userAgent, useOkhttp, null, null, DEFAULT_TIMEOUT)
|
||||
|
||||
companion object {
|
||||
private const val DEFAULT_TIMEOUT = 60_000L
|
||||
var webViewUserAgent: String? = null
|
||||
|
||||
@JvmName("getWebViewUserAgent1")
|
||||
|
@ -262,7 +274,7 @@ class WebViewResolver(
|
|||
|
||||
var loop = 0
|
||||
// Timeouts after this amount, 60s
|
||||
val totalTime = 60000L
|
||||
val totalTime = timeout
|
||||
|
||||
val delayTime = 100L
|
||||
|
||||
|
|
|
@ -317,7 +317,7 @@ class HomeParentItemAdapterPreview(
|
|||
homePreviewText.text = item.name
|
||||
populateChips(
|
||||
homePreviewTags,
|
||||
item.tags ?: emptyList(),
|
||||
item.tags?.take(6) ?: emptyList(),
|
||||
R.style.ChipFilledSemiTransparent
|
||||
)
|
||||
|
||||
|
|
|
@ -681,6 +681,7 @@ open class ResultFragmentPhone : FullScreenPlayer() {
|
|||
resultMetaYear.setText(d.yearText)
|
||||
resultMetaDuration.setText(d.durationText)
|
||||
resultMetaRating.setText(d.ratingText)
|
||||
resultMetaStatus.setText(d.onGoingText)
|
||||
resultMetaContentRating.setText(d.contentRatingText)
|
||||
resultCastText.setText(d.actorsText)
|
||||
resultNextAiring.setText(d.nextAiringEpisode)
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
package com.lagradost.cloudstream3.ui.settings.extensions
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.lagradost.cloudstream3.CommonActivity.activity
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.databinding.RepositoryItemBinding
|
||||
import com.lagradost.cloudstream3.databinding.RepositoryItemTvBinding
|
||||
|
@ -112,6 +119,17 @@ class RepoAdapter(
|
|||
repositoryItemRoot.setOnClickListener {
|
||||
clickCallback(repositoryData)
|
||||
}
|
||||
|
||||
repositoryItemRoot.setOnLongClickListener {
|
||||
val clipboardManager =
|
||||
activity?.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager?
|
||||
clipboardManager?.setPrimaryClip(ClipData.newPlainText("RepoUrl", repositoryData.url))
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
|
||||
showToast(R.string.copyRepoUrl, Toast.LENGTH_SHORT)
|
||||
}
|
||||
return@setOnLongClickListener true
|
||||
}
|
||||
|
||||
mainText.text = repositoryData.name
|
||||
subText.text = repositoryData.url
|
||||
}
|
||||
|
|
|
@ -106,6 +106,8 @@ import com.lagradost.cloudstream3.extractors.ContentX
|
|||
import com.lagradost.cloudstream3.extractors.EmturbovidExtractor
|
||||
import com.lagradost.cloudstream3.extractors.Hotlinger
|
||||
import com.lagradost.cloudstream3.extractors.FourCX
|
||||
import com.lagradost.cloudstream3.extractors.PlayRu
|
||||
import com.lagradost.cloudstream3.extractors.FourPlayRu
|
||||
import com.lagradost.cloudstream3.extractors.HDMomPlayer
|
||||
import com.lagradost.cloudstream3.extractors.HDPlayerSystem
|
||||
import com.lagradost.cloudstream3.extractors.VideoSeyred
|
||||
|
@ -704,6 +706,8 @@ val extractorApis: MutableList<ExtractorApi> = arrayListOf(
|
|||
ContentX(),
|
||||
Hotlinger(),
|
||||
FourCX(),
|
||||
PlayRu(),
|
||||
FourPlayRu(),
|
||||
HDMomPlayer(),
|
||||
HDPlayerSystem(),
|
||||
VideoSeyred(),
|
||||
|
|
|
@ -137,7 +137,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="5"
|
||||
android:maxLines="3"
|
||||
android:paddingBottom="5dp"
|
||||
android:textSize="15sp"
|
||||
tools:text="very nice tv series" />
|
||||
|
|
|
@ -83,7 +83,7 @@
|
|||
android:layout_height="25dp"
|
||||
android:layout_margin="5dp"
|
||||
android:elevation="10dp"
|
||||
|
||||
android:tooltipText="@string/subscribe_tooltip"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/baseline_notifications_none_24"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
|
@ -100,7 +100,7 @@
|
|||
android:layout_height="25dp"
|
||||
android:layout_margin="5dp"
|
||||
android:elevation="10dp"
|
||||
|
||||
android:tooltipText="@string/action_add_to_favorites"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_baseline_favorite_border_24"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
|
@ -117,7 +117,7 @@
|
|||
android:layout_height="25dp"
|
||||
android:layout_margin="5dp"
|
||||
android:elevation="10dp"
|
||||
|
||||
android:tooltipText="@string/result_share"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_outline_share_24"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
|
@ -135,7 +135,7 @@
|
|||
android:layout_height="25dp"
|
||||
android:layout_margin="5dp"
|
||||
android:elevation="10dp"
|
||||
|
||||
android:tooltipText="@string/result_open_in_browser"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/ic_baseline_public_24"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
|
@ -153,7 +153,7 @@
|
|||
android:layout_height="30dp"
|
||||
android:layout_margin="5dp"
|
||||
android:elevation="10dp"
|
||||
|
||||
android:tooltipText="@string/result_search_tooltip"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/search_icon"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
|
@ -171,7 +171,7 @@
|
|||
android:layout_height="25dp"
|
||||
android:layout_margin="5dp"
|
||||
android:elevation="10dp"
|
||||
|
||||
android:tooltipText="@string/recommendations_tooltip"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:src="@drawable/baseline_list_alt_24"
|
||||
android:layout_gravity="end|center_vertical"
|
||||
|
|
|
@ -387,6 +387,7 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
<com.lagradost.cloudstream3.widget.FlowLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="5dp"
|
||||
app:itemSpacing="10dp">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
|
@ -399,6 +400,7 @@ https://developer.android.com/design/ui/tv/samples/jet-fit
|
|||
android:id="@+id/result_meta_content_rating"
|
||||
android:layout_gravity="center_vertical"
|
||||
style="@style/SmallWhiteButton"
|
||||
android:focusable="false"
|
||||
tools:text="PG-13" />
|
||||
|
||||
<TextView
|
||||
|
|
|
@ -148,7 +148,7 @@
|
|||
<string name="download_done">Download Done</string>
|
||||
<string name="download_format" translatable="false">%s - %s</string>
|
||||
<string name="update_started">Update Started</string>
|
||||
<string name="stream">Stream</string>
|
||||
<string name="stream">Network stream</string>
|
||||
<string name="error_loading_links_toast">Error Loading Links</string>
|
||||
<string name="links_reloaded_toast">Links Reloaded</string>
|
||||
<string name="download_storage_text">Internal Storage</string>
|
||||
|
@ -174,6 +174,10 @@
|
|||
<string name="sort_clear">Clear</string>
|
||||
<string name="sort_save">Save</string>
|
||||
<string name="copyTitle">Title copied!</string>
|
||||
<string name="copyRepoUrl">Repo URL copied!</string>
|
||||
<string name="subscribe_tooltip">New episode notification</string>
|
||||
<string name="result_search_tooltip">Search in other extensions</string>
|
||||
<string name="recommendations_tooltip">Show recommendations</string>
|
||||
<string name="player_speed">Player Speed</string>
|
||||
<string name="subtitles_settings">Subtitle Settings</string>
|
||||
<string name="subs_text_color">Text Color</string>
|
||||
|
@ -213,8 +217,8 @@
|
|||
<string name="player_subtitles_settings_des">Player subtitles settings</string>
|
||||
<string name="chromecast_subtitles_settings">Chromecast Subtitles</string>
|
||||
<string name="chromecast_subtitles_settings_des">Chromecast subtitles settings</string>
|
||||
<string name="eigengraumode_settings">Eigengravy Mode</string>
|
||||
<string name="eigengraumode_settings_des">Adds a speed option in the player</string>
|
||||
<string name="eigengraumode_settings">Playback speed</string>
|
||||
<string name="speed_setting_summary">Adds a speed option in the player</string>
|
||||
<string name="swipe_to_seek_settings">Swipe to seek</string>
|
||||
<string name="swipe_to_seek_settings_des">Swipe from side to side to control your position in a video</string>
|
||||
<string name="swipe_to_change_settings">Swipe to change settings</string>
|
||||
|
@ -391,9 +395,9 @@
|
|||
<string name="video_disk_description">Causes problems if set too high on devices with low storage space, such as Android TV.</string>
|
||||
<string name="dns_pref">DNS over HTTPS</string>
|
||||
<string name="dns_pref_summary">Useful for bypassing ISP blocks</string>
|
||||
<string name="jsdelivr_proxy">raw.githubusercontent.com Proxy</string>
|
||||
<string name="jsdelivr_proxy">GitHub Proxy</string>
|
||||
<string name="jsdelivr_enabled">Could not reach GitHub. Turning on jsDelivr proxy…</string>
|
||||
<string name="jsdelivr_proxy_summary">Bypasses blocking of GitHub using jsDelivr. May cause updates to be delayed by few days.</string>
|
||||
<string name="jsdelivr_proxy_summary">Bypass blocking of raw github URLs using jsDelivr. May cause updates to be delayed by few days.</string>
|
||||
<string name="add_site_pref">Clone site</string>
|
||||
<string name="remove_site_pref">Remove site</string>
|
||||
<string name="add_site_summary">Add a clone of an existing site, with a different URL</string>
|
||||
|
@ -439,13 +443,15 @@
|
|||
<string name="category_general">General</string>
|
||||
<string name="random_button_settings">Random Button</string>
|
||||
<string name="random_button_settings_desc">Show random button on Homepage and Library</string>
|
||||
<string name="provider_lang_settings">Provider languages</string>
|
||||
<string name="provider_lang_settings">Extension languages</string>
|
||||
<string name="app_layout">App Layout</string>
|
||||
<string name="preferred_media_settings">Preferred media</string>
|
||||
<string name="enable_nsfw_on_providers">Enable NSFW on supported providers</string>
|
||||
<string name="enable_nsfw_on_providers">Enable NSFW on supported Extensions</string>
|
||||
<string name="subtitles_encoding">Subtitle encoding</string>
|
||||
<string name="category_providers">Providers</string>
|
||||
<string name="category_provider_test">Provider test</string>
|
||||
<string name="test_extensions">Test all Extensions</string>
|
||||
<string name="test_extensions_summary">This Test is meant for developers only and does not verifies or denies working of any extension.</string>
|
||||
<string name="category_ui">Layout</string>
|
||||
<string name="automatic">Auto</string>
|
||||
<string name="tv_layout">TV layout</string>
|
||||
|
@ -462,11 +468,11 @@
|
|||
<string name="opensubtitles_key" translatable="false">opensubtitles_key</string>
|
||||
<string name="nginx_key" translatable="false">nginx_key</string>
|
||||
<string name="example_password">password123</string>
|
||||
<string name="example_username">MyCoolUsername</string>
|
||||
<string name="example_username">Username</string>
|
||||
<string name="example_email">hello@world.com</string>
|
||||
<string name="example_ip">127.0.0.1</string>
|
||||
<string name="example_site_name">MyCoolSite</string>
|
||||
<string name="example_site_url">example.com</string>
|
||||
<string name="example_site_name">NewSiteName</string>
|
||||
<string name="example_site_url">https://example.com</string>
|
||||
<string name="example_lang_name">Language code (en)</string>
|
||||
<!--
|
||||
<string name="mal_account_settings" translatable="false">MAL</string>
|
||||
|
@ -558,8 +564,8 @@
|
|||
<string name="subtitles_filter_lang">Filter by preferred media language</string>
|
||||
<string name="extras">Extras</string>
|
||||
<string name="trailer">Trailer</string>
|
||||
<string name="network_adress_example">Link to stream</string>
|
||||
<string name="referer">Referer</string>
|
||||
<string name="network_adress_example">https://example.com/example.mp4</string>
|
||||
<string name="referer">Referer (optional)</string>
|
||||
<string name="next">Next</string>
|
||||
<string name="provider_languages_tip">Watch videos in these languages</string>
|
||||
<string name="previous">Previous</string>
|
||||
|
@ -594,8 +600,6 @@
|
|||
<string name="plugins_updated" formatted="true">Updated %d plugins</string>
|
||||
<string name="blank_repo_message">CloudStream has no sites installed by default. You need to install the sites from repositories.
|
||||
\n
|
||||
\nBecause of a brainless DMCA takedown by Sky UK Limited 🤮 we cannot link the repository site in app.
|
||||
\n
|
||||
\nJoin our Discord or search online.</string>
|
||||
<string name="view_public_repositories_button">View community repositories</string>
|
||||
<string name="view_public_repositories_button_short">Public list</string>
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
app:key="@string/player_resize_enabled_key" />
|
||||
<SwitchPreference
|
||||
android:icon="@drawable/ic_baseline_speed_24"
|
||||
android:summary="@string/eigengraumode_settings_des"
|
||||
android:summary="@string/speed_setting_summary"
|
||||
android:title="@string/eigengraumode_settings"
|
||||
app:defaultValue="false"
|
||||
app:key="@string/playback_speed_enabled_key" />
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
<Preference
|
||||
android:icon="@drawable/baseline_network_ping_24"
|
||||
android:key="@string/test_providers_key"
|
||||
android:title="Test all providers" />
|
||||
android:title="@string/test_extensions"
|
||||
android:summary="@string/test_extensions_summary"/>
|
||||
|
||||
</PreferenceScreen>
|
Loading…
Add table
Add a link
Reference in a new issue