Merge branch 'master' into flow

This commit is contained in:
IndusAryan 2023-12-09 15:07:27 +05:30 committed by GitHub
commit aad0fd3e56
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 172 additions and 79 deletions

View file

@ -150,7 +150,7 @@ repositories {
dependencies {
// Testing
testImplementation("junit:junit:4.13.2")
testImplementation("org.json:json:20230618")
testImplementation("org.json:json:20231013")
androidTestImplementation("androidx.test:core")
implementation("androidx.test.ext:junit-ktx:1.1.5")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
@ -172,13 +172,13 @@ dependencies {
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
// Glide Module
ksp("com.github.bumptech.glide:ksp:4.15.1")
implementation("com.github.bumptech.glide:glide:4.15.1")
implementation("com.github.bumptech.glide:okhttp3-integration:4.15.1")
ksp("com.github.bumptech.glide:ksp:4.16.0")
implementation("com.github.bumptech.glide:glide:4.16.0")
implementation("com.github.bumptech.glide:okhttp3-integration:4.16.0")
// For KSP -> Official Annotation Processors are Not Yet Supported for KSP
ksp("dev.zacsweers.autoservice:auto-service-ksp:1.1.0")
implementation("com.google.guava:guava:32.1.2-android")
implementation("com.google.guava:guava:32.1.3-android")
implementation("dev.zacsweers.autoservice:auto-service-ksp:1.1.0")
// Media 3 (ExoPlayer)
@ -210,15 +210,15 @@ dependencies {
implementation("com.github.discord:OverlappingPanels:0.1.5") // Gestures
implementation("com.github.rubensousa:previewseekbar-media3:1.1.1.0") // SeekBar Preview
// Extensionns & Other Libs
implementation("org.mozilla:rhino:1.7.13") /* run JS
^ Don't Bump RhinoJS to 1.7.14, since in 1.7.14 Rhino Uses the `SourceVersion` Class, Which is NOT
Available on Android (even with Desugaring) & `NoClassDefFoundError` Occurs. */
// Extensions & Other Libs
implementation("org.mozilla:rhino:1.7.13") /* run JavaScript
^ Don't Bump RhinoJS to 1.7.14,`NoClassDefFoundError` Occurs and Trailers won't play (even with Desugaring)
NewPipeExtractor Issue */
implementation("me.xdrop:fuzzywuzzy:1.4.0") // Library/Ext Searching with Levenshtein Distance
implementation("com.github.LagradOst:SafeFile:0.0.5") // To Prevent the URI File Fu*kery
implementation("com.github.LagradOst:SafeFile:0.0.6") // To Prevent the URI File Fu*kery
implementation("org.conscrypt:conscrypt-android:2.5.2") // To Fix SSL Fu*kery on Android 9
implementation("com.uwetrottmann.tmdb2:tmdb-java:2.10.0") // TMDB API v3 Wrapper Made with RetroFit
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:1.1.6")
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.13.1") /* JSON Parser
^ Don't Bump Jackson above 2.13.1 , Crashes on Android TV's and FireSticks that have Min API
Level 25 or Less. */

View file

@ -7,7 +7,7 @@ import com.lagradost.cloudstream3.extractors.helper.AesHelper.cryptoAESHandler
import com.lagradost.cloudstream3.utils.AppUtils
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.M3u8Helper
class Moviesapi : Chillx() {
override val name = "Moviesapi"
@ -23,13 +23,14 @@ class Watchx : Chillx() {
override val name = "Watchx"
override val mainUrl = "https://watchx.top"
}
open class Chillx : ExtractorApi() {
override val name = "Chillx"
override val mainUrl = "https://chillx.top"
override val requiresReferer = true
companion object {
private const val KEY = "eN0^>\$^#M08uFv%c"
private const val KEY = "tSIsE8FgpRkv3QQQ"
}
override suspend fun getUrl(
@ -38,10 +39,14 @@ open class Chillx : ExtractorApi() {
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val master = Regex("MasterJS\\s*=\\s*'([^']+)").find(
val master = Regex("\\s*=\\s*'([^']+)").find(
app.get(
url,
referer = referer
referer = referer ?: "",
headers = mapOf(
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language" to "en-US,en;q=0.5",
)
).text
)?.groupValues?.get(1)
val decrypt = cryptoAESHandler(master ?: return, KEY.toByteArray(), false)?.replace("\\", "") ?: throw ErrorLoadingException("failed to decrypt")
@ -59,17 +64,12 @@ open class Chillx : ExtractorApi() {
"Origin" to mainUrl,
)
callback.invoke(
ExtractorLink(
name,
name,
source ?: return,
"$mainUrl/",
Qualities.P1080.value,
headers = headers,
isM3u8 = true
)
)
M3u8Helper.generateM3u8(
name,
source ?: return,
"$mainUrl/",
headers = headers
).forEach(callback)
AppUtils.tryParseJson<List<Tracks>>("[$tracks]")
?.filter { it.kind == "captions" }?.map { track ->

View file

@ -7,7 +7,6 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
import com.lagradost.cloudstream3.utils.Qualities
import java.net.URL
open class Dailymotion : ExtractorApi() {
@ -27,21 +26,16 @@ open class Dailymotion : ExtractorApi() {
callback: (ExtractorLink) -> Unit
) {
val embedUrl = getEmbedUrl(url) ?: return
val doc = app.get(embedUrl).document
val req = app.get(embedUrl)
val prefix = "window.__PLAYER_CONFIG__ = "
val configStr = doc.selectFirst("script:containsData($prefix)")?.data() ?: return
val config = tryParseJson<Config>(configStr.substringAfter(prefix)) ?: return
val configStr = req.document.selectFirst("script:containsData($prefix)")?.data() ?: return
val config = tryParseJson<Config>(configStr.substringAfter(prefix).substringBefore(";").trim()) ?: return
val id = getVideoId(embedUrl) ?: return
val dmV1st = config.dmInternalData.v1st
val dmTs = config.dmInternalData.ts
val metaDataUrl =
"$mainUrl/player/metadata/video/$id?locale=en&dmV1st=$dmV1st&dmTs=$dmTs&is_native_app=0"
val cookies = mapOf(
"v1st" to dmV1st,
"dmvk" to config.context.dmvk,
"ts" to dmTs.toString()
)
val metaData = app.get(metaDataUrl, referer = embedUrl, cookies = cookies)
val embedder = config.context.embedder
val metaDataUrl = "$mainUrl/player/metadata/video/$id?embedder=$embedder&locale=en-US&dmV1st=$dmV1st&dmTs=$dmTs&is_native_app=0"
val metaData = app.get(metaDataUrl, referer = embedUrl, cookies = req.cookies)
.parsedSafe<MetaData>() ?: return
metaData.qualities.forEach { (_, video) ->
video.forEach {
@ -84,13 +78,13 @@ open class Dailymotion : ExtractorApi() {
)
data class InternalData(
val ts: Int,
val ts: Long,
val v1st: String
)
data class Context(
@JsonProperty("access_token") val accessToken: String?,
val dmvk: String,
val embedder: String?,
)
data class MetaData(

View file

@ -18,7 +18,8 @@ open class Linkbox : ExtractorApi() {
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val id = Regex("""(?:/f/|/file/|\?id=)(\w+)""").find(url)?.groupValues?.get(1)
val token = Regex("""(?:/f/|/file/|\?id=)(\w+)""").find(url)?.groupValues?.get(1)
val id = app.get("$mainUrl/api/file/share_out_list/?sortField=utime&sortAsc=0&pageNo=1&pageSize=50&shareToken=$token").parsedSafe<Responses>()?.data?.itemId
app.get("$mainUrl/api/file/detail?itemId=$id", referer = url)
.parsedSafe<Responses>()?.data?.itemInfo?.resolutionList?.map { link ->
callback.invoke(
@ -44,6 +45,7 @@ open class Linkbox : ExtractorApi() {
data class Data(
@JsonProperty("itemInfo") val itemInfo: ItemInfo? = null,
@JsonProperty("itemId") val itemId: String? = null,
)
data class Responses(

View file

@ -0,0 +1,92 @@
package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.base64Encode
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
// Code found in https://github.com/Claudemirovsky/worstsource-keys
// special credits to @Claudemirovsky for providing key
open class Vidplay : ExtractorApi() {
override val name = "Vidplay"
override val mainUrl = "https://vidplay.site"
override val requiresReferer = true
override suspend fun getUrl(
url: String,
referer: String?,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
val id = url.substringBefore("?").substringAfterLast("/")
val encodeId = encodeId(id, getKeys())
val mediaUrl = callFutoken(encodeId, url)
val res = app.get(
"$mediaUrl", headers = mapOf(
"Accept" to "application/json, text/javascript, */*; q=0.01",
"X-Requested-With" to "XMLHttpRequest",
), referer = url
).parsedSafe<Response>()?.result?.sources
res?.map {
M3u8Helper.generateM3u8(
this.name,
it.file ?: return@map,
"$mainUrl/"
).forEach(callback)
}
}
private suspend fun getKeys(): List<String> {
return app.get("https://raw.githubusercontent.com/Claudemirovsky/worstsource-keys/keys/keys.json")
.parsed()
}
private suspend fun callFutoken(id: String, url: String): String? {
val script = app.get("$mainUrl/futoken").text
val k = "k='(\\S+)'".toRegex().find(script)?.groupValues?.get(1) ?: return null
val a = mutableListOf(k)
for (i in id.indices) {
a.add((k[i % k.length].code + id[i].code).toString())
}
return "$mainUrl/mediainfo/${a.joinToString(",")}?${url.substringAfter("?")}"
}
private fun encodeId(id: String, keyList: List<String>): String {
val cipher1 = Cipher.getInstance("RC4")
val cipher2 = Cipher.getInstance("RC4")
cipher1.init(
Cipher.DECRYPT_MODE,
SecretKeySpec(keyList[0].toByteArray(), "RC4"),
cipher1.parameters
)
cipher2.init(
Cipher.DECRYPT_MODE,
SecretKeySpec(keyList[1].toByteArray(), "RC4"),
cipher2.parameters
)
var input = id.toByteArray()
input = cipher1.doFinal(input)
input = cipher2.doFinal(input)
return base64Encode(input).replace("/", "_")
}
data class Sources(
@JsonProperty("file") val file: String? = null,
)
data class Result(
@JsonProperty("sources") val sources: ArrayList<Sources>? = arrayListOf(),
)
data class Response(
@JsonProperty("result") val result: Result? = null,
)
}

View file

@ -167,6 +167,7 @@ import com.lagradost.cloudstream3.extractors.Vidgomunimesb
import com.lagradost.cloudstream3.extractors.Vidmoly
import com.lagradost.cloudstream3.extractors.Vidmolyme
import com.lagradost.cloudstream3.extractors.Vido
import com.lagradost.cloudstream3.extractors.Vidplay
import com.lagradost.cloudstream3.extractors.Vidstreamz
import com.lagradost.cloudstream3.extractors.Vizcloud
import com.lagradost.cloudstream3.extractors.Vizcloud2
@ -793,6 +794,7 @@ val extractorApis: MutableList<ExtractorApi> = arrayListOf(
VidSrcExtractor2(),
PlayLtXyz(),
AStreamHub(),
Vidplay(),
Cda(),
Dailymotion(),

View file

@ -30,7 +30,7 @@ class GlideModule : AppGlideModule() {
.signature(ObjectKey(System.currentTimeMillis().toShort()))
}.setDiskCache {
// Possible to make this a setting in the future.
val memoryCacheSizeBytes: Long = 1024 * 1024 * 100; // 100mb
val memoryCacheSizeBytes: Long = 1024 * 1024 * 100 // 100mb
InternalCacheDiskCacheFactory(context, memoryCacheSizeBytes).build()
}
}

View file

@ -316,15 +316,15 @@ object UIHelper {
if (colorCallback != null) {
builder = builder.listener(object : RequestListener<Drawable> {
@SuppressLint("CheckResult")
override fun onResourceReady(
resource: Drawable?,
model: Any?,
resource: Drawable,
model: Any,
target: Target<Drawable>?,
dataSource: DataSource?,
dataSource: DataSource,
isFirstResource: Boolean
): Boolean {
resource?.toBitmapOrNull()
resource.toBitmapOrNull()
?.let { bitmap ->
createPaletteAsync(
identifier,
@ -335,11 +335,10 @@ object UIHelper {
return false
}
@SuppressLint("CheckResult")
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: Target<Drawable>?,
target: Target<Drawable>,
isFirstResource: Boolean
): Boolean {
return false

View file

@ -11,9 +11,9 @@
<string name="bug_report_settings_off">بس بعات البيانات وقتما يتعطل الآپ</string>
<string name="preview_background_img_des">شوف الخلفية</string>
<string name="play_movie_button">مشّي الفيلم</string>
<string name="subs_hold_to_reset_to_default">ضلّ كابس لترجع الساتِنگز كيف كانة أول ما نزلتو الآپ</string>
<string name="subs_hold_to_reset_to_default">ضلّ كابس لترجع السَتِنگز كيف كانة أول ما نزلتو الآپ</string>
<string name="season_format">%1$s%2$d%3$s</string>
<string name="subs_default_reset_toast">رجِعت الساتِنيگز ل كيف كانت أساسًا</string>
<string name="subs_default_reset_toast">رجِعت السَتِنگز ل كيف كانت أساسًا</string>
<string name="uprereleases_settings_des">نبش على تجديدات بالنسخة التجريبية كمان</string>
<string name="subs_outline_color">لون حدود الكتيبة</string>
<string name="search_poster_img_des">پوستر</string>
@ -37,7 +37,7 @@
<string name="subs_download_languages">نزل الترجمات مع الڤيديو</string>
<string name="search_provider_text_providers">عوزو المصادر لَ تنبّشو</string>
<string name="go_back_img_des">رجاع</string>
<string name="discord">انضم لگروپ \"كلودستريم\" ع الـ\"ديسكورد\"</string>
<string name="discord">انضم لگروپ \"كلود ستريم\" ع الـ\"ديسكورد\"</string>
<string name="episode_more_options_des">بعد خيارات</string>
<string name="backup_success">تسيّڤة النسخة الإحتياطية</string>
<string name="benene_count_text">صرتو عاطين %d موزززة للمطورين!</string>
@ -73,7 +73,7 @@
<string name="resume">كَمِّل</string>
<string name="test_log">سِجِل</string>
<string name="torrent_no_plot">ما نلاقى الوصف</string>
<string name="subtitles_settings">ساتِنگز الترجمة</string>
<string name="subtitles_settings">سَتِنگز الترجمة</string>
<string name="subs_window_color">لون العلبة</string>
<string name="play_torrent_button">عمول ستريم للتورنت</string>
<string name="automatic_plugin_download_summary">تلقائيًا نَزِل كل الإضافات من الريپويات يلي نزادِت.</string>
@ -86,18 +86,18 @@
<string name="advanced_search">تنبيش منظّم</string>
<string name="chromecast_subtitles_settings">ترجمة \"كروم كاست\"</string>
<string name="swipe_to_change_settings">سحابو لتتحكمو بالصوت والضو</string>
<string name="rated_format" formatted="true">رايتيگ: %.1f</string>
<string name="chromecast_subtitles_settings_des">ستنگز تبع ترجمة \"كروم كاست\"</string>
<string name="rated_format" formatted="true">رايتينگ: %.1f</string>
<string name="chromecast_subtitles_settings_des">سَتِنگز تبع ترجمة \"كروم كاست\"</string>
<string name="browser">متصفح الوَب</string>
<string name="double_tap_to_seek_settings_des">كبوس مرتين على اليمين أو الشمال حتى تقرب أو ترَجِع الڤيديو</string>
<string name="normal_no_plot">ما نلاقى وصف الأحداث</string>
<string name="next_episode">الحلقة يلي بَعدا</string>
<string name="updates_settings">فرجي تجديدات الآپ</string>
<string name="library">رفّ</string>
<string name="lightnovel">آپ زغير من نفس المطورين للروايات بدل من الڤيديوات</string>
<string name="lightnovel">آپ من نفس المطورين للروايات الخفيفة، بدل من الڤيديوات</string>
<string name="automatic_plugin_download_mode_title">حدد الوضع لَتفَلتِر تنزيل الإضافات</string>
<string name="episode">حلقة</string>
<string name="autoplay_next_settings_des">مَشّي الحلقة يلي بعدا تلقائيًا بعد ما تُخلَص الحلقة</string>
<string name="autoplay_next_settings_des">مَشّي الحلقة يلّي بعدا تلقائيًا بعد ما تُخلَص الحلقة</string>
<string name="subs_text_color">لون الكتيبة</string>
<string name="type_completed">مخلص</string>
<string name="use_system_brightness_settings_des">عوز قوة ضوّ الشاشة تبع السيستام بدل من تغميئ الڤيديو</string>
@ -139,7 +139,7 @@
<string name="home_main_poster_img_des">الپوسر الأساسية</string>
<string name="pick_source">المصادر</string>
<string name="double_tap_to_seek_settings">كبوسو مرتين لتقفو</string>
<string name="title_settings">ثاتينگز</string>
<string name="title_settings">سَتِنگز</string>
<string name="title_search">التنبيش</string>
<string name="loading">لودينگ…</string>
<string name="action_remove_watching">شيل</string>
@ -147,17 +147,17 @@
<string name="category_updates">التجديد والنسخات الاحتياطية</string>
<string name="pref_filter_search_quality">خبي هيدي الجودات من نتائج التنبيش</string>
<string name="type_on_hold">موقف موقتًا</string>
<string name="app_name">كلاودستريم</string>
<string name="app_name">كلود ستريم</string>
<string name="player_size_settings_des">شيل الأسود من الأطراف</string>
<string name="season_short">ج</string>
<string name="apk_installer_settings">طريقة تجديد الآپ</string>
<string name="autoplay_next_settings">تقائيًا مشّي الحلقة ل بعدا</string>
<string name="autoplay_next_settings">تلقائيًا مشّي الحلقة الّي بعدا</string>
<string name="picture_in_picture">كفي فوق غير آپ</string>
<string name="player_subtitles_settings_des">ساتِنگز ترجمة الڤيديو</string>
<string name="player_subtitles_settings_des">سَتِنگز ترجمة الڤيديو</string>
<string name="app_language">لغة الآپ</string>
<string name="show_trailers_settings">فرجي المقاطع الدعائية</string>
<string name="test_passed">نجح</string>
<string name="play_with_app_name">مَشّي بـ\"كلاود ستريم\"</string>
<string name="play_with_app_name">مَشّي بـ\"كلود ستريم\"</string>
<string name="subs_subtitle_elevation">إرتفاع الترجمة</string>
<string name="search_provider_text_types">عوزو الأنواع ل تنبّشو</string>
<string name="episodes">حلقات</string>
@ -536,7 +536,7 @@
<string name="plugins_updated" formatted="true">عدد الإضافيات يلي تجددت: %d</string>
<string name="delayed_update_notice">رح يتجدد الآپ وقتا تطلعو مِنو</string>
<string name="hls_playlist">پلاي ليست \"ايش أل أس\"</string>
<string name="add_repository">زيد ريپوزيتاري</string>
<string name="add_repository">زيد ريپوزيتوري</string>
<string name="action_mark_as_watched">علم إنو حضرتو</string>
<string name="preferred_media_subtext">شو بَدَك تشوف</string>
<string name="subtitles_remove_captions">شيل المعلومات يلي محطوطة بالترجمة ليلي عندن فقد سمعي</string>

View file

@ -510,4 +510,7 @@
<string name="automatic">Automatikus</string>
<string name="android_tv_interface_on_seek_settings_summary">Az átugrás mértéke, amikor a lejátszó látható</string>
<string name="automatic_plugin_download_mode_title">Válassza ki a módot a pluginek letöltésének szűréséhez</string>
<string name="backup_frequency">Mentési gyakoriság</string>
<string name="sync_score">Értékelt</string>
<string name="disable">Kikapcsolás</string>
</resources>

View file

@ -11,11 +11,11 @@
<string name="rew_text_regular_format" formatted="true" translatable="false">%d</string>
<string name="rating_format" formatted="true" translatable="false">%.1f/10.0</string>
<string name="year_format" formatted="true" translatable="false">%d</string>
<string name="app_dub_sub_episode_text_format" formatted="true">%$1s B. %2$d</string>
<string name="app_dub_sub_episode_text_format" formatted="true">%1$s B. %2$d</string>
<string name="cast_format" formatted="true">Cast: %s</string>
<string name="next_episode_format" formatted="true">Bölüm %d şu tarihte yayınlanacak</string>
<string name="next_episode_time_day_format" formatted="true">%dg %ds %dd</string>
<string name="next_episode_time_hour_format" formatted="true">%ds %dd</string>
<string name="next_episode_time_day_format" formatted="true">%1$dg %2$ds %3$dd</string>
<string name="next_episode_time_hour_format" formatted="true">%1$ds %2$dd</string>
<string name="next_episode_time_min_format" formatted="true">%dm</string>
<!-- IS NOT NEEDED TO TRANSLATE AS THEY ARE ONLY USED FOR SCREEN READERS AND WONT SHOW UP TO NORMAL USERS -->
<string name="result_poster_img_des">Poster</string>
@ -204,7 +204,7 @@
<string name="delete_file">Dosyayı sil</string>
<string name="delete">Sil</string>
<string name="cancel">İptal et</string>
<string name="pause">Durdur</string>
<string name="pause">Duraklat</string>
<string name="resume">Sürdür</string>
<string name="go_back_30">-30</string>
<string name="go_forward_30">+30</string>
@ -537,11 +537,11 @@
<string name="clipboard_too_large">Çok fazla metin. Panoya kaydedilemiyor.</string>
<string name="library">Kütüphane</string>
<string name="browser">Tarayıcı</string>
<string name="empty_library_no_accounts_message">Görünüşe göre kütüphaneniz boş :(
\nBir kütüphane hesabına giriş yapın veya yerel kütüphanenize içerik ekleyin</string>
<string name="empty_library_no_accounts_message">Kütüphaneniz boş :(
\nBir kütüphane hesabında oturum açın veya yerel kütüphanenize programlar ekleyin.</string>
<string name="safe_mode_file">Güvenli mod dosyası bulundu!
\nDosya kaldırılana kadar başlangıçta herhangi bir uzantı yüklenmiyor.</string>
<string name="sort_by">Sırala</string>
<string name="sort_by">Şuna Göre Sırala</string>
<string name="sort">Sırala</string>
<string name="sort_updated_new">Güncellenme (Yeniden Eskiye)</string>
<string name="sort_updated_old">Güncellenme (Eskiden Yeniye)</string>

View file

@ -181,8 +181,8 @@
<string name="no_season">Không có mùa nào</string>
<string name="episode">Tập</string>
<string name="episodes">Tập</string>
<string name="episodes_range">%1$ng-%2$ng</string>
<string name="episode_format" formatted="true">%d %s</string>
<string name="episodes_range">%1$d-%2$d</string>
<string name="episode_format" formatted="true">%1$d %2$s</string>
<string name="season_short">M</string>
<string name="episode_short">T</string>
<string name="no_episodes_found">Không có tập nào</string>
@ -311,7 +311,7 @@
<string name="example_site_name">Địa chỉ trang web</string>
<string name="example_site_url">example.com</string>
<string name="example_lang_name">Mã ngôn ngữ (vi)</string>
<string name="login_format" formatted="true">%1$gi %2$gi</string>
<string name="login_format" formatted="true">%1$s %2$s</string>
<string name="account">tài khoản</string>
<string name="logout">Đăng xuất</string>
<string name="login">Đăng nhập</string>
@ -444,7 +444,7 @@
<string name="redo_setup_process">Thiết lập lại</string>
<string name="apk_installer_settings">Bộ cài APK</string>
<string name="apk_installer_settings_des">Một số máy không hỗ trợ trình cài đặt gói mới. Hãy thử tùy chọn cũ nếu các bản cập nhật không cài đặt.</string>
<string name="season_format">%s %d%s</string>
<string name="season_format">%1$s %2$d%3$s</string>
<string name="play_trailer_button">Xem giới thiệu</string>
<string name="automatic_plugin_download_summary">Tự động tải plugin còn thiếu.</string>
<string name="update_started">Bắt đầu cập nhật</string>

View file

@ -6,7 +6,7 @@ buildscript {
}
dependencies {
classpath("com.android.tools.build:gradle:8.2.0")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.20")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.21")
classpath("org.jetbrains.dokka:dokka-gradle-plugin:1.9.10")
// NOTE: Do not place your application dependencies here; they belong
@ -22,9 +22,9 @@ allprojects {
}
plugins {
id("com.google.devtools.ksp") version "1.9.20-1.0.14" apply false
id("com.google.devtools.ksp") version "1.9.21-1.0.15" apply false
}
tasks.register<Delete>("clean") {
delete(rootProject.layout.buildDirectory)
}
}

View file

@ -1,6 +1,7 @@
CloudStream-3 size film, dizi ve anime akışı yapma ve indirme olanağı sunar.
CloudStream-3, Filmleri, TV Dizilerini ve Animeleri izlemenize ve indirmenize olanak tanır.
Uygulama hiçbir reklam ve analitik yöntemleri barındırmaz ve birçok fragman & film sitelerini destekler, ve daha fazlası:
Uygulama herhangi bir reklam ve analitik içermez ve
birden fazla fragman & film sitesini ve daha fazlasını destekler, örneğin:
Yer imleri