From e1d4a46309f8a979327e5b5486f2f8753f0a0639 Mon Sep 17 00:00:00 2001 From: firelight <147925818+fire-light42@users.noreply.github.com> Date: Fri, 5 Jul 2024 15:26:44 +0200 Subject: [PATCH 1/9] bugfix on lib startup --- .../lagradost/cloudstream3/MainActivity.kt | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index a47e7685..59f499c5 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -1112,23 +1112,6 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa MainAPI.settingsForProvider = settingsForProvider - // Change library icon with logo of current api in sync - libraryViewModel = ViewModelProvider(this)[LibraryViewModel::class.java] - libraryViewModel?.currentApiName?.observe(this) { - val syncAPI = libraryViewModel?.currentSyncApi - Log.i("SYNC_API", "${syncAPI?.name}, ${syncAPI?.idPrefix}") - val icon = if (syncAPI?.idPrefix == localListApi.idPrefix) { - R.drawable.library_icon - } else { - syncAPI?.icon ?: R.drawable.library_icon - } - - binding?.apply { - navRailView.menu.findItem(R.id.navigation_library)?.setIcon(icon) - navView.menu.findItem(R.id.navigation_library)?.setIcon(icon) - } - } - loadThemes(this) updateLocale() super.onCreate(savedInstanceState) @@ -1538,6 +1521,26 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener, BiometricCa logError(e) } } + + // we need to run this after we init all apis, otherwise currentSyncApi will fuck itself + this@MainActivity.runOnUiThread { + // Change library icon with logo of current api in sync + libraryViewModel = ViewModelProvider(this@MainActivity)[LibraryViewModel::class.java] + libraryViewModel?.currentApiName?.observe(this@MainActivity) { + val syncAPI = libraryViewModel?.currentSyncApi + Log.i("SYNC_API", "${syncAPI?.name}, ${syncAPI?.idPrefix}") + val icon = if (syncAPI?.idPrefix == localListApi.idPrefix) { + R.drawable.library_icon + } else { + syncAPI?.icon ?: R.drawable.library_icon + } + + binding?.apply { + navRailView.menu.findItem(R.id.navigation_library)?.setIcon(icon) + navView.menu.findItem(R.id.navigation_library)?.setIcon(icon) + } + } + } } SearchResultBuilder.updateCache(this) From 699a6979a5d6a924859d5dff122de34389a100a7 Mon Sep 17 00:00:00 2001 From: KingLucius Date: Fri, 5 Jul 2024 19:04:32 +0300 Subject: [PATCH 2/9] feat(TV UI): Fix clone site focus (#1179) --- app/src/main/res/layout/add_remove_sites.xml | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/layout/add_remove_sites.xml b/app/src/main/res/layout/add_remove_sites.xml index 9ef6ad6a..653f607f 100644 --- a/app/src/main/res/layout/add_remove_sites.xml +++ b/app/src/main/res/layout/add_remove_sites.xml @@ -1,19 +1,21 @@ + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent"> + android:id="@+id/add_site" + android:text="@string/add_site_pref" + android:focusable="true" + style="@style/SettingsItem"> + android:id="@+id/remove_site" + android:text="@string/remove_site_pref" + android:focusable="true" + style="@style/SettingsItem" /> \ No newline at end of file From 9b1ac5fc28774585f207acd0a5444cc9d09933b6 Mon Sep 17 00:00:00 2001 From: KingLucius Date: Fri, 5 Jul 2024 19:05:32 +0300 Subject: [PATCH 3/9] feat(Trakt): Skip specials season for next airing (#1181) --- .../com/lagradost/cloudstream3/metaproviders/TraktProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt index 736e05f2..7c375e0a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt @@ -238,7 +238,7 @@ open class TraktProvider : MainAPI() { description = episode.overview, ).apply { this.addDate(episode.firstAired, "yyyy-MM-dd'T'HH:mm:ss.SSSXXX") - if (nextAir == null && this.date != null && this.date!! > unixTimeMS) { + if (nextAir == null && this.date != null && this.date!! > unixTimeMS && this.season != 0) { nextAir = NextAiring( episode = this.episode!!, unixTime = this.date!!.div(1000L), From 145c42f1c8bdbd53a18733786778be6ff9f77d2b Mon Sep 17 00:00:00 2001 From: KingLucius Date: Fri, 5 Jul 2024 19:10:58 +0300 Subject: [PATCH 4/9] feat(UI): Use same Episode holder size (#1180) --- .../cloudstream3/ui/result/EpisodeAdapter.kt | 7 +++---- app/src/main/res/layout/result_episode.xml | 19 ++++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt index 0a1b777d..ed5e51f1 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/EpisodeAdapter.kt @@ -57,8 +57,7 @@ const val ACTION_PLAY_EPISODE_IN_MPV = 17 const val ACTION_MARK_AS_WATCHED = 18 const val ACTION_FCAST = 19 -const val TV_EP_SIZE_LARGE = 400 -const val TV_EP_SIZE_SMALL = 300 +const val TV_EP_SIZE = 400 data class EpisodeClickEvent(val action: Int, val data: ResultEpisode) class EpisodeAdapter( @@ -181,7 +180,7 @@ class EpisodeAdapter( fun bind(card: ResultEpisode) { localCard = card val setWidth = - if (isLayout(TV or EMULATOR)) TV_EP_SIZE_LARGE.toPx else ViewGroup.LayoutParams.MATCH_PARENT + if (isLayout(TV or EMULATOR)) TV_EP_SIZE.toPx else ViewGroup.LayoutParams.MATCH_PARENT binding.episodeLinHolder.layoutParams.width = setWidth binding.episodeHolderLarge.layoutParams.width = setWidth @@ -336,7 +335,7 @@ class EpisodeAdapter( fun bind(card: ResultEpisode) { binding.episodeHolder.layoutParams.apply { width = - if (isLayout(TV or EMULATOR)) TV_EP_SIZE_SMALL.toPx else ViewGroup.LayoutParams.MATCH_PARENT + if (isLayout(TV or EMULATOR)) TV_EP_SIZE.toPx else ViewGroup.LayoutParams.MATCH_PARENT } binding.apply { diff --git a/app/src/main/res/layout/result_episode.xml b/app/src/main/res/layout/result_episode.xml index b56cdb1d..36d60bd6 100644 --- a/app/src/main/res/layout/result_episode.xml +++ b/app/src/main/res/layout/result_episode.xml @@ -90,14 +90,15 @@ android:textColor="?attr/textColor" tools:text="Episode 1" /> - - + + + \ No newline at end of file From e86c926c30d565841d0701adac937d48dc9a8d69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20Sancak?= Date: Mon, 8 Jul 2024 23:59:02 +0300 Subject: [PATCH 5/9] Extractor: added Pichive & Sobreatsesuyp (#1184) --- .../extractors/HotlingerExtractor.kt | 5 ++ .../extractors/SobreatsesuypExtractor.kt | 56 +++++++++++++++++++ .../cloudstream3/utils/ExtractorApi.kt | 4 ++ 3 files changed, 65 insertions(+) create mode 100644 library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/SobreatsesuypExtractor.kt diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HotlingerExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HotlingerExtractor.kt index db721108..11f8ccaf 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HotlingerExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HotlingerExtractor.kt @@ -22,6 +22,11 @@ class FourPlayRu : ContentX() { override var mainUrl = "https://four.playru.net" } +class Pichive : ContentX() { + override var name = "Pichive" + override var mainUrl = "https://pichive.online" +} + class FourPichive : ContentX() { override var name = "FourPichive" override var mainUrl = "https://four.pichive.online" diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/SobreatsesuypExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/SobreatsesuypExtractor.kt new file mode 100644 index 00000000..91b60dac --- /dev/null +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/SobreatsesuypExtractor.kt @@ -0,0 +1,56 @@ +// ! Bu araç @keyiflerolsun tarafından | @KekikAkademi için yazılmıştır. + +package com.lagradost.cloudstream3.extractors + +import android.util.Log +import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.utils.* +import com.fasterxml.jackson.annotation.JsonProperty + +open class Sobreatsesuyp : ExtractorApi() { + override val name = "Sobreatsesuyp" + override val mainUrl = "https://sobreatsesuyp.com" + override val requiresReferer = true + + override suspend fun getUrl(url: String, referer: String?, subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit) { + val extRef = referer ?: "" + + val videoReq = app.get(url, referer = extRef).text + + val file = Regex("""file\":\"([^\"]+)""").find(videoReq)?.groupValues?.get(1) ?: throw ErrorLoadingException("File not found") + val postLink = "${mainUrl}/" + file.replace("\\", "") + val rawList = app.post(postLink, referer = extRef).parsedSafe>() ?: throw ErrorLoadingException("Post link not found") + + val postJson: List = rawList.drop(1).map { item -> + val mapItem = item as Map<*, *> + SobreatsesuypVideoData( + title = mapItem["title"] as? String, + file = mapItem["file"] as? String + ) + } + Log.d("Kekik_${this.name}", "postJson » ${postJson}") + + for (item in postJson) { + if (item.file == null || item.title == null) continue + + val fileUrl = "${mainUrl}/playlist/${item.file.substring(1)}.txt" + val videoData = app.post(fileUrl, referer = extRef).text + + callback.invoke( + ExtractorLink( + source = this.name, + name = "${this.name} - ${item.title}", + url = videoData, + referer = extRef, + quality = Qualities.Unknown.value, + type = INFER_TYPE + ) + ) + } + } + + data class SobreatsesuypVideoData( + @JsonProperty("title") val title: String? = null, + @JsonProperty("file") val file: String? = 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 566e29f0..0df73a0e 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -115,6 +115,7 @@ 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.Pichive import com.lagradost.cloudstream3.extractors.FourPichive import com.lagradost.cloudstream3.extractors.HDMomPlayer import com.lagradost.cloudstream3.extractors.HDPlayerSystem @@ -124,6 +125,7 @@ import com.lagradost.cloudstream3.extractors.HDStreamAble import com.lagradost.cloudstream3.extractors.RapidVid import com.lagradost.cloudstream3.extractors.TRsTX import com.lagradost.cloudstream3.extractors.VidMoxy +import com.lagradost.cloudstream3.extractors.Sobreatsesuyp import com.lagradost.cloudstream3.extractors.PixelDrain import com.lagradost.cloudstream3.extractors.MailRu import com.lagradost.cloudstream3.extractors.Mediafire @@ -734,6 +736,7 @@ val extractorApis: MutableList = arrayListOf( FourCX(), PlayRu(), FourPlayRu(), + Pichive(), FourPichive(), HDMomPlayer(), HDPlayerSystem(), @@ -743,6 +746,7 @@ val extractorApis: MutableList = arrayListOf( RapidVid(), TRsTX(), VidMoxy(), + Sobreatsesuyp(), PixelDrain(), MailRu(), From 8be8e5474647e5aeb31cb1026fe2e350dbf3c139 Mon Sep 17 00:00:00 2001 From: firelight <147925818+fire-light42@users.noreply.github.com> Date: Mon, 8 Jul 2024 23:17:25 +0200 Subject: [PATCH 6/9] Fixed log --- .../cloudstream3/extractors/SobreatsesuypExtractor.kt | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/SobreatsesuypExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/SobreatsesuypExtractor.kt index 91b60dac..c90b22f4 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/SobreatsesuypExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/SobreatsesuypExtractor.kt @@ -2,7 +2,6 @@ package com.lagradost.cloudstream3.extractors -import android.util.Log import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.utils.* import com.fasterxml.jackson.annotation.JsonProperty @@ -28,15 +27,13 @@ open class Sobreatsesuyp : ExtractorApi() { file = mapItem["file"] as? String ) } - Log.d("Kekik_${this.name}", "postJson » ${postJson}") for (item in postJson) { if (item.file == null || item.title == null) continue - val fileUrl = "${mainUrl}/playlist/${item.file.substring(1)}.txt" - val videoData = app.post(fileUrl, referer = extRef).text + val videoData = app.post("${mainUrl}/playlist/${item.file.substring(1)}.txt", referer = extRef).text - callback.invoke( + callback.invoke( ExtractorLink( source = this.name, name = "${this.name} - ${item.title}", From febb843424e0331b63b2e26ad796e797f7267ccc Mon Sep 17 00:00:00 2001 From: RowdyRushya Date: Mon, 15 Jul 2024 08:06:20 -0700 Subject: [PATCH 7/9] Fix VidSrcTo extractor (#1198) --- .../cloudstream3/extractors/Chillx.kt | 29 +++++++++---------- .../cloudstream3/extractors/VidSrcTo.kt | 14 ++++++++- .../cloudstream3/extractors/Vidplay.kt | 27 +++++++++++++---- 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Chillx.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Chillx.kt index 26567c7a..dd22efb2 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Chillx.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Chillx.kt @@ -6,6 +6,7 @@ import com.lagradost.cloudstream3.extractors.helper.AesHelper.cryptoAESHandler import com.lagradost.cloudstream3.utils.ExtractorApi import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.M3u8Helper +import kotlin.run class Moviesapi : Chillx() { override val name = "Moviesapi" @@ -28,17 +29,22 @@ open class Chillx : ExtractorApi() { override val requiresReferer = true companion object { + private val keySource = "https://rowdy-avocado.github.io/multi-keys/" + private var key: String? = null - suspend fun fetchKey(): String { - return if (key != null) { - key!! - } else { - val fetch = app.get("https://raw.githubusercontent.com/rushi-chavan/multi-keys/keys/keys.json").parsedSafe()?.key?.get(0) ?: throw ErrorLoadingException("Unable to get key") - key = fetch - key!! - } + private suspend fun fetchKey(): String { + return key + ?: run { + val res = + app.get(keySource).parsedSafe() + ?: throw ErrorLoadingException("Unable to get keys") + key = res.keys.get(0) + res.keys.get(0) + } } + + private data class KeysData(@JsonProperty("chillx") val keys: List) } @Suppress("NAME_SHADOWING") @@ -97,11 +103,4 @@ open class Chillx : ExtractorApi() { it.groupValues[1].toInt(16).toChar().toString() } } - - - - data class Keys( - @JsonProperty("chillx") val key: List - ) - } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VidSrcTo.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VidSrcTo.kt index 73857fb3..578f5fb9 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VidSrcTo.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VidSrcTo.kt @@ -26,7 +26,13 @@ class VidSrcTo : ExtractorApi() { callback: (ExtractorLink) -> Unit ) { val mediaId = app.get(url).document.selectFirst("ul.episodes li a")?.attr("data-id") ?: return - val res = app.get("$mainUrl/ajax/embed/episode/$mediaId/sources").parsedSafe() ?: return + val subtitlesLink = "$mainUrl/ajax/embed/episode/$mediaId/subtitles" + val subRes = app.get(subtitlesLink).parsedSafe>() + subRes?.forEach { + if (it.kind.equals("captions")) subtitleCallback.invoke(SubtitleFile(it.label, it.file)) + } + val sourcesLink = "$mainUrl/ajax/embed/episode/$mediaId/sources" + val res = app.get(sourcesLink).parsedSafe() ?: return if (res.status != 200) return res.result?.amap { source -> try { @@ -68,5 +74,11 @@ class VidSrcTo : ExtractorApi() { @JsonProperty("result") val result: VidsrctoUrl ) + data class VidsrctoSubtitles( + @JsonProperty("file") val file: String, + @JsonProperty("label") val label: String, + @JsonProperty("kind") val kind: String + ) + data class VidsrctoUrl(@JsonProperty("url") val encUrl: String) } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vidplay.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vidplay.kt index cb9eaf1e..6202800f 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vidplay.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vidplay.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.ErrorLoadingException import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.base64Encode @@ -9,6 +10,7 @@ import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.M3u8Helper import javax.crypto.Cipher import javax.crypto.spec.SecretKeySpec +import kotlin.run // Code found in https://github.com/KillerDogeEmpire/vidplay-keys // special credits to @KillerDogeEmpire for providing key @@ -35,8 +37,25 @@ open class Vidplay : ExtractorApi() { override val name = "Vidplay" override val mainUrl = "https://vidplay.site" override val requiresReferer = true - open val key = - "https://raw.githubusercontent.com/KillerDogeEmpire/vidplay-keys/keys/keys.json" + + companion object { + private val keySource = "https://rowdy-avocado.github.io/multi-keys/" + + private var keys: List? = null + + private suspend fun getKeys(): List { + return keys + ?: run { + val res = + app.get(keySource).parsedSafe() + ?: throw ErrorLoadingException("Unable to get keys") + keys = res.keys + res.keys + } + } + + private data class KeysData(@JsonProperty("vidplay") val keys: List) + } override suspend fun getUrl( url: String, @@ -70,10 +89,6 @@ open class Vidplay : ExtractorApi() { } - private suspend fun getKeys(): List { - return app.get(key).parsed() - } - private suspend fun callFutoken(id: String, url: String): String? { val script = app.get("$mainUrl/futoken", referer = url).text val k = "k='(\\S+)'".toRegex().find(script)?.groupValues?.get(1) ?: return null From 694193fa3eeada9388d68be521822ecf4f659bd4 Mon Sep 17 00:00:00 2001 From: IndusAryan <125901294+IndusAryan@users.noreply.github.com> Date: Mon, 15 Jul 2024 20:40:41 +0530 Subject: [PATCH 8/9] refactor(fix): result sync, fix slider theme and trailer fix (#1187) --- app/build.gradle.kts | 24 +- app/src/main/res/layout/result_sync.xml | 397 ++++++++++-------------- 2 files changed, 168 insertions(+), 253 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index ebefa0ea..6e439d53 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -157,16 +157,16 @@ dependencies { testImplementation("junit:junit:4.13.2") testImplementation("org.json:json:20240303") androidTestImplementation("androidx.test:core") - implementation("androidx.test.ext:junit-ktx:1.1.5") - androidTestImplementation("androidx.test.ext:junit:1.1.5") - androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") + implementation("androidx.test.ext:junit-ktx:1.2.1") + androidTestImplementation("androidx.test.ext:junit:1.2.1") + androidTestImplementation("androidx.test.espresso:espresso-core:3.6.1") // Android Core & Lifecycle implementation("androidx.core:core-ktx:1.13.1") implementation("androidx.appcompat:appcompat:1.7.0") implementation("androidx.navigation:navigation-ui-ktx:2.7.7") - implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.2") - implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.2") + implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.3") + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.3") implementation("androidx.navigation:navigation-fragment-ktx:2.7.7") // Design & UI @@ -182,9 +182,9 @@ dependencies { 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:33.2.0-android") - implementation("dev.zacsweers.autoservice:auto-service-ksp:1.1.0") + ksp("dev.zacsweers.autoservice:auto-service-ksp:1.2.0") + implementation("com.google.guava:guava:33.2.1-android") + implementation("dev.zacsweers.autoservice:auto-service-ksp:1.2.0") // Media 3 (ExoPlayer) implementation("androidx.media3:media3-ui:1.1.1") @@ -200,9 +200,9 @@ dependencies { // PlayBack implementation("com.jaredrummler:colorpicker:1.1.0") // Subtitle Color Picker implementation("com.github.recloudstream:media-ffmpeg:1.1.0") // Custom FF-MPEG Lib for Audio Codecs - implementation("com.github.teamnewpipe:NewPipeExtractor:fafd471") /* For Trailers + implementation("com.github.teamnewpipe:NewPipeExtractor:592f159") /* For Trailers ^ Update to Latest Commits if Trailers Misbehave, github.com/TeamNewPipe/NewPipeExtractor/commits/dev */ - implementation("com.github.albfernandez:juniversalchardet:2.4.0") // Subtitle Decoding + implementation("com.github.albfernandez:juniversalchardet:2.5.0") // Subtitle Decoding // Crash Reports (AcraApplication.kt) implementation("ch.acra:acra-core:5.11.3") @@ -215,14 +215,14 @@ dependencies { implementation("com.github.discord:OverlappingPanels:0.1.5") // Gestures implementation ("androidx.biometric:biometric:1.2.0-alpha05") // Fingerprint Authentication implementation("com.github.rubensousa:previewseekbar-media3:1.1.1.0") // SeekBar Preview - implementation("io.github.g0dkar:qrcode-kotlin:4.1.1") // QR code for PIN Auth on TV + implementation("io.github.g0dkar:qrcode-kotlin:4.2.0") // QR code for PIN Auth on TV // Extensions & Other Libs implementation("org.mozilla:rhino:1.7.15") // run JavaScript implementation("me.xdrop:fuzzywuzzy:1.4.0") // Library/Ext Searching with Levenshtein Distance 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 + implementation("com.uwetrottmann.tmdb2:tmdb-java:2.11.0") // TMDB API v3 Wrapper Made with RetroFit 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 diff --git a/app/src/main/res/layout/result_sync.xml b/app/src/main/res/layout/result_sync.xml index 9cde195c..8b7b33c0 100644 --- a/app/src/main/res/layout/result_sync.xml +++ b/app/src/main/res/layout/result_sync.xml @@ -1,306 +1,221 @@ + android:layout_width="match_parent" + android:layout_height="match_parent"> + android:id="@+id/result_sync_holder" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:padding="16dp" + android:visibility="gone" + tools:visibility="visible"> + + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="vertical"> + android:id="@+id/result_sync_names" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginBottom="10dp" + android:text="MyAnimeList, AniList" + android:textSize="16sp" + android:textStyle="bold" /> + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:visibility="visible"> + android:id="@+id/result_sync_sub_episode" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="end|center_vertical" + android:background="?android:attr/selectableItemBackgroundBorderless" + android:padding="10dp" + android:src="@drawable/baseline_remove_24" + app:tint="?attr/textColor" /> + android:id="@+id/result_sync_current_episodes" + style="@style/AppEditStyle" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:inputType="number" + android:textColorHint="?attr/grayTextColor" + android:textSize="20sp" + tools:hint="20" + tools:ignore="LabelFor" /> + android:id="@+id/result_sync_max_episodes" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:paddingBottom="1dp" + android:textColor="?attr/textColor" + android:textSize="20sp" + tools:text="30" /> + android:id="@+id/result_sync_add_episode" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="end|center_vertical" + android:background="?android:attr/selectableItemBackgroundBorderless" + android:padding="10dp" + android:src="@drawable/ic_baseline_add_24" + app:tint="?attr/textColor" /> - - + android:id="@+id/result_sync_episodes" + style="?android:attr/progressBarStyleHorizontal" + android:layout_width="match_parent" + android:layout_height="20dp" + android:layout_gravity="end|center_vertical" + android:indeterminate="false" + android:max="100" + android:padding="10dp" + android:progress="0" + android:progressBackgroundTint="?attr/colorPrimary" + tools:visibility="visible" /> + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:padding="10dp" + android:text="@string/sync_score" + android:textColor="?attr/textColor" + android:textSize="17sp" /> + style="@style/BlackButton" + android:layout_width="wrap_content" + android:layout_height="30dp" + android:layout_gravity="center_vertical" + android:layout_marginStart="0dp" + android:minWidth="0dp" + android:text="7/10" /> + android:id="@+id/result_sync_rating" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginStart="-5dp" + android:layout_marginEnd="-5dp" + app:thumbHeight="20dp" + android:stepSize="1" + android:value="4" + android:valueFrom="0" + android:valueTo="10" + app:labelStyle="@style/BlackLabel" + app:thumbRadius="10dp" + app:tickVisible="false" /> + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:paddingTop="12dp" + android:paddingBottom="12dp" + android:visibility="gone"> + android:id="@+id/home_parent_item_title" + style="@style/WatchHeaderText" + tools:text="Recommended" /> + android:layout_width="30dp" + android:layout_height="match_parent" + android:layout_gravity="end|center_vertical" + android:layout_marginEnd="5dp" + android:contentDescription="@string/home_more_info" + android:src="@drawable/ic_baseline_arrow_forward_24" + app:tint="?attr/textColor" /> + android:id="@+id/result_sync_check" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_rowWeight="1" + tools:listitem="@layout/sort_bottom_single_choice" /> + style="@style/WhiteButton" + android:layout_width="match_parent" + android:layout_marginTop="10dp" + android:text="@string/type_watching" + android:visibility="gone" /> + android:id="@+id/result_sync_set_score" + style="@style/BlackButton" + android:layout_width="match_parent" + android:layout_marginTop="10dp" + android:text="@string/upload_sync" + app:icon="@drawable/baseline_sync_24" /> + android:id="@+id/result_sync_loading_shimmer" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_gravity="center" + android:orientation="vertical" + android:padding="15dp" + 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" + tools:ignore="MissingClass"> + + - - + android:layout_height="30dp" /> + android:layout_width="match_parent" + android:layout_height="30dp" /> + android:layout_width="match_parent" + android:layout_height="30dp" /> @@ -313,8 +228,8 @@ + android:layout_width="match_parent" + android:layout_height="30dp" /> From a157115cfac1ef3f3c532198a931873d6cee9097 Mon Sep 17 00:00:00 2001 From: KingLucius Date: Mon, 15 Jul 2024 18:15:59 +0300 Subject: [PATCH 9/9] feat(Subtitles): SubSource subtitles provider (#1199) --- .../syncproviders/AccountManager.kt | 4 +- .../syncproviders/providers/SubSource.kt | 158 ++++++++++++++++++ 2 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SubSource.kt 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 e86d73aa..0259ccad 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AccountManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AccountManager.kt @@ -22,6 +22,7 @@ abstract class AccountManager(private val defIndex: Int) : AuthAPI { val addic7ed = Addic7ed() val subDlApi = SubDlApi(0) val localListApi = LocalList() + val subSourceApi = SubSourceApi() // used to login via app intent val OAuth2Apis @@ -51,7 +52,8 @@ abstract class AccountManager(private val defIndex: Int) : AuthAPI { get() = listOf( openSubtitlesApi, addic7ed, - subDlApi + subDlApi, + subSourceApi ) const val appString = "cloudstreamapp" diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SubSource.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SubSource.kt new file mode 100644 index 00000000..0e233ece --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SubSource.kt @@ -0,0 +1,158 @@ +package com.lagradost.cloudstream3.syncproviders.providers + +import com.fasterxml.jackson.annotation.JsonProperty +import com.lagradost.cloudstream3.TvType +import com.lagradost.cloudstream3.app +import com.lagradost.cloudstream3.subtitles.AbstractSubProvider +import com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities +import com.lagradost.cloudstream3.subtitles.SubtitleResource +import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.AppUtils.toJson +import com.lagradost.cloudstream3.utils.SubtitleHelper + +class SubSourceApi : AbstractSubProvider { + override val idPrefix = "subsource" + val name = "SubSource" + + companion object { + const val APIURL = "https://api.subsource.net/api" + const val DOWNLOADENDPOINT = "https://api.subsource.net/api/downloadSub" + } + + override suspend fun search(query: AbstractSubtitleEntities.SubtitleSearch): List? { + + //Only supports Imdb Id search for now + if (query.imdbId == null) return null + val queryLang = SubtitleHelper.fromTwoLettersToLanguage(query.lang!!) + val type = if ((query.seasonNumber ?: 0) > 0) TvType.TvSeries else TvType.Movie + + val searchRes = app.post( + url = "$APIURL/searchMovie", + data = mapOf( + "query" to query.imdbId!! + ) + ).parsedSafe() ?: return null + + val postData = if (type == TvType.TvSeries) { + mapOf( + "langs" to "[]", + "movieName" to searchRes.found.first().linkName, + "season" to "season-${query.seasonNumber}" + ) + } else { + mapOf( + "langs" to "[]", + "movieName" to searchRes.found.first().linkName, + ) + } + + val getMovieRes = app.post( + url = "$APIURL/getMovie", + data = postData + ).parsedSafe().let { + // api doesn't has episode number or lang filtering + if (type == TvType.Movie) { + it?.subs?.filter { sub -> + sub.lang == queryLang + } + } else { + it?.subs?.filter { sub -> + sub.releaseName!!.contains( + String.format( + "E%02d", + query.epNumber + ) + ) && sub.lang == queryLang + } + } + } ?: return null + + return getMovieRes.map { subtitle -> + AbstractSubtitleEntities.SubtitleEntity( + idPrefix = this.idPrefix, + name = subtitle.releaseName!!, + lang = subtitle.lang!!, + data = SubData( + movie = subtitle.linkName!!, + lang = subtitle.lang, + id = subtitle.subId.toString(), + ).toJson(), + type = type, + source = this.name, + epNumber = query.epNumber, + seasonNumber = query.seasonNumber, + isHearingImpaired = subtitle.hi == 1, + ) + } + } + + override suspend fun SubtitleResource.getResources(data: AbstractSubtitleEntities.SubtitleEntity) { + + val parsedSub = parseJson(data.data) + + val subRes = app.post( + url = "$APIURL/getSub", + data = mapOf( + "movie" to parsedSub.movie, + "lang" to data.lang, + "id" to parsedSub.id + ) + ).parsedSafe() ?: return + + this.addZipUrl( + "$DOWNLOADENDPOINT/${subRes.sub.downloadToken}" + ) { name, _ -> + name + } + } + + data class ApiSearch( + @JsonProperty("success") val success: Boolean, + @JsonProperty("found") val found: List, + ) + + data class Found( + @JsonProperty("id") val id: Long, + @JsonProperty("title") val title: String, + @JsonProperty("seasons") val seasons: Long, + @JsonProperty("type") val type: String, + @JsonProperty("releaseYear") val releaseYear: Long, + @JsonProperty("linkName") val linkName: String, + ) + + data class ApiResponse( + @JsonProperty("success") val success: Boolean, + @JsonProperty("movie") val movie: Movie, + @JsonProperty("subs") val subs: List, + ) + + data class Movie( + @JsonProperty("id") val id: Long? = null, + @JsonProperty("type") val type: String? = null, + @JsonProperty("year") val year: Long? = null, + @JsonProperty("fullName") val fullName: String? = null, + ) + + data class Sub( + @JsonProperty("hi") val hi: Int? = null, + @JsonProperty("fullLink") val fullLink: String? = null, + @JsonProperty("linkName") val linkName: String? = null, + @JsonProperty("lang") val lang: String? = null, + @JsonProperty("releaseName") val releaseName: String? = null, + @JsonProperty("subId") val subId: Long? = null, + ) + + data class SubData( + @JsonProperty("movie") val movie: String, + @JsonProperty("lang") val lang: String, + @JsonProperty("id") val id: String, + ) + + data class SubTitleLink( + @JsonProperty("sub") val sub: SubToken, + ) + + data class SubToken( + @JsonProperty("downloadToken") val downloadToken: String, + ) +} \ No newline at end of file