├── FAILURE ├── Animasu ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── animasu │ │ ├── AnimasuPlugin.kt │ │ ├── Extractors.kt │ │ └── Animasu.kt └── build.gradle.kts ├── AnimeIndo ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── animeindo │ │ └── AnimeIndoPlugin.kt └── build.gradle.kts ├── AnimeSail ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── animesail │ │ └── AnimeSailPlugin.kt └── build.gradle.kts ├── Anoboy ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── anoboy │ │ ├── AnoboyPlugin.kt │ │ └── Anoboy.kt └── build.gradle.kts ├── Dramaid ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── dramaid │ │ ├── Oppadrama.kt │ │ ├── DramaidPlugin.kt │ │ ├── Extractors.kt │ │ └── Dramaid.kt └── build.gradle.kts ├── Dubbindo ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── dubbindo │ │ ├── DubbindoPlugin.kt │ │ └── Dubbindo.kt └── build.gradle.kts ├── Dutamovie ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── dutamovie │ │ ├── Extractors.kt │ │ └── DutamoviePlugin.kt └── build.gradle.kts ├── Gomov ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── gomov │ │ ├── GomovPlugin.kt │ │ └── Extractors.kt └── build.gradle.kts ├── Gomunime ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── gomunime │ │ └── GomunimePlugin.kt └── build.gradle.kts ├── Idlix ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── idlix │ │ ├── IdlixPlugin.kt │ │ ├── Extractors.kt │ │ └── CryptoJSAES.kt └── build.gradle.kts ├── IndoTV ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── indotv │ │ └── IndoTVPlugin.kt └── build.gradle.kts ├── Kuronime ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── kuronime │ │ └── KuronimePlugin.kt └── build.gradle.kts ├── LayarKaca ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── layarkaca │ │ ├── LayarKacaPlugin.kt │ │ └── Extractors.kt └── build.gradle.kts ├── Minioppai ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── minioppai │ │ ├── MinioppaiPlugin.kt │ │ ├── Extractors.kt │ │ └── Minioppai.kt └── build.gradle.kts ├── Nekopoi ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── nekopoi │ │ ├── NekopoiPlugin.kt │ │ └── Extractors.kt └── build.gradle.kts ├── Neonime ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── neonime │ │ └── NeonimePlugin.kt └── build.gradle.kts ├── Ngefilm ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── ngefilm │ │ ├── NgefilmPlugin.kt │ │ ├── Ngefilm.kt │ │ └── Extractors.kt └── build.gradle.kts ├── Nimegami ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── nimegami │ │ ├── NimegamiPlugin.kt │ │ ├── Extractors.kt │ │ └── Nimegami.kt └── build.gradle.kts ├── Oploverz ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── oploverz │ │ ├── OploverzPlugin.kt │ │ └── Extractors.kt └── build.gradle.kts ├── Otakudesu ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── otakudesu │ │ └── OtakudesuPlugin.kt └── build.gradle.kts ├── Pusatfilm ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── pusatfilm │ │ ├── PusatfilmPlugin.kt │ │ ├── Extractors.kt │ │ └── Pusatfilm.kt └── build.gradle.kts ├── Raveeflix ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── raveeflix │ │ ├── RaveeflixPlugin.kt │ │ └── Raveeflix.kt └── build.gradle.kts ├── Rebahin ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── rebahin │ │ ├── Cgvindo.kt │ │ ├── RebahinPlugin.kt │ │ └── Kitanonton.kt └── build.gradle.kts ├── DramaSerial ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── dramaserial │ │ ├── DramaSerialPlugin.kt │ │ └── DramaSerial.kt └── build.gradle.kts ├── Funmovieslix ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── funmovieslix │ │ ├── FunmovieslixProvider.kt │ │ ├── Extractors.kt │ │ └── Funmovieslix.kt └── build.gradle.kts ├── Kuramanime ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── kuramanime │ │ ├── KuramanimePlugin.kt │ │ ├── Extractors.kt │ │ └── Kuramanime.kt └── build.gradle.kts ├── Nodrakorid ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── nodrakorid │ │ ├── NodrakoridPlugin.kt │ │ └── Extractors.kt └── build.gradle.kts ├── NontonAnimeID ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── nontonanimeid │ │ ├── NontonAnimeIDPlugin.kt │ │ └── Extractors.kt └── build.gradle.kts ├── Pencurimovie ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── pencurimovie │ │ ├── PencurimovieProvider.kt │ │ └── Pencurimovie.kt └── build.gradle.kts ├── Samehadaku ├── src │ └── main │ │ ├── AndroidManifest.xml │ │ └── kotlin │ │ └── com │ │ └── samehadaku │ │ └── SamehadakuPlugin.kt └── build.gradle.kts ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── settings.gradle.kts ├── .vscode └── settings.json ├── .github ├── ISSUE_TEMPLATE │ ├── 09_Other_Issue.yml │ ├── 02_site-request.yml │ └── 01_report_issue.yml └── workflows │ └── build.yml ├── gradle.properties ├── gradlew.bat └── README.md /FAILURE: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Animasu/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /AnimeIndo/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /AnimeSail/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Anoboy/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dramaid/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dubbindo/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Dutamovie/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Gomov/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Gomunime/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Idlix/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /IndoTV/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Kuronime/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /LayarKaca/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Minioppai/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Nekopoi/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Neonime/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Ngefilm/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Nimegami/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Oploverz/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Otakudesu/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Pusatfilm/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Raveeflix/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Rebahin/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /DramaSerial/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Funmovieslix/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Kuramanime/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Nodrakorid/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /NontonAnimeID/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Pencurimovie/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Samehadaku/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TeKuma25/IndoStream/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea 5 | .DS_Store 6 | /build 7 | **/build 8 | /captures 9 | .externalNativeBuild 10 | .cxx 11 | local.properties 12 | .vscode -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip 3 | distributionPath=wrapper/dists 4 | zipStorePath=wrapper/dists 5 | zipStoreBase=GRADLE_USER_HOME -------------------------------------------------------------------------------- /Dramaid/src/main/kotlin/com/dramaid/Oppadrama.kt: -------------------------------------------------------------------------------- 1 | package com.dramaid 2 | 3 | import com.lagradost.cloudstream3.extractors.Filesim 4 | 5 | class Oppadrama : Dramaid() { 6 | override var mainUrl = "http://45.11.57.64" 7 | override var name = "Oppadrama" 8 | } -------------------------------------------------------------------------------- /Rebahin/src/main/kotlin/com/rebahin/Cgvindo.kt: -------------------------------------------------------------------------------- 1 | package com.rebahin 2 | 3 | class Cgvindo : Rebahin() { 4 | 5 | // override var mainUrl = "http://62.171.170.1/" 6 | override var mainUrl = "https://cgvindo.christmas/" 7 | override var name = "Cgvindo" 8 | } 9 | -------------------------------------------------------------------------------- /Idlix/src/main/kotlin/com/idlix/IdlixPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.idlix 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | 7 | @CloudstreamPlugin 8 | class IdlixPlugin : Plugin() { 9 | override fun load(context: Context) { 10 | registerMainAPI(Idlix()) 11 | registerExtractorAPI(Jeniusplay()) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Pencurimovie/src/main/kotlin/com/pencurimovie/PencurimovieProvider.kt: -------------------------------------------------------------------------------- 1 | package com.pencurimovie 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | 7 | @CloudstreamPlugin 8 | class PencurimovieProvider : Plugin() { 9 | override fun load(context: Context) { 10 | registerMainAPI(Pencurimovie()) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Anoboy/src/main/kotlin/com/anoboy/AnoboyPlugin.kt: -------------------------------------------------------------------------------- 1 | 2 | package com.anoboy 3 | 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | import android.content.Context 7 | 8 | @CloudstreamPlugin 9 | class AnoboyPlugin: Plugin() { 10 | override fun load(context: Context) { 11 | // All providers should be added in this manner. Please don't edit the providers list directly. 12 | registerMainAPI(Anoboy()) 13 | } 14 | } -------------------------------------------------------------------------------- /Neonime/src/main/kotlin/com/neonime/NeonimePlugin.kt: -------------------------------------------------------------------------------- 1 | 2 | package com.neonime 3 | 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | import android.content.Context 7 | 8 | @CloudstreamPlugin 9 | class NeonimePlugin: Plugin() { 10 | override fun load(context: Context) { 11 | // All providers should be added in this manner. Please don't edit the providers list directly. 12 | registerMainAPI(Neonime()) 13 | } 14 | } -------------------------------------------------------------------------------- /Gomunime/src/main/kotlin/com/gomunime/GomunimePlugin.kt: -------------------------------------------------------------------------------- 1 | 2 | package com.gomunime 3 | 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | import android.content.Context 7 | 8 | @CloudstreamPlugin 9 | class GomunimePlugin: Plugin() { 10 | override fun load(context: Context) { 11 | // All providers should be added in this manner. Please don't edit the providers list directly. 12 | registerMainAPI(Gomunime()) 13 | } 14 | } -------------------------------------------------------------------------------- /Kuronime/src/main/kotlin/com/kuronime/KuronimePlugin.kt: -------------------------------------------------------------------------------- 1 | 2 | package com.kuronime 3 | 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | import android.content.Context 7 | 8 | @CloudstreamPlugin 9 | class KuronimePlugin: Plugin() { 10 | override fun load(context: Context) { 11 | // All providers should be added in this manner. Please don't edit the providers list directly. 12 | registerMainAPI(Kuronime()) 13 | } 14 | } -------------------------------------------------------------------------------- /AnimeIndo/src/main/kotlin/com/animeindo/AnimeIndoPlugin.kt: -------------------------------------------------------------------------------- 1 | 2 | package com.animeindo 3 | 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | import android.content.Context 7 | 8 | @CloudstreamPlugin 9 | class AnimeIndoPlugin: Plugin() { 10 | override fun load(context: Context) { 11 | // All providers should be added in this manner. Please don't edit the providers list directly. 12 | registerMainAPI(AnimeIndo()) 13 | } 14 | } -------------------------------------------------------------------------------- /IndoTV/src/main/kotlin/com/indotv/IndoTVPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.indotv 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | 7 | @CloudstreamPlugin 8 | class IndoTVPlugin : Plugin() { 9 | override fun load(context: Context) { 10 | // All providers should be added in this manner. Please don't edit the providers list 11 | // directly. 12 | registerMainAPI(IndoTV()) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Raveeflix/src/main/kotlin/com/raveeflix/RaveeflixPlugin.kt: -------------------------------------------------------------------------------- 1 | 2 | package com.raveeflix 3 | 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | import android.content.Context 7 | 8 | @CloudstreamPlugin 9 | class RaveeflixPlugin: Plugin() { 10 | override fun load(context: Context) { 11 | // All providers should be added in this manner. Please don't edit the providers list directly. 12 | registerMainAPI(Raveeflix()) 13 | } 14 | } -------------------------------------------------------------------------------- /Dubbindo/src/main/kotlin/com/dubbindo/DubbindoPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.dubbindo 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | 7 | @CloudstreamPlugin 8 | class DubbindoPlugin : Plugin() { 9 | override fun load(context: Context) { 10 | // All providers should be added in this manner. Please don't edit the providers list 11 | // directly. 12 | registerMainAPI(Dubbindo()) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Samehadaku/src/main/kotlin/com/samehadaku/SamehadakuPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.samehadaku 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | 7 | @CloudstreamPlugin 8 | class SamehadakuPlugin : Plugin() { 9 | override fun load(context: Context) { 10 | // All providers should be added in this manner. Please don't edit the providers list 11 | // directly. 12 | registerMainAPI(Samehadaku()) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /AnimeSail/src/main/kotlin/com/animesail/AnimeSailPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.animesail 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | 7 | @CloudstreamPlugin 8 | class AnimeSailPlugin : Plugin() { 9 | 10 | override fun load(context: Context) { 11 | 12 | // All providers should be added in this manner. Please don't edit the providers list 13 | // directly. 14 | registerMainAPI(AnimeSail()) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Nekopoi/src/main/kotlin/com/nekopoi/NekopoiPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.nekopoi 2 | 3 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 4 | import com.lagradost.cloudstream3.plugins.Plugin 5 | import android.content.Context 6 | 7 | @CloudstreamPlugin 8 | class NekopoiPlugin: Plugin() { 9 | override fun load(context: Context) { 10 | // All providers should be added in this manner. Please don't edit the providers list directly. 11 | registerMainAPI(Nekopoi()) 12 | registerExtractorAPI(ZippyShare()) 13 | } 14 | } -------------------------------------------------------------------------------- /Oploverz/src/main/kotlin/com/oploverz/OploverzPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.oploverz 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | 7 | @CloudstreamPlugin 8 | class OploverzPlugin : Plugin() { 9 | override fun load(context: Context) { 10 | // All providers should be added in this manner. Please don't edit the providers list 11 | // directly. 12 | registerMainAPI(Oploverz()) 13 | registerExtractorAPI(Qiwi()) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Dutamovie/src/main/kotlin/com/dutamovie/Extractors.kt: -------------------------------------------------------------------------------- 1 | package com.dutamovie 2 | 3 | import com.lagradost.cloudstream3.extractors.JWPlayer 4 | 5 | 6 | class Embedfirex : JWPlayer() { 7 | override var name = "embedpyrox" 8 | override var mainUrl = "https://embedpyrox.xyz" 9 | } 10 | 11 | class Embedfirex : JWPlayer() { 12 | override var name = "helvid" 13 | override var mainUrl = "https://helvid.net" 14 | } 15 | 16 | class Embedfirex : JWPlayer() { 17 | override var name = "p2pplay" 18 | override var mainUrl = "https://pm21.p2pplay.pro" 19 | } 20 | -------------------------------------------------------------------------------- /Dutamovie/build.gradle.kts: -------------------------------------------------------------------------------- 1 | version = 3 2 | 3 | cloudstream { 4 | description = "DutaMovie" 5 | language = "id" 6 | authors = listOf("Hexated", "TeKuma25") 7 | 8 | /** 9 | * Status int as the following: 10 | * 0: Down 11 | * 1: Ok 12 | * 2: Slow 13 | * 3: Beta only 14 | * */ 15 | status = 1 // will be 3 if unspecified 16 | tvTypes = listOf( 17 | "AsianDrama", 18 | "TvSeries", 19 | "Movie", 20 | ) 21 | 22 | iconUrl = "https://www.google.com/s2/favicons?domain=scandal.dutamovie21.cc&sz=256" 23 | } -------------------------------------------------------------------------------- /Pusatfilm/src/main/kotlin/com/pusatfilm/PusatfilmPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.pusatfilm 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | 7 | @CloudstreamPlugin 8 | class PusatfilmPlugin : Plugin() { 9 | override fun load(context: Context) { 10 | // All providers should be added in this manner. Please don't edit the providers list 11 | // directly. 12 | registerMainAPI(Pusatfilm()) 13 | registerExtractorAPI(Kotakajaib()) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Rebahin/src/main/kotlin/com/rebahin/RebahinPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.rebahin 2 | 3 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 4 | import com.lagradost.cloudstream3.plugins.Plugin 5 | import android.content.Context 6 | 7 | @CloudstreamPlugin 8 | class RebahinPlugin : Plugin() { 9 | override fun load(context: Context) { 10 | // All providers should be added in this manner. Please don't edit the providers list directly. 11 | registerMainAPI(Rebahin()) 12 | registerMainAPI(Kitanonton()) 13 | registerMainAPI(Cgvindo()) 14 | } 15 | } -------------------------------------------------------------------------------- /Dutamovie/src/main/kotlin/com/dutamovie/DutamoviePlugin.kt: -------------------------------------------------------------------------------- 1 | package com.dutamovie 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.extractors.JWPlayer 5 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 6 | import com.lagradost.cloudstream3.plugins.Plugin 7 | 8 | @CloudstreamPlugin 9 | class DutaMoviePlugin : Plugin() { 10 | override fun load(context: Context) { 11 | registerMainAPI(DutaMovie()) 12 | registerExtractorAPI(Ryderjet()) 13 | registerExtractorAPI(JWPlayer()) 14 | registerExtractorAPI(Embedfirex()) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DramaSerial/src/main/kotlin/com/dramaserial/DramaSerialPlugin.kt: -------------------------------------------------------------------------------- 1 | 2 | package com.dramaserial 3 | 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | import android.content.Context 7 | 8 | @CloudstreamPlugin 9 | class DramaSerialPlugin: Plugin() { 10 | override fun load(context: Context) { 11 | // All providers should be added in this manner. Please don't edit the providers list directly. 12 | registerMainAPI(DramaSerial()) 13 | registerExtractorAPI(Bk21()) 14 | registerExtractorAPI(Lkc21()) 15 | } 16 | } -------------------------------------------------------------------------------- /Minioppai/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 12 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | // description = "Lorem Ipsum" 10 | authors = listOf("Sora", "TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "NSFW", 22 | ) 23 | 24 | iconUrl = "https://www.google.com/s2/favicons?domain=minioppai.org&sz=%size%" 25 | } -------------------------------------------------------------------------------- /Minioppai/src/main/kotlin/com/minioppai/MinioppaiPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.minioppai 2 | 3 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 4 | import com.lagradost.cloudstream3.plugins.Plugin 5 | import android.content.Context 6 | 7 | @CloudstreamPlugin 8 | class MinioppaiPlugin: Plugin() { 9 | override fun load(context: Context) { 10 | // All providers should be added in this manner. Please don't edit the providers list directly. 11 | registerMainAPI(Minioppai()) 12 | registerExtractorAPI(Streampai()) 13 | registerExtractorAPI(Paistream()) 14 | registerExtractorAPI(TvMinioppai()) 15 | } 16 | } -------------------------------------------------------------------------------- /Nekopoi/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 7 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | // description = "Lorem Ipsum" 10 | authors = listOf("Sora", "TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "NSFW", 22 | ) 23 | 24 | iconUrl = "https://www.google.com/s2/favicons?domain=nekopoi.care&sz=%size%" 25 | } -------------------------------------------------------------------------------- /Ngefilm/src/main/kotlin/com/ngefilm/NgefilmPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.ngefilm 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.extractors.Chillx 5 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 6 | import com.lagradost.cloudstream3.plugins.Plugin 7 | 8 | @CloudstreamPlugin 9 | class NgefilmPlugin : Plugin() { 10 | override fun load(context: Context) { 11 | // All providers should be added in this manner. Please don't edit the providers list 12 | // directly. 13 | registerMainAPI(Ngefilm()) 14 | registerExtractorAPI(Boosterx()) 15 | registerExtractorAPI(Chillx()) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Nimegami/src/main/kotlin/com/nimegami/NimegamiPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.nimegami 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | 7 | @CloudstreamPlugin 8 | class NimegamiPlugin : Plugin() { 9 | override fun load(context: Context) { 10 | // All providers should be added in this manner. Please don't edit the providers list 11 | // directly. 12 | registerMainAPI(Nimegami()) 13 | registerExtractorAPI(Mitedrive()) 14 | registerExtractorAPI(Berkasdrive()) 15 | registerExtractorAPI(Videogami()) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Otakudesu/src/main/kotlin/com/otakudesu/OtakudesuPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.otakudesu 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | 7 | @CloudstreamPlugin 8 | class OtakudesuPlugin : Plugin() { 9 | override fun load(context: Context) { 10 | // All providers should be added in this manner. Please don't edit the providers list 11 | // directly. 12 | registerMainAPI(Otakudesu()) 13 | registerExtractorAPI(Moedesu()) 14 | registerExtractorAPI(DesuBeta()) 15 | registerExtractorAPI(Desudesuhd()) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /IndoTV/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 6 3 | 4 | 5 | cloudstream { 6 | // All of these properties are optional, you can safely remove them 7 | language = "id" 8 | description = "Indo IPTV" 9 | authors = listOf("TeKuma25") 10 | 11 | /** 12 | * Status int as the following: 13 | * 0: Down 14 | * 1: Ok 15 | * 2: Slow 16 | * 3: Beta only 17 | * */ 18 | status = 1 // will be 3 if unspecified 19 | tvTypes = listOf( 20 | "Live", 21 | ) 22 | 23 | iconUrl = "https://www.google.com/s2/favicons?domain=github.com&sz=%size%" 24 | 25 | isCrossPlatform = false 26 | } 27 | -------------------------------------------------------------------------------- /LayarKaca/src/main/kotlin/com/layarkaca/LayarKacaPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.layarkaca 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | 7 | @CloudstreamPlugin 8 | class LayarKacaPlugin : Plugin() { 9 | override fun load(context: Context) { 10 | // All providers should be added in this manner. Please don't edit the providers list 11 | // directly. 12 | registerMainAPI(LayarKaca()) 13 | registerExtractorAPI(Emturbovid()) 14 | registerExtractorAPI(Furher()) 15 | registerExtractorAPI(Hownetwork()) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Dramaid/src/main/kotlin/com/dramaid/DramaidPlugin.kt: -------------------------------------------------------------------------------- 1 | 2 | package com.dramaid 3 | 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | import android.content.Context 7 | 8 | @CloudstreamPlugin 9 | class DramaidPlugin: Plugin() { 10 | override fun load(context: Context) { 11 | // All providers should be added in this manner. Please don't edit the providers list directly. 12 | registerMainAPI(Dramaid()) 13 | registerMainAPI(Oppadrama()) 14 | registerExtractorAPI(Vanfem()) 15 | registerExtractorAPI(Filelions()) 16 | registerExtractorAPI(Gcam()) 17 | } 18 | } -------------------------------------------------------------------------------- /DramaSerial/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 7 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | description = "Drama Serial, harus pake vpn" 10 | authors = listOf("Hexated", "TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "AsianDrama", 22 | ) 23 | 24 | iconUrl = "https://www.google.com/s2/favicons?domain=tv3.dramaserial.id&sz=%size%" 25 | } -------------------------------------------------------------------------------- /Dramaid/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 13 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | description = "Include: Oppadrama" 10 | authors = listOf("Hexated", "TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "AsianDrama", 22 | "Movie", 23 | ) 24 | 25 | iconUrl = "https://www.google.com/s2/favicons?domain=dramaid.nl&sz=%size%" 26 | } -------------------------------------------------------------------------------- /Nodrakorid/src/main/kotlin/com/nodrakorid/NodrakoridPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.nodrakorid 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.extractors.Chillx 5 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 6 | import com.lagradost.cloudstream3.plugins.Plugin 7 | 8 | @CloudstreamPlugin 9 | class NodrakoridPlugin : Plugin() { 10 | override fun load(context: Context) { 11 | // All providers should be added in this manner. Please don't edit the providers list 12 | // directly. 13 | registerMainAPI(Nodrakorid()) 14 | registerExtractorAPI(Boosterx()) 15 | registerExtractorAPI(Chillx()) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Raveeflix/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 4 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | // description = "Lorem Ipsum" 10 | authors = listOf("Hexated", "TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "AsianDrama", 22 | "TvSeries", 23 | "Movie", 24 | ) 25 | 26 | iconUrl = "https://raveeflix.my.id/favicon.ico" 27 | } 28 | -------------------------------------------------------------------------------- /Animasu/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 13 3 | 4 | cloudstream { 5 | language = "id" 6 | // All of these properties are optional, you can safely remove them 7 | 8 | // description = "Lorem Ipsum" 9 | authors = listOf("Hexated", "TeKuma25") 10 | 11 | /** 12 | * Status int as the following: 13 | * 0: Down 14 | * 1: Ok 15 | * 2: Slow 16 | * 3: Beta only 17 | * */ 18 | status = 1 // will be 3 if unspecified 19 | tvTypes = listOf( 20 | "AnimeMovie", 21 | "OVA", 22 | "Anime", 23 | ) 24 | 25 | iconUrl = "https://www.google.com/s2/favicons?domain=animasu.cc&sz=%size%" 26 | } -------------------------------------------------------------------------------- /Nimegami/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 13 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | // description = "Lorem Ipsum" 10 | authors = listOf("TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "AnimeMovie", 22 | "Anime", 23 | "OVA", 24 | ) 25 | 26 | iconUrl = "https://www.google.com/s2/favicons?domain=nimegami.id&sz=%size%" 27 | } -------------------------------------------------------------------------------- /AnimeSail/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 15 3 | 4 | cloudstream { 5 | language = "id" 6 | // All of these properties are optional, you can safely remove them 7 | 8 | // description = "Lorem Ipsum" 9 | authors = listOf("Hexated", "TeKuma25") 10 | 11 | /** 12 | * Status int as the following: 13 | * 0: Down 14 | * 1: Ok 15 | * 2: Slow 16 | * 3: Beta only 17 | * */ 18 | status = 1 // will be 3 if unspecified 19 | tvTypes = listOf( 20 | "AnimeMovie", 21 | "Anime", 22 | "OVA", 23 | ) 24 | 25 | iconUrl = "https://www.google.com/s2/favicons?domain=154.26.137.28&sz=%size%" 26 | } -------------------------------------------------------------------------------- /Nodrakorid/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 1 3 | 4 | cloudstream { 5 | // All of these properties are optional, you can safely remove them 6 | 7 | description = "Nodrakorid" 8 | language = "id" 9 | authors = listOf("Hexated", "TeKuma25") 10 | 11 | /** 12 | * Status int as the following: 13 | * 0: Down 14 | * 1: Ok 15 | * 2: Slow 16 | * 3: Beta only 17 | * */ 18 | status = 1 // will be 3 if unspecified 19 | tvTypes = listOf( 20 | "AsianDrama", 21 | "TvSeries", 22 | "Movie", 23 | ) 24 | 25 | iconUrl = "https://tv.nodrakor22.sbs/wp-content/uploads/2025/01/22-2.png" 26 | } -------------------------------------------------------------------------------- /Oploverz/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 30 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | // description = "Lorem Ipsum" 10 | authors = listOf("TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "AnimeMovie", 22 | "Anime", 23 | "OVA", 24 | ) 25 | 26 | iconUrl = "https://www.google.com/s2/favicons?domain=oploverz.care&sz=%size%" 27 | } 28 | -------------------------------------------------------------------------------- /Otakudesu/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 16 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | // description = "Lorem Ipsum" 10 | authors = listOf("TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "AnimeMovie", 22 | "Anime", 23 | "OVA", 24 | ) 25 | 26 | iconUrl = "https://www.google.com/s2/favicons?domain=otakudesu.watch&sz=%size%" 27 | } -------------------------------------------------------------------------------- /Anoboy/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 1 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | // description = "Lorem Ipsum" 10 | authors = listOf("Hexated", "TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "AnimeMovie", 22 | "Anime", 23 | "OVA", 24 | ) 25 | 26 | iconUrl = "https://www.google.com/s2/favicons?domain=ww1.anoboy.app&sz=%size%" 27 | } -------------------------------------------------------------------------------- /Gomunime/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 4 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | // description = "Lorem Ipsum" 10 | authors = listOf("Hexated", "TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 0 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "AnimeMovie", 22 | "Anime", 23 | "OVA", 24 | ) 25 | 26 | iconUrl = "https://www.google.com/s2/favicons?domain=185.231.223.76&sz=%size%" 27 | } -------------------------------------------------------------------------------- /Kuronime/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 21 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | // description = "Lorem Ipsum" 10 | authors = listOf("Hexated", "TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "AnimeMovie", 22 | "Anime", 23 | "OVA", 24 | ) 25 | 26 | iconUrl = "https://www.google.com/s2/favicons?domain=kuronime.biz&sz=%size%" 27 | } -------------------------------------------------------------------------------- /Animasu/src/main/kotlin/com/animasu/AnimasuPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.animasu 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | 7 | @CloudstreamPlugin 8 | class AnimasuPlugin : Plugin() { 9 | override fun load(context: Context) { 10 | // All providers should be added in this manner. Please don't edit the providers list 11 | // directly. 12 | registerMainAPI(Animasu()) 13 | registerExtractorAPI(Archivd()) 14 | registerExtractorAPI(Newuservideo()) 15 | registerExtractorAPI(Vidhidepro()) 16 | registerExtractorAPI(Blogger()) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /AnimeIndo/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 24 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | // description = "Lorem Ipsum" 10 | authors = listOf("Hexated", "TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "AnimeMovie", 22 | "OVA", 23 | "Anime", 24 | ) 25 | 26 | iconUrl = "https://www.google.com/s2/favicons?domain=animeindo.xyz&sz=%size%" 27 | } -------------------------------------------------------------------------------- /Samehadaku/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 23 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | // description = "Lorem Ipsum" 10 | authors = listOf("TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "AnimeMovie", 22 | "OVA", 23 | "Anime", 24 | ) 25 | 26 | iconUrl = "https://www.google.com/s2/favicons?domain=https://samehadaku.world&sz=%size%" 27 | } -------------------------------------------------------------------------------- /Ngefilm/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 1 3 | 4 | 5 | cloudstream { 6 | 7 | // All of these properties are optional, you can safely remove them 8 | 9 | description = "Ngefilm" 10 | language = "id" 11 | authors = listOf("Hexated", "TeKuma25") 12 | 13 | /** 14 | * Status int as the following: 15 | * 0: Down 16 | * 1: Ok 17 | * 2: Slow 18 | * 3: Beta only 19 | * */ 20 | status = 1 // will be 3 if unspecified 21 | tvTypes = listOf( 22 | "AsianDrama", 23 | "TvSeries", 24 | "Movie", 25 | ) 26 | 27 | iconUrl = "https://new.ngefilm.site/wp-content/uploads/2022/06/20220602_221251.png" 28 | } -------------------------------------------------------------------------------- /NontonAnimeID/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 22 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | // description = "Lorem Ipsum" 10 | authors = listOf("Hexated", "TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 0 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "AnimeMovie", 22 | "Anime", 23 | "OVA", 24 | ) 25 | 26 | iconUrl = "https://www.google.com/s2/favicons?domain=nontonanimeid.org&sz=%size%" 27 | } -------------------------------------------------------------------------------- /Kuramanime/src/main/kotlin/com/kuramanime/KuramanimePlugin.kt: -------------------------------------------------------------------------------- 1 | package com.kuramanime 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | 7 | @CloudstreamPlugin 8 | class KuramanimePlugin : Plugin() { 9 | override fun load(context: Context) { 10 | // All providers should be added in this manner. Please don't edit the providers list 11 | // directly. 12 | registerMainAPI(Kuramanime()) 13 | registerExtractorAPI(Nyomo()) 14 | registerExtractorAPI(Streamhide()) 15 | registerExtractorAPI(Kuramadrive()) 16 | registerExtractorAPI(Lbx()) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Dubbindo/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 2 3 | 4 | cloudstream { 5 | language = "id" 6 | // All of these properties are optional, you can safely remove them 7 | 8 | // description = "Lorem Ipsum" 9 | authors = listOf("Hexated", "TeKuma25") 10 | 11 | /** 12 | * Status int as the following: 13 | * 0: Down 14 | * 1: Ok 15 | * 2: Slow 16 | * 3: Beta only 17 | * */ 18 | status = 1 // will be 3 if unspecified 19 | tvTypes = listOf( 20 | "TvSeries", 21 | "Movie", 22 | "Cartoon", 23 | "Anime", 24 | ) 25 | 26 | iconUrl = "https://www.google.com/s2/favicons?domain=www.dubbindo.site&sz=256" 27 | } -------------------------------------------------------------------------------- /Funmovieslix/src/main/kotlin/com/funmovieslix/FunmovieslixProvider.kt: -------------------------------------------------------------------------------- 1 | package com.funmovieslix 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.extractors.FileMoonIn 5 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 6 | import com.lagradost.cloudstream3.plugins.Plugin 7 | 8 | @CloudstreamPlugin 9 | class FunmovieslixProvider : Plugin() { 10 | override fun load(context: Context) { 11 | registerMainAPI(Funmovieslix()) 12 | registerExtractorAPI(Ryderjet()) 13 | registerExtractorAPI(FilemoonV2()) 14 | registerExtractorAPI(Dhtpre()) 15 | registerExtractorAPI(FileMoonIn()) 16 | registerExtractorAPI(Vidhideplus()) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Idlix/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 19 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | // description = "Lorem Ipsum" 10 | authors = listOf("Hexated", "TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "TvSeries", 22 | "Movie", 23 | "Anime", 24 | "AsianDrama", 25 | ) 26 | 27 | iconUrl = "hhttps://tv7.idlix.asia/wp-content/uploads/2020/07/logov4.png" 28 | } -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "CloudstreamPlugins" 2 | 3 | // This file sets what projects are included. 4 | // All new projects should get automatically included unless specified in the "disabled" variable. 5 | 6 | val disabled = listOf() 7 | 8 | File(rootDir, ".").eachDir { dir -> 9 | if (!disabled.contains(dir.name) && File(dir, "build.gradle.kts").exists()) { 10 | include(dir.name) 11 | } 12 | } 13 | 14 | fun File.eachDir(block: (File) -> Unit) { 15 | listFiles()?.filter { it.isDirectory }?.forEach { block(it) } 16 | } 17 | 18 | // To only include a single project, comment out the previous lines (except the first one), and include your plugin like so: 19 | // include("PluginName") -------------------------------------------------------------------------------- /Neonime/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 10 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | // description = "Lorem Ipsum" 10 | authors = listOf("Hexated", "TeKuma") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "AnimeMovie", 22 | "Anime", 23 | "Movie", 24 | "OVA", 25 | ) 26 | 27 | iconUrl = "https://www.google.com/s2/favicons?domain=otakupoi.org/neonime&sz=%size%" 28 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "java.configuration.updateBuildConfiguration": "automatic", 3 | "[kotlin]": { 4 | "editor.defaultFormatter": "esafirm.kotlin-formatter" 5 | }, 6 | "[xml]": { 7 | "editor.defaultFormatter": "redhat.vscode-xml" 8 | }, 9 | "terminal.integrated.profiles.windows": { 10 | "CS3 Log": { 11 | "overrideName": true, 12 | "source": "PowerShell", 13 | "args": [ 14 | "adb logcat -b all -c; adb logcat --pid=$(adb shell pidof -s com.lagradost.cloudstream3.prerelease)" 15 | ] 16 | } 17 | }, 18 | "editor.detectIndentation": false, 19 | "editor.indentSize": "tabSize", 20 | "editor.tabSize": 4, 21 | "java.format.settings.url": "eclipse-formatter.xml" 22 | } 23 | -------------------------------------------------------------------------------- /LayarKaca/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 23 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | // description = "Lorem Ipsum" 10 | authors = listOf("Hexated", "TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "AsianDrama", 22 | "TvSeries", 23 | "Movie", 24 | ) 25 | 26 | 27 | iconUrl = "https://www.google.com/s2/favicons?domain=amp.lk21official.mom&sz=%size%" 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Pusatfilm/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 2 3 | 4 | cloudstream { 5 | // All of these properties are optional, you can safely remove them 6 | description = "Pusatfilm is a plugin that provides streaming links for movies and TV series." 7 | language = "id" 8 | authors = listOf("Hexated", "TeKuma25") 9 | 10 | /** 11 | * Status int as the following: 12 | * 0: Down 13 | * 1: Ok 14 | * 2: Slow 15 | * 3: Beta only 16 | * */ 17 | status = 1 // will be 3 if unspecified 18 | tvTypes = listOf( 19 | "AsianDrama", 20 | "TvSeries", 21 | "Movie", 22 | ) 23 | 24 | iconUrl = "https://www.google.com/s2/favicons?domain=gomov.bio&sz=%size%" 25 | } -------------------------------------------------------------------------------- /Rebahin/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 11 3 | 4 | 5 | cloudstream { 6 | language = "id" 7 | // All of these properties are optional, you can safely remove them 8 | 9 | description = "Includes: Cgvindo, Kitanonton" 10 | authors = listOf("Hexated", "TeKuma25") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | tvTypes = listOf( 21 | "AsianDrama", 22 | "Anime", 23 | "TvSeries", 24 | "Movie", 25 | ) 26 | 27 | 28 | iconUrl = "https://www.google.com/s2/favicons?domain=rebahinxxi1.cfd&sz=%size%" 29 | } 30 | -------------------------------------------------------------------------------- /Gomov/src/main/kotlin/com/gomov/GomovPlugin.kt: -------------------------------------------------------------------------------- 1 | package com.gomov 2 | 3 | import android.content.Context 4 | import com.lagradost.cloudstream3.extractors.Chillx 5 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 6 | import com.lagradost.cloudstream3.plugins.Plugin 7 | 8 | @CloudstreamPlugin 9 | class GomovPlugin : Plugin() { 10 | override fun load(context: Context) { 11 | // All providers should be added in this manner. Please don't edit the providers list 12 | // directly. 13 | registerMainAPI(Gomov()) 14 | registerExtractorAPI(Chillx()) 15 | registerExtractorAPI(Watchx()) 16 | registerExtractorAPI(Boosterx()) 17 | registerExtractorAPI(Dhtpre()) 18 | registerExtractorAPI(Filelions()) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /NontonAnimeID/src/main/kotlin/com/nontonanimeid/NontonAnimeIDPlugin.kt: -------------------------------------------------------------------------------- 1 | 2 | package com.nontonanimeid 3 | 4 | import com.lagradost.cloudstream3.plugins.CloudstreamPlugin 5 | import com.lagradost.cloudstream3.plugins.Plugin 6 | import android.content.Context 7 | 8 | @CloudstreamPlugin 9 | class NontonAnimeIDPlugin: Plugin() { 10 | override fun load(context: Context) { 11 | // All providers should be added in this manner. Please don't edit the providers list directly. 12 | registerMainAPI(NontonAnimeID()) 13 | registerExtractorAPI(Nontonanimeid()) 14 | registerExtractorAPI(EmbedKotakAnimeid()) 15 | registerExtractorAPI(KotakAnimeidCom()) 16 | registerExtractorAPI(Gdplayer()) 17 | registerExtractorAPI(Kotaksb()) 18 | } 19 | } -------------------------------------------------------------------------------- /Funmovieslix/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 1 3 | 4 | 5 | cloudstream { 6 | // All of these properties are optional, you can safely remove them 7 | 8 | description = "Indonesia Source" 9 | language = "id" 10 | authors = listOf("Phisher98") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | 21 | // List of video source types. Users are able to filter for extensions in a given category. 22 | // You can find a list of avaliable types here: 23 | // https://recloudstream.github.io/cloudstream/html/app/com.lagradost.cloudstream3/-tv-type/index.html 24 | tvTypes = listOf("Movie","TvSeries") 25 | iconUrl = "https://raw.githubusercontent.com/phisher98/TVVVV/refs/heads/main/Funmovieslix.png" 26 | } 27 | -------------------------------------------------------------------------------- /Pencurimovie/build.gradle.kts: -------------------------------------------------------------------------------- 1 | // use an integer for version numbers 2 | version = 3 3 | 4 | 5 | cloudstream { 6 | // All of these properties are optional, you can safely remove them 7 | 8 | description = "Pencurimovie " 9 | language = "id" 10 | authors = listOf("Phisher98") 11 | 12 | /** 13 | * Status int as the following: 14 | * 0: Down 15 | * 1: Ok 16 | * 2: Slow 17 | * 3: Beta only 18 | * */ 19 | status = 1 // will be 3 if unspecified 20 | 21 | // List of video source types. Users are able to filter for extensions in a given category. 22 | // You can find a list of avaliable types here: 23 | // https://recloudstream.github.io/cloudstream/html/app/com.lagradost.cloudstream3/-tv-type/index.html 24 | tvTypes = listOf("Movie","TvSeries") 25 | iconUrl = "https://t2.gstatic.com/faviconV2?client=SOCIAL&type=FAVICON&fallback_opts=TYPE,SIZE,URL&url=https://ww03.pencurimovie.bond&size=%size%" 26 | } 27 | -------------------------------------------------------------------------------- /Nekopoi/src/main/kotlin/com/nekopoi/Extractors.kt: -------------------------------------------------------------------------------- 1 | package com.nekopoi 2 | 3 | import com.lagradost.cloudstream3.SubtitleFile 4 | import com.lagradost.cloudstream3.app 5 | import com.lagradost.cloudstream3.utils.ExtractorApi 6 | import com.lagradost.cloudstream3.utils.ExtractorLink 7 | import com.lagradost.cloudstream3.utils.newExtractorLink 8 | 9 | open class ZippyShare : ExtractorApi() { 10 | override val name = "ZippyShare" 11 | override val mainUrl = "https://zippysha.re" 12 | override val requiresReferer = true 13 | 14 | override suspend fun getUrl( 15 | url: String, 16 | referer: String?, 17 | subtitleCallback: (SubtitleFile) -> Unit, 18 | callback: (ExtractorLink) -> Unit 19 | ) { 20 | val res = app.get(url, referer = referer).document 21 | val video = res.selectFirst("a#download-url")?.attr("href") 22 | callback.invoke( 23 | newExtractorLink( 24 | name, 25 | name, 26 | video ?: return 27 | ){ 28 | this.referer = "$mainUrl/" 29 | } 30 | ) 31 | } 32 | } -------------------------------------------------------------------------------- /Gomov/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.konan.properties.Properties 2 | 3 | // use an integer for version numbers 4 | version = 35 5 | 6 | android { 7 | buildFeatures { 8 | buildConfig = true 9 | } 10 | defaultConfig { 11 | val properties = Properties() 12 | properties.load(project.rootProject.file("local.properties").inputStream()) 13 | buildConfigField("String", "ZSHOW_API", "\"${properties.getProperty("ZSHOW_API")}\"") 14 | } 15 | } 16 | 17 | cloudstream { 18 | language = "id" 19 | // All of these properties are optional, you can safely remove them 20 | 21 | description = "Includes: DutaMovie, Ngefilm, Nodrakorid, Multiplex, Pusatfilm" 22 | authors = listOf("Hexated", "TeKuma25") 23 | 24 | /** 25 | * Status int as the following: 26 | * 0: Down 27 | * 1: Ok 28 | * 2: Slow 29 | * 3: Beta only 30 | * */ 31 | status = 1 // will be 3 if unspecified 32 | tvTypes = listOf( 33 | "AsianDrama", 34 | "TvSeries", 35 | "Movie", 36 | ) 37 | 38 | iconUrl = "https://www.google.com/s2/favicons?domain=gomov.bio&sz=%size%" 39 | } -------------------------------------------------------------------------------- /Pusatfilm/src/main/kotlin/com/pusatfilm/Extractors.kt: -------------------------------------------------------------------------------- 1 | package com.pusatfilm 2 | 3 | import com.lagradost.cloudstream3.SubtitleFile 4 | import com.lagradost.cloudstream3.apmap 5 | import com.lagradost.cloudstream3.app 6 | import com.lagradost.cloudstream3.base64Decode 7 | import com.lagradost.cloudstream3.utils.ExtractorApi 8 | import com.lagradost.cloudstream3.utils.ExtractorLink 9 | import com.lagradost.cloudstream3.utils.loadExtractor 10 | 11 | open class Kotakajaib : ExtractorApi() { 12 | override val name = "Kotakajaib" 13 | override val mainUrl = "https://kotakajaib.me" 14 | override val requiresReferer = true 15 | 16 | override suspend fun getUrl( 17 | url: String, 18 | referer: String?, 19 | subtitleCallback: (SubtitleFile) -> Unit, 20 | callback: (ExtractorLink) -> Unit 21 | ) { 22 | app.get(url, referer = referer).document.select("ul#dropdown-server li a").apmap { 23 | loadExtractor( 24 | base64Decode(it.attr("data-frame")), 25 | "$mainUrl/", 26 | subtitleCallback, 27 | callback 28 | ) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/09_Other_Issue.yml: -------------------------------------------------------------------------------- 1 | name: 👀 Other Issue 2 | description: Any Other Issue 3 | assignees: tekuma25 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: | 8 | ### Other Issue 9 | If you have a any other Issue. 10 | 11 | - type: textarea 12 | id: Details 13 | attributes: 14 | label: Details 15 | placeholder: | 16 | Additional details and attachments. 17 | 18 | - type: checkboxes 19 | id: acknowledgements 20 | attributes: 21 | label: Acknowledgements 22 | description: Your issue will be closed if you haven't done these steps. 23 | options: 24 | - label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open or closed issue. 25 | required: true 26 | - label: I have written a title with source name. 27 | required: true 28 | - label: I have updated all installed extensions. 29 | required: true 30 | - label: I have opened WebView and checked that the source website is down. 31 | required: true 32 | - label: I will fill out all of the requested information in this form. 33 | required: true 34 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | android.buildFeatures.buildConfig=true 21 | # org.gradle.java.home=/usr/lib/jvm/java-17-openjdk 22 | -------------------------------------------------------------------------------- /Ngefilm/src/main/kotlin/com/ngefilm/Ngefilm.kt: -------------------------------------------------------------------------------- 1 | package com.ngefilm 2 | 3 | import com.lagradost.cloudstream3.* 4 | import com.lagradost.cloudstream3.MainAPI 5 | import com.lagradost.cloudstream3.mainPageOf 6 | 7 | class Ngefilm : MainAPI() { 8 | 9 | override var mainUrl = "https://new16.ngefilm.site/" 10 | 11 | override var name = "Ngefilm" 12 | override val hasMainPage = true 13 | override var lang = "id" 14 | override val supportedTypes = setOf(TvType.Movie, TvType.TvSeries, TvType.AsianDrama) 15 | override val mainPage = 16 | mainPageOf( 17 | "/page/%d/?s&search=advanced&post_type=movie&index&orderby&genre&movieyear&country&quality=" to 18 | "Movies Terbaru", 19 | "/page/%d/?s=&search=advanced&post_type=tv&index=&orderby=&genre=&movieyear=&country=&quality=" to 20 | "Series Terbaru", 21 | "/page/%d/?s=&search=advanced&post_type=tv&index=&orderby=&genre=drakor&movieyear=&country=&quality=" to 22 | "Series Korea", 23 | "/page/%d/?s=&search=advanced&post_type=tv&index=&orderby=&genre=&movieyear=&country=indonesia&quality=" to 24 | "Series Indonesia", 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /Oploverz/src/main/kotlin/com/oploverz/Extractors.kt: -------------------------------------------------------------------------------- 1 | package com.oploverz 2 | 3 | import com.lagradost.cloudstream3.* 4 | import com.lagradost.cloudstream3.SubtitleFile 5 | import com.lagradost.cloudstream3.utils.* 6 | 7 | open class Qiwi : ExtractorApi() { 8 | override val name = "Qiwi" 9 | override val mainUrl = "https://qiwi.gg" 10 | override val requiresReferer = true 11 | 12 | override suspend fun getUrl( 13 | url: String, 14 | referer: String?, 15 | subtitleCallback: (SubtitleFile) -> Unit, 16 | callback: (ExtractorLink) -> Unit 17 | ) { 18 | val document = app.get(url, referer = referer).document 19 | val title = document.select("title").text() 20 | val source = document.select("video source").attr("src") 21 | 22 | callback.invoke( 23 | newExtractorLink( 24 | name, 25 | name, 26 | source 27 | ){ 28 | this.referer = "$mainUrl/" 29 | this.quality = getIndexQuality(title) 30 | this.headers = mapOf("Range" to "bytes=0-") 31 | } 32 | 33 | ) 34 | } 35 | 36 | private fun getIndexQuality(str: String): Int { 37 | return Regex("(\\d{3,4})[pP]").find(str)?.groupValues?.getOrNull(1)?.toIntOrNull() 38 | ?: Qualities.Unknown.value 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Rebahin/src/main/kotlin/com/rebahin/Kitanonton.kt: -------------------------------------------------------------------------------- 1 | package com.rebahin 2 | 3 | import com.lagradost.cloudstream3.* 4 | 5 | class Kitanonton : Rebahin() { 6 | override var mainUrl = "http://kitanonton.cloud" 7 | override var name = "KitaNonton" 8 | override var mainServer = "https://kitanonton.cloud" 9 | 10 | override val mainPage = 11 | mainPageOf( 12 | "$mainUrl/genre/populer/page/" to "Populer Movies", 13 | "$mainUrl/movies/page/" to "New Movies", 14 | "$mainUrl/genre/westseries/page/" to "West TV Series", 15 | "$mainUrl/genre/drama-korea/page/" to "Drama Korea", 16 | "$mainUrl/genre/animation/page/" to "Anime", 17 | "$mainUrl/genre/series-indonesia/page/" to "Drama Indonesia", 18 | "$mainUrl/genre/drama-jepang/page/" to "Drama Jepang", 19 | "$mainUrl/genre/drama-china/page/" to "Drama China", 20 | "$mainUrl/genre/thailand-series/page/" to "Drama Thailand", 21 | ) 22 | 23 | override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { 24 | val document = app.get(request.data + page).document 25 | val home = document.select("div#featured div.ml-item").mapNotNull { it.toSearchResult() } 26 | return newHomePageResponse(request.name, home) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Kuramanime/build.gradle.kts: -------------------------------------------------------------------------------- 1 | dependencies { 2 | // implementation(kotlin("stdlib")) 3 | implementation("com.github.Blatzar:NiceHttp:0.4.11") 4 | implementation("org.jsoup:jsoup:1.18.3") 5 | implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.16.1") 6 | implementation("com.fasterxml.jackson.core:jackson-databind:2.16.1") 7 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.1") 8 | implementation("com.faendir.rhino:rhino-android:1.6.0") 9 | implementation("me.xdrop:fuzzywuzzy:1.4.0") 10 | implementation("com.google.code.gson:gson:2.11.0") 11 | implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3") 12 | implementation("app.cash.quickjs:quickjs-android:0.9.2") 13 | implementation("org.jsoup:jsoup:1.18.3") 14 | implementation("com.squareup.okhttp3:okhttp:4.11.0") 15 | implementation("androidx.core:core-ktx:1.16.0") 16 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1") 17 | } 18 | // use an integer for version numbers 19 | version = 39 20 | 21 | 22 | cloudstream { 23 | language = "id" 24 | // All of these properties are optional, you can safely remove them 25 | 26 | // description = "Lorem Ipsum" 27 | authors = listOf("TeKuma25") 28 | 29 | /** 30 | * Status int as the following: 31 | * 0: Down 32 | * 1: Ok 33 | * 2: Slow 34 | * 3: Beta only 35 | * */ 36 | status = 1 // will be 3 if unspecified 37 | tvTypes = listOf( 38 | "AnimeMovie", 39 | "Anime", 40 | "OVA", 41 | ) 42 | 43 | iconUrl = "https://www.google.com/s2/favicons?domain=kuramanime.com&sz=%size%" 44 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/02_site-request.yml: -------------------------------------------------------------------------------- 1 | name: ⭐ Source Request 2 | description: Request a new Source 3 | labels: [Site request] 4 | assignees: tekuma25 5 | body: 6 | - type: input 7 | id: name 8 | attributes: 9 | label: Source name 10 | placeholder: | 11 | Example: "Not Real Source" 12 | validations: 13 | required: true 14 | 15 | - type: input 16 | id: link 17 | attributes: 18 | label: Source link 19 | placeholder: | 20 | Example: "https://notrealsource.org" 21 | validations: 22 | required: true 23 | 24 | - type: input 25 | id: language 26 | attributes: 27 | label: Source language 28 | placeholder: | 29 | Example: "Hindi" 30 | validations: 31 | required: true 32 | 33 | - type: textarea 34 | id: other-details 35 | attributes: 36 | label: Other details 37 | placeholder: | 38 | Additional details and attachments. 39 | Example: "+18/NSFW = yes" 40 | 41 | - type: checkboxes 42 | id: acknowledgements 43 | attributes: 44 | label: Acknowledgements 45 | description: Your issue will be closed if you haven't done these steps. 46 | options: 47 | - label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open or closed issue. 48 | required: true 49 | - label: I have written a title with source name. 50 | required: true 51 | - label: I have checked that the extension does not already exist on the any Dev Repo or Request. 52 | required: true 53 | - label: I have checked that the extension does not already exist by searching on CS and verified it. 54 | required: true 55 | - label: I will fill out all of the requested information in this form. 56 | required: true 57 | -------------------------------------------------------------------------------- /Funmovieslix/src/main/kotlin/com/funmovieslix/Extractors.kt: -------------------------------------------------------------------------------- 1 | package com.funmovieslix 2 | 3 | import com.lagradost.api.Log 4 | import com.lagradost.cloudstream3.SubtitleFile 5 | import com.lagradost.cloudstream3.extractors.VidhideExtractor 6 | import com.lagradost.cloudstream3.utils.ExtractorApi 7 | import com.lagradost.cloudstream3.utils.ExtractorLink 8 | import com.lagradost.cloudstream3.app 9 | import com.lagradost.cloudstream3.utils.ExtractorLinkType 10 | import com.lagradost.cloudstream3.utils.JsUnpacker 11 | import com.lagradost.cloudstream3.utils.Qualities 12 | 13 | 14 | class Ryderjet : VidhideExtractor() { 15 | override var mainUrl = "https://ryderjet.com" 16 | } 17 | 18 | class Dhtpre : VidhideExtractor() { 19 | override var mainUrl = "https://dhtpre.com" 20 | } 21 | 22 | 23 | class Vidhideplus : VidhideExtractor() { 24 | override var mainUrl = "https://vidhideplus.com" 25 | } 26 | 27 | class FilemoonV2 : ExtractorApi() { 28 | override var name = "Filemoon" 29 | override var mainUrl = "https://filemoon.to" 30 | override val requiresReferer = true 31 | 32 | override suspend fun getUrl( 33 | url: String, 34 | referer: String?, 35 | subtitleCallback: (SubtitleFile) -> Unit, 36 | callback: (ExtractorLink) -> Unit 37 | ) { 38 | Log.d("Phisher","I'm here") 39 | val href=app.get(url).document.selectFirst("iframe")?.attr("src") ?:"" 40 | Log.d("Phisher",href) 41 | val res= app.get(href, headers = mapOf("Accept-Language" to "en-US,en;q=0.5","sec-fetch-dest" to "iframe")).document.selectFirst("script:containsData(function(p,a,c,k,e,d))")?.data().toString() 42 | val m3u8= JsUnpacker(res).unpack()?.let { unPacked -> 43 | Regex("sources:\\[\\{file:\"(.*?)\"").find(unPacked)?.groupValues?.get(1) 44 | } 45 | Log.d("Phisher",m3u8.toString()) 46 | callback.invoke( 47 | ExtractorLink( 48 | this.name, 49 | this.name, 50 | m3u8 ?:"", 51 | url, 52 | Qualities.P1080.value, 53 | type = ExtractorLinkType.M3U8, 54 | ) 55 | ) 56 | } 57 | } -------------------------------------------------------------------------------- /Dramaid/src/main/kotlin/com/dramaid/Extractors.kt: -------------------------------------------------------------------------------- 1 | package com.dramaid 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.lagradost.cloudstream3.APIHolder 5 | import com.lagradost.cloudstream3.SubtitleFile 6 | import com.lagradost.cloudstream3.app 7 | import com.lagradost.cloudstream3.extractors.Filesim 8 | import com.lagradost.cloudstream3.extractors.XStreamCdn 9 | import com.lagradost.cloudstream3.utils.ExtractorApi 10 | import com.lagradost.cloudstream3.utils.ExtractorLink 11 | import com.lagradost.cloudstream3.utils.M3u8Helper 12 | 13 | open class Gcam : ExtractorApi() { 14 | override val name = "Gcam" 15 | override val mainUrl = "https://gdrive.cam" 16 | override val requiresReferer = true 17 | 18 | override suspend fun getUrl( 19 | url: String, 20 | referer: String?, 21 | subtitleCallback: (SubtitleFile) -> Unit, 22 | callback: (ExtractorLink) -> Unit 23 | ) { 24 | val response = app.get(url, referer = referer).text 25 | val kaken = "kaken\\s*=\\s*\"(.*)\"".toRegex().find(response)?.groupValues?.get(1) 26 | val json = app.get("https://cdn2.gdrive.cam/api/?${kaken ?: return}=&_=${APIHolder.unixTimeMS}").parsedSafe() 27 | 28 | json?.sources?.map { 29 | M3u8Helper.generateM3u8( 30 | name, 31 | it.file ?: return@map, 32 | "" 33 | ).forEach(callback) 34 | } 35 | 36 | json?.tracks?.map { 37 | subtitleCallback.invoke( 38 | SubtitleFile( 39 | it.label ?: return@map, 40 | it.file ?: return@map 41 | ) 42 | ) 43 | } 44 | 45 | } 46 | 47 | data class Tracks( 48 | @JsonProperty("file") val file: String? = null, 49 | @JsonProperty("label") val label: String? = null, 50 | ) 51 | 52 | data class Sources( 53 | @JsonProperty("file") val file: String? = null, 54 | ) 55 | 56 | data class Response( 57 | @JsonProperty("sources") val sources: ArrayList? = arrayListOf(), 58 | @JsonProperty("tracks") val tracks: ArrayList? = arrayListOf(), 59 | ) 60 | 61 | } 62 | 63 | class Vanfem : XStreamCdn() { 64 | override val name: String = "Vanfem" 65 | override val mainUrl: String = "https://vanfem.com" 66 | } 67 | 68 | class Filelions : Filesim() { 69 | override val name = "Filelions" 70 | override var mainUrl = "https://filelions.live" 71 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/01_report_issue.yml: -------------------------------------------------------------------------------- 1 | name: 🐞 Issue report 2 | description: Report a source issue 3 | labels: [Bug] 4 | assignees: tekuma25 5 | body: 6 | - type: input 7 | id: source 8 | attributes: 9 | label: Source Name 10 | description: | 11 | You can find the extension name in App. 12 | placeholder: | 13 | Example: "Anplay" 14 | validations: 15 | required: true 16 | 17 | - type: input 18 | id: language 19 | attributes: 20 | label: Source language 21 | placeholder: | 22 | Example: "Indonesian" 23 | validations: 24 | required: true 25 | 26 | - type: textarea 27 | id: reproduce-steps 28 | attributes: 29 | label: Steps to reproduce 30 | description: Provide an example of the issue. Be as specific as possible. 31 | placeholder: | 32 | Example: 33 | 1. First step (e.g. "Open Mahouka Koukou No Rettousei (first season)") 34 | 2. Second step (e.g. "Try to watch episode 15") 35 | 3. Issue here (e.g. "It shows a HTTP 403 error toast") 36 | validations: 37 | required: true 38 | 39 | - type: textarea 40 | id: expected-behavior 41 | attributes: 42 | label: Expected behavior 43 | placeholder: | 44 | Example: 45 | "This should happen..." 46 | validations: 47 | required: true 48 | 49 | - type: textarea 50 | id: actual-behavior 51 | attributes: 52 | label: Actual behavior 53 | placeholder: | 54 | Example: 55 | "This happened instead..." 56 | validations: 57 | required: true 58 | 59 | - type: input 60 | id: cs-version 61 | attributes: 62 | label: CloudStream Version 63 | description: | 64 | You can find your Cloudstream Version in Settings at Bottom. 65 | placeholder: | 66 | Example: "Red Icon -Version" or "Blue Icon - Version" 67 | validations: 68 | required: true 69 | 70 | - type: textarea 71 | id: other-details 72 | attributes: 73 | label: Other details 74 | placeholder: | 75 | Additional details and attachments. 76 | 77 | - type: checkboxes 78 | id: acknowledgements 79 | attributes: 80 | label: Acknowledgements 81 | description: Your issue will be closed if you haven't done these steps. 82 | options: 83 | - label: I have searched the existing issues and this is a new ticket, **NOT** a duplicate or related to another open or closed issue. 84 | required: true 85 | - label: I have written a short but informative title. 86 | required: true 87 | - label: I have updated the app to version **[Pre Release Updated Version](https://github.com/recloudstream/cloudstream/releases/tag/pre-release)**. 88 | required: true 89 | - label: I will fill out all of the requested information in this form. 90 | required: true 91 | -------------------------------------------------------------------------------- /Idlix/src/main/kotlin/com/idlix/Extractors.kt: -------------------------------------------------------------------------------- 1 | package com.idlix 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.lagradost.cloudstream3.SubtitleFile 5 | import com.lagradost.cloudstream3.app 6 | import com.lagradost.cloudstream3.utils.* 7 | import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson 8 | 9 | open class Jeniusplay : ExtractorApi() { 10 | override val name = "Jeniusplay" 11 | override val mainUrl = "https://jeniusplay.com" 12 | override val requiresReferer = true 13 | 14 | override suspend fun getUrl( 15 | url: String, 16 | referer: String?, 17 | subtitleCallback: (SubtitleFile) -> Unit, 18 | callback: (ExtractorLink) -> Unit 19 | ) { 20 | val document = app.get(url, referer = "$mainUrl/").document 21 | val hash = url.split("/").last().substringAfter("data=") 22 | 23 | val m3uLink = 24 | app.post( 25 | url = "$mainUrl/player/index.php?data=$hash&do=getVideo", 26 | data = mapOf("hash" to hash, "r" to "$referer"), 27 | referer = url, 28 | headers = mapOf("X-Requested-With" to "XMLHttpRequest") 29 | ) 30 | .parsed() 31 | .videoSource 32 | 33 | M3u8Helper.generateM3u8( 34 | this.name, 35 | m3uLink, 36 | url, 37 | ) 38 | .forEach(callback) 39 | 40 | document.select("script").map { script -> 41 | if (script.data().contains("eval(function(p,a,c,k,e,d)")) { 42 | val subData = 43 | getAndUnpack(script.data()) 44 | .substringAfter("\"tracks\":[") 45 | .substringBefore("],") 46 | tryParseJson>("[$subData]")?.map { subtitle -> 47 | subtitleCallback.invoke( 48 | SubtitleFile(getLanguage(subtitle.label ?: ""), subtitle.file) 49 | ) 50 | } 51 | } 52 | } 53 | } 54 | 55 | private fun getLanguage(str: String): String { 56 | return when { 57 | str.contains("indonesia", true) || str.contains("bahasa", true) -> "Indonesian" 58 | else -> str 59 | } 60 | } 61 | 62 | data class ResponseSource( 63 | @JsonProperty("hls") val hls: Boolean, 64 | @JsonProperty("videoSource") val videoSource: String, 65 | @JsonProperty("securedLink") val securedLink: String?, 66 | ) 67 | 68 | data class Tracks( 69 | @JsonProperty("kind") val kind: String?, 70 | @JsonProperty("file") val file: String, 71 | @JsonProperty("label") val label: String?, 72 | ) 73 | } 74 | -------------------------------------------------------------------------------- /Minioppai/src/main/kotlin/com/minioppai/Extractors.kt: -------------------------------------------------------------------------------- 1 | package com.minioppai 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.lagradost.cloudstream3.SubtitleFile 5 | import com.lagradost.cloudstream3.app 6 | import com.lagradost.cloudstream3.fixTitle 7 | import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson 8 | import com.lagradost.cloudstream3.utils.ExtractorApi 9 | import com.lagradost.cloudstream3.utils.ExtractorLink 10 | import com.lagradost.cloudstream3.utils.Qualities 11 | import com.lagradost.cloudstream3.utils.fixUrl 12 | import com.lagradost.cloudstream3.utils.newExtractorLink 13 | 14 | class Paistream : Streampai() { 15 | override val name = "Paistream" 16 | override val mainUrl = "https://paistream.my.id" 17 | } 18 | 19 | class TvMinioppai : Streampai() { 20 | override val name = "Minioppai" 21 | override val mainUrl = "https://tv.minioppai.org" 22 | } 23 | 24 | open class Streampai : ExtractorApi() { 25 | override val name = "Streampai" 26 | override val mainUrl = "https://streampai.my.id" 27 | override val requiresReferer = true 28 | 29 | override suspend fun getUrl( 30 | url: String, 31 | referer: String?, 32 | subtitleCallback: (SubtitleFile) -> Unit, 33 | callback: (ExtractorLink) -> Unit 34 | ) { 35 | val res = app.get(url, referer = referer).document 36 | val data = res.selectFirst("script:containsData(player =)")?.data() ?: return 37 | 38 | val sources = data.substringAfter("sources: [").substringBefore("]") 39 | .addMarks("src") 40 | .addMarks("type") 41 | .addMarks("size") 42 | .replace("\'", "\"") 43 | 44 | val tracks = data.substringAfter("tracks: [").substringBefore("]") 45 | .replace("\'", "\"") 46 | 47 | 48 | tryParseJson>("[$sources]")?.forEach { 49 | callback.invoke( 50 | newExtractorLink( 51 | name, 52 | name, 53 | fixUrl(it.src) 54 | ){ 55 | this.referer = url 56 | this.quality = it.size ?: Qualities.Unknown.value 57 | this.headers = mapOf( 58 | "Range" to "bytes=0-", 59 | ) 60 | } 61 | ) 62 | } 63 | 64 | tryParseJson>("[$tracks]")?.forEach { 65 | subtitleCallback.invoke( 66 | SubtitleFile( 67 | fixTitle(it.label ?: return@forEach), 68 | fixUrl(it.src) 69 | ) 70 | ) 71 | } 72 | } 73 | 74 | private fun String.addMarks(str: String): String { 75 | return this.replace(Regex("\"?$str\"?"), "\"$str\"") 76 | } 77 | 78 | data class Responses( 79 | @JsonProperty("src") val src: String, 80 | @JsonProperty("type") val type: String?, 81 | @JsonProperty("label") val label: String?, 82 | @JsonProperty("size") val size: Int? 83 | ) 84 | 85 | } -------------------------------------------------------------------------------- /LayarKaca/src/main/kotlin/com/layarkaca/Extractors.kt: -------------------------------------------------------------------------------- 1 | package com.layarkaca 2 | 3 | import com.lagradost.cloudstream3.SubtitleFile 4 | import com.lagradost.cloudstream3.app 5 | import com.lagradost.cloudstream3.extractors.Filesim 6 | import com.lagradost.cloudstream3.utils.ExtractorApi 7 | import com.lagradost.cloudstream3.utils.ExtractorLink 8 | import com.lagradost.cloudstream3.utils.M3u8Helper 9 | import com.lagradost.cloudstream3.utils.getQualityFromName 10 | import com.lagradost.cloudstream3.utils.newExtractorLink 11 | 12 | open class Emturbovid : ExtractorApi() { 13 | override val name = "Emturbovid" 14 | override val mainUrl = "https://emturbovid.com" 15 | override val requiresReferer = true 16 | 17 | override suspend fun getUrl( 18 | url: String, 19 | referer: String?, 20 | subtitleCallback: (SubtitleFile) -> Unit, 21 | callback: (ExtractorLink) -> Unit 22 | ) { 23 | val response = app.get(url, referer = referer) 24 | val m3u8 = 25 | Regex("[\"'](.*?master\\.m3u8.*?)[\"']") 26 | .find(response.text) 27 | ?.groupValues 28 | ?.getOrNull(1) 29 | M3u8Helper.generateM3u8(name, m3u8 ?: return, mainUrl).forEach(callback) 30 | } 31 | } 32 | 33 | open class Hownetwork : ExtractorApi() { 34 | override val name = "Hownetwork" 35 | override val mainUrl = "https://cloud.hownetwork.xyz" 36 | override val requiresReferer = true 37 | 38 | override suspend fun getUrl( 39 | url: String, 40 | referer: String?, 41 | subtitleCallback: (SubtitleFile) -> Unit, 42 | callback: (ExtractorLink) -> Unit 43 | ) { 44 | val id = url.substringAfter("id=") 45 | val res = 46 | app.post( 47 | "$mainUrl/api.php?id=$id", 48 | data = 49 | mapOf( 50 | "r" to "https://playeriframe.sbs/", 51 | "d" to "stream.hownetwork.xyz", 52 | ), 53 | referer = url, 54 | headers = mapOf("X-Requested-With" to "XMLHttpRequest") 55 | ) 56 | .parsedSafe() 57 | 58 | res?.data?.map { 59 | callback.invoke( 60 | newExtractorLink( 61 | name, 62 | name, 63 | it.file 64 | ){ 65 | this.referer = url 66 | this.quality = getQualityFromName(it.label) 67 | } 68 | ) 69 | } 70 | } 71 | 72 | data class Sources(val data: ArrayList) { 73 | data class Data( 74 | val file: String, 75 | val label: String?, 76 | ) 77 | } 78 | } 79 | 80 | class FileMoon : Filesim() { 81 | override val name = "FileMoon" 82 | override var mainUrl = "https://filemoon.sx" 83 | } 84 | 85 | -------------------------------------------------------------------------------- /NontonAnimeID/src/main/kotlin/com/nontonanimeid/Extractors.kt: -------------------------------------------------------------------------------- 1 | package com.nontonanimeid 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.lagradost.cloudstream3.APIHolder 5 | import com.lagradost.cloudstream3.SubtitleFile 6 | import com.lagradost.cloudstream3.app 7 | import com.lagradost.cloudstream3.extractors.Hxfile 8 | import com.lagradost.cloudstream3.utils.ExtractorApi 9 | import com.lagradost.cloudstream3.utils.ExtractorLink 10 | import com.lagradost.cloudstream3.utils.Qualities 11 | import com.lagradost.cloudstream3.utils.newExtractorLink 12 | 13 | open class Gdplayer : ExtractorApi() { 14 | override val name = "Gdplayer" 15 | override val mainUrl = "https://gdplayer.to" 16 | override val requiresReferer = true 17 | 18 | override suspend fun getUrl( 19 | url: String, 20 | referer: String?, 21 | subtitleCallback: (SubtitleFile) -> Unit, 22 | callback: (ExtractorLink) -> Unit 23 | ) { 24 | val res = app.get(url, referer = referer).document 25 | val script = res.selectFirst("script:containsData(player = \"\")")?.data() 26 | val kaken = script?.substringAfter("kaken = \"")?.substringBefore("\"") 27 | 28 | val json = app.get( 29 | "$mainUrl/api/?${kaken ?: return}=&_=${APIHolder.unixTimeMS}", 30 | headers = mapOf( 31 | "X-Requested-With" to "XMLHttpRequest" 32 | ) 33 | ).parsedSafe() 34 | 35 | json?.sources?.map { 36 | callback.invoke( 37 | newExtractorLink( 38 | name, 39 | name, 40 | it.file ?: return@map 41 | ){ 42 | this.quality = getQuality(json.title) 43 | } 44 | ) 45 | } 46 | } 47 | 48 | private fun getQuality(str: String?): Int { 49 | return Regex("(\\d{3,4})[pP]").find(str ?: "")?.groupValues?.getOrNull(1)?.toIntOrNull() 50 | ?: Qualities.Unknown.value 51 | } 52 | 53 | data class Response( 54 | @JsonProperty("title") val title: String? = null, 55 | @JsonProperty("sources") val sources: ArrayList? = null, 56 | ) { 57 | data class Sources( 58 | @JsonProperty("file") val file: String? = null, 59 | @JsonProperty("type") val type: String? = null, 60 | ) 61 | } 62 | 63 | } 64 | 65 | class Nontonanimeid : Hxfile() { 66 | override val name = "Nontonanimeid" 67 | override val mainUrl = "https://nontonanimeid.com" 68 | override val requiresReferer = true 69 | } 70 | 71 | class EmbedKotakAnimeid : Hxfile() { 72 | override val name = "EmbedKotakAnimeid" 73 | override val mainUrl = "https://embed2.kotakanimeid.com" 74 | override val requiresReferer = true 75 | } 76 | 77 | class Kotaksb : Hxfile() { 78 | override val name = "Kotaksb" 79 | override val mainUrl = "https://kotaksb.fun" 80 | override val requiresReferer = true 81 | } 82 | 83 | class KotakAnimeidCom : Hxfile() { 84 | override val name = "KotakAnimeid" 85 | override val mainUrl = "https://kotakanimeid.com" 86 | override val requiresReferer = true 87 | } -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /Nimegami/src/main/kotlin/com/nimegami/Extractors.kt: -------------------------------------------------------------------------------- 1 | package com.nimegami 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.lagradost.cloudstream3.* 5 | import com.lagradost.cloudstream3.utils.* 6 | 7 | open class Mitedrive : ExtractorApi() { 8 | override val name = "Mitedrive" 9 | override val mainUrl = "https://mitedrive.com" 10 | override val requiresReferer = false 11 | 12 | override suspend fun getUrl( 13 | url: String, 14 | referer: String?, 15 | subtitleCallback: (SubtitleFile) -> Unit, 16 | callback: (ExtractorLink) -> Unit 17 | ) { 18 | val id = url.substringAfterLast("/") 19 | val video = 20 | app.post( 21 | "https://api.mitedrive.com/api/view/$id", 22 | referer = "$mainUrl/", 23 | data = 24 | mapOf( 25 | "csrf_token" to 26 | "ZXlKcGNDSTZJak0yTGpneExqWTFMakUyTWlJc0ltUmxkbWxqWlNJNklrMXZlbWxzYkdFdk5TNHdJQ2hYYVc1a2IzZHpJRTVVSURFd0xqQTdJRmRwYmpZME95QjROalE3SUhKMk9qRXdNUzR3S1NCSFpXTnJieTh5TURFd01ERXdNU0JHYVhKbFptOTRMekV3TVM0d0lpd2lZbkp2ZDNObGNpSTZJazF2ZW1sc2JHRWlMQ0pqYjI5cmFXVWlPaUlpTENKeVpXWmxjbkpsY2lJNklpSjk=", 27 | "slug" to id 28 | ) 29 | ) 30 | .parsedSafe() 31 | ?.data 32 | ?.url 33 | 34 | callback.invoke( 35 | newExtractorLink( 36 | name, 37 | name, 38 | video ?: return 39 | ){ 40 | this.referer = "$mainUrl/" 41 | } 42 | ) 43 | } 44 | 45 | data class Data( 46 | @JsonProperty("original_url") val url: String? = null, 47 | ) 48 | 49 | data class Responses( 50 | @JsonProperty("data") val data: Data? = null, 51 | ) 52 | } 53 | 54 | open class Berkasdrive : ExtractorApi() { 55 | override val name = "Berkasdrive" 56 | override val mainUrl = "https://dl.berkasdrive.com" 57 | override val requiresReferer = true 58 | 59 | override suspend fun getUrl( 60 | url: String, 61 | referer: String?, 62 | subtitleCallback: (SubtitleFile) -> Unit, 63 | callback: (ExtractorLink) -> Unit 64 | ) { 65 | val res = app.get(url, referer = referer).document 66 | val video = res.select("video#player source").attr("src") 67 | 68 | callback.invoke( 69 | newExtractorLink( 70 | name, 71 | name, 72 | video 73 | ){ 74 | this.referer = "$mainUrl/" 75 | } 76 | ) 77 | } 78 | } 79 | 80 | open class Videogami : ExtractorApi() { 81 | override val name = "Videogami" 82 | override val mainUrl = "https://video.nimegami.id" 83 | override val requiresReferer = false 84 | 85 | override suspend fun getUrl( 86 | url: String, 87 | referer: String?, 88 | subtitleCallback: (SubtitleFile) -> Unit, 89 | callback: (ExtractorLink) -> Unit 90 | ) { 91 | val id = base64Decode(url.substringAfter("url=")).substringAfterLast("/") 92 | loadExtractor("https://hxfile.co/embed-$id.html", "$mainUrl/", subtitleCallback, callback) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IndoStream: Kumpulan Ekstensi CloudStream untuk Konten Indonesia 2 | 3 | IndoStream adalah kumpulan ekstensi CloudStream yang berfokus pada penyediaan konten streaming dari berbagai sumber di Indonesia. Repositori ini berisi ekstensi yang memperluas fungsionalitas aplikasi CloudStream, memungkinkan pengguna untuk menikmati berbagai macam film, serial, dan anime dari situs-situs populer di Indonesia. 4 | 5 | ## Fitur Utama 6 | 7 | * **Beragam Sumber Konten:** Akses konten dari berbagai situs streaming populer di Indonesia. 8 | * **Mudah Digunakan:** Instalasi dan penggunaan yang sederhana melalui aplikasi CloudStream. 9 | * **Pembaruan Reguler:** Ekstensi diperbarui secara berkala untuk memastikan kompatibilitas dan ketersediaan konten. 10 | * **Fokus pada Konten Indonesia:** Kumpulan ekstensi ini berfokus pada konten yang relevan dengan pengguna di Indonesia. 11 | 12 | ## Daftar Ekstensi 13 | 14 | Berikut adalah daftar ekstensi yang tersedia di repositori IndoStream: 15 | 16 | | Nama Ekstensi | Status | 17 | | ------------- | --------------------------------- | 18 | | Animasu | Jalan, gambar poster tidak muncul | 19 | | Animindo | Error | 20 | | Animesail | Jalan | 21 | | Anoboy | Error | 22 | | Dramaid | Link Error. Oppadrama jalan | 23 | | DramaSerial | Error | 24 | | Dubbindo | Jalan | 25 | | Dutamovie | Butuh VPN | 26 | | Funmovieslix | Jalan | 27 | | Gomov | Butuh VPN, Link Error | 28 | | Gomunime | Down | 29 | | Idlix | Link Error | 30 | | IndoTV | Jalan | 31 | | Kuramanime | Butuh VPN, Link Error | 32 | | Kuronime | Link Error | 33 | | LayarKaca | Jalan | 34 | | Minioppai | Error | 35 | | Nekopoi | Butuh VPN | 36 | | Neonime | Error | 37 | | Ngefilm | Error | 38 | | Nimegami | Jalan, perlu perbaikan menu | 39 | | Nodrakorid | Error tidak bisa diinstal | 40 | | NontonAnimeID | Down | 41 | | Oploverz | Down | 42 | | Otakudesu | Jalan | 43 | | Pencurimovie | Jalan | 44 | | Pusatfilm | The Operation is not implemented | 45 | | Raveeflix | Down | 46 | | Rebahin | Butuh VPN, Link Error | 47 | | Samehadaku | Butuh VPN | 48 | | UseeTv | Error | 49 | 50 | ## Cara Menggunakan 51 | 52 | 1. Buka aplikasi CloudStream. 53 | 2. Buka menu "Ekstensi". 54 | 3. Klik tombol "Tambahkan Repositori". 55 | 4. Masukkan URL repositori IndoStream: https://raw.githubusercontent.com/TeKuma25/IndoStream/builds/repo.json 56 | 5. Klik "Tambahkan". 57 | 6. Ekstensi yang tersedia akan muncul di daftar. 58 | 7. Pilih ekstensi yang ingin Anda instal dan klik "Instal". 59 | 60 | ## Membangun Proyek 61 | 62 | Untuk membangun proyek ini, Anda memerlukan [Gradle](https://gradle.org/) yang terinstal. Anda dapat membangun proyek menggunakan perintah berikut: 63 | 64 | sh ./gradlew build 65 | 66 | ## Kontribusi 67 | 68 | Kami menyambut baik kontribusi dari komunitas! Jika Anda ingin menambahkan ekstensi baru, memperbaiki bug, atau meningkatkan dokumentasi, silakan buat *pull request* atau buka *issue*. 69 | -------------------------------------------------------------------------------- /Idlix/src/main/kotlin/com/idlix/CryptoJSAES.kt: -------------------------------------------------------------------------------- 1 | package com.idlix 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.fasterxml.jackson.databind.ObjectMapper 5 | import java.security.MessageDigest 6 | import java.util.* 7 | import javax.crypto.Cipher 8 | import javax.crypto.spec.IvParameterSpec 9 | import javax.crypto.spec.SecretKeySpec 10 | 11 | data class EncryptedData( 12 | @JsonProperty("ct") val ct: String, 13 | @JsonProperty("iv") val iv: String, 14 | @JsonProperty("s") val s: String 15 | ) 16 | 17 | object CryptoJsAes { 18 | private val objectMapper = ObjectMapper() 19 | 20 | fun encrypt(value: Any, passphrase: String): String { 21 | val salt = ByteArray(8) 22 | Random().nextBytes(salt) 23 | var salted = ByteArray(0) 24 | var dx = ByteArray(0) 25 | while (salted.size < 48) { 26 | dx = MessageDigest.getInstance("MD5").digest(dx + passphrase.toByteArray() + salt) 27 | salted += dx 28 | } 29 | val key = salted.copyOfRange(0, 32) 30 | val iv = salted.copyOfRange(32, 48) 31 | 32 | val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") 33 | cipher.init(Cipher.ENCRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv)) 34 | val encryptedData = cipher.doFinal(objectMapper.writeValueAsBytes(value)) 35 | 36 | val encryptedDataObj = 37 | EncryptedData( 38 | ct = Base64.getEncoder().encodeToString(encryptedData), 39 | iv = iv.toHex(), 40 | s = salt.toHex() 41 | ) 42 | 43 | return objectMapper.writeValueAsString(encryptedDataObj) 44 | } 45 | 46 | fun decrypt(jsonStr: String, passphrase: String): String? { 47 | val jsonData = objectMapper.readValue(jsonStr, EncryptedData::class.java) 48 | val salt = jsonData.s.hexToByteArray() 49 | val iv = jsonData.iv.hexToByteArray() 50 | val ct = Base64.getDecoder().decode(jsonData.ct) 51 | 52 | val concatedPassphrase = passphrase.toByteArray() + salt 53 | var result = MessageDigest.getInstance("MD5").digest(concatedPassphrase) 54 | repeat(2) { result += MessageDigest.getInstance("MD5").digest(result + concatedPassphrase) } 55 | val key = result.copyOfRange(0, 32) 56 | 57 | val cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") 58 | cipher.init(Cipher.DECRYPT_MODE, SecretKeySpec(key, "AES"), IvParameterSpec(iv)) 59 | val decryptedData = cipher.doFinal(ct) 60 | 61 | return try { 62 | String(decryptedData) 63 | } catch (e: Exception) { 64 | println("Error decoding JSON: ${e.message}") 65 | null 66 | } 67 | } 68 | 69 | private fun ByteArray.toHex(): String = joinToString("") { "%02x".format(it) } 70 | private fun String.hexToByteArray(): ByteArray = 71 | chunked(2).map { it.toInt(16).toByte() }.toByteArray() 72 | } 73 | 74 | fun addBase64Padding(b64String: String): String = 75 | b64String + "=".repeat((4 - b64String.length % 4) % 4) 76 | 77 | fun dec(r: String, e: String): String { 78 | val rList = r.chunked(2).filterIndexed { index, _ -> index % 2 == 0 } 79 | val mPadded = addBase64Padding(e.reversed()) 80 | val decodedM = 81 | try { 82 | String(Base64.getDecoder().decode(mPadded)) 83 | } catch (e: IllegalArgumentException) { 84 | println("Base64 decoding error: ${e.message}") 85 | return "" 86 | } 87 | 88 | return decodedM.split("|") 89 | .filter { it.toIntOrNull() != null && it.toInt() < rList.size } 90 | .joinToString("") { "\\x${rList[it.toInt()]}" } 91 | } 92 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | concurrency: 4 | group: "build" 5 | cancel-in-progress: true 6 | 7 | on: 8 | workflow_dispatch: # hanya jalan saat ditekan manual dari GitHub UI 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - name: Checkout main code 16 | uses: actions/checkout@v4 17 | with: 18 | path: src 19 | 20 | - name: Checkout builds (create if not exists) 21 | run: | 22 | REPO="https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}" 23 | if git ls-remote --exit-code $REPO builds; then 24 | echo "Branch 'builds' exists, checking out..." 25 | git clone --branch builds $REPO builds 26 | else 27 | echo "Branch 'builds' does not exist, creating..." 28 | git clone $REPO builds 29 | cd builds 30 | git checkout --orphan builds 31 | git rm -rf . 32 | echo "# builds branch" > README.md 33 | git add README.md 34 | git config user.email "actions@github.com" 35 | git config user.name "GitHub Actions" 36 | git commit -m "init builds branch" 37 | git push $REPO builds 38 | fi 39 | 40 | - name: Clean old builds 41 | run: | 42 | rm -f builds/*.cs3 || true 43 | rm -f builds/*.jar || true 44 | rm -f builds/plugins.json || true 45 | 46 | - name: Setup JDK 17 47 | uses: actions/setup-java@v4 48 | with: 49 | distribution: "adopt" 50 | java-version: 17 51 | 52 | - name: Setup Android SDK 53 | uses: android-actions/setup-android@v3 54 | 55 | - name: Access Secrets (local.properties) 56 | run: | 57 | cd src 58 | echo ANIMASU_API=${{ secrets.ANIMASU_API }} >> local.properties 59 | echo DUBBINDO_API=${{ secrets.DUBBINDO_API }} >> local.properties 60 | echo GOMOV_API=${{ secrets.GOMOV_API }} >> local.properties 61 | echo IDLIX_API=${{ secrets.IDLIX_API }} >> local.properties 62 | echo KURAMANIME_API=${{ secrets.KURAMANIME_API }} >> local.properties 63 | echo LAYARKACA_API=${{ secrets.LAYARKACA_API }} >> local.properties 64 | echo NIMEGAMI_API=${{ secrets.NIMEGAMI_API }} >> local.properties 65 | echo OPLOVERZ_API=${{ secrets.OPLOVERZ_API }} >> local.properties 66 | echo OTAKUDESU_API=${{ secrets.OTAKUDESU_API }} >> local.properties 67 | echo PENCURIMOVIE_API=${{ secrets.PENCURIMOVIE_API }} >> local.properties 68 | echo SAMEHADAKU_API=${{ secrets.SAMEHADAKU_API }} >> local.properties 69 | echo USEETV_API=${{ secrets.USEETV_API }} >> local.properties 70 | 71 | - name: Build Plugins 72 | run: | 73 | cd src 74 | chmod +x gradlew 75 | ./gradlew make makePluginsJson ensureJarCompatibility -x lint --continue 76 | cp **/build/*.cs3 ../builds || true 77 | cp **/build/*.jar ../builds || true 78 | cp build/plugins.json ../builds || true 79 | 80 | - name: Push builds 81 | run: | 82 | cd builds 83 | git config user.email "actions@github.com" 84 | git config user.name "GitHub Actions" 85 | git add . 86 | git commit --amend -m "Build $GITHUB_SHA" || exit 0 87 | git push --force "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}" builds 88 | 89 | - name: Upload Artifacts 90 | uses: actions/upload-artifact@v4 91 | with: 92 | name: builds-output 93 | path: | 94 | builds/*.cs3 95 | builds/*.jar 96 | builds/plugins.json 97 | -------------------------------------------------------------------------------- /Kuramanime/src/main/kotlin/com/kuramanime/Extractors.kt: -------------------------------------------------------------------------------- 1 | package com.kuramanime 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.lagradost.cloudstream3.SubtitleFile 5 | import com.lagradost.cloudstream3.app 6 | import com.lagradost.cloudstream3.extractors.Filesim 7 | import com.lagradost.cloudstream3.extractors.StreamSB 8 | import com.lagradost.cloudstream3.utils.ExtractorApi 9 | import com.lagradost.cloudstream3.utils.ExtractorLink 10 | import com.lagradost.cloudstream3.utils.Qualities 11 | import com.lagradost.cloudstream3.utils.getQualityFromName 12 | import com.lagradost.cloudstream3.utils.newExtractorLink 13 | 14 | class Nyomo : StreamSB() { 15 | override var name: String = "Nyomo" 16 | override var mainUrl = "https://nyomo.my.id" 17 | } 18 | 19 | class Streamhide : Filesim() { 20 | override var name: String = "Streamhide" 21 | override var mainUrl: String = "https://streamhide.to" 22 | } 23 | 24 | open class Lbx : ExtractorApi() { 25 | override val name = "Linkbox" 26 | override val mainUrl = "https://lbx.to" 27 | private val realUrl = "https://www.linkbox.to" 28 | override val requiresReferer = true 29 | 30 | override suspend fun getUrl( 31 | url: String, 32 | referer: String?, 33 | subtitleCallback: (SubtitleFile) -> Unit, 34 | callback: (ExtractorLink) -> Unit 35 | ) { 36 | val token = Regex("""(?:/f/|/file/|\?id=)(\w+)""").find(url)?.groupValues?.get(1) 37 | val id = 38 | app.get( 39 | "$realUrl/api/file/share_out_list/?sortField=utime&sortAsc=0&pageNo=1&pageSize=50&shareToken=$token" 40 | ) 41 | .parsedSafe() 42 | ?.data 43 | ?.itemId 44 | app.get("$realUrl/api/file/detail?itemId=$id", referer = url) 45 | .parsedSafe() 46 | ?.data 47 | ?.itemInfo 48 | ?.resolutionList 49 | ?.map { link -> 50 | callback.invoke( 51 | newExtractorLink( 52 | name, 53 | name, 54 | link.url ?: return@map null 55 | ){ 56 | this.referer = "$realUrl/" 57 | this.quality = getQualityFromName(link.resolution) 58 | } 59 | ) 60 | } 61 | } 62 | 63 | data class Resolutions( 64 | @JsonProperty("url") val url: String? = null, 65 | @JsonProperty("resolution") val resolution: String? = null, 66 | ) 67 | 68 | data class ItemInfo( 69 | @JsonProperty("resolutionList") 70 | val resolutionList: ArrayList? = arrayListOf(), 71 | ) 72 | 73 | data class Data( 74 | @JsonProperty("itemInfo") val itemInfo: ItemInfo? = null, 75 | @JsonProperty("itemId") val itemId: String? = null, 76 | ) 77 | 78 | data class Responses( 79 | @JsonProperty("data") val data: Data? = null, 80 | ) 81 | } 82 | 83 | open class Kuramadrive : ExtractorApi() { 84 | override val name = "DriveKurama" 85 | override val mainUrl = "https://kuramadrive.com" 86 | override val requiresReferer = true 87 | 88 | override suspend fun getUrl( 89 | url: String, 90 | referer: String?, 91 | subtitleCallback: (SubtitleFile) -> Unit, 92 | callback: (ExtractorLink) -> Unit 93 | ) { 94 | val req = app.get(url, referer = referer) 95 | val doc = req.document 96 | 97 | val title = doc.select("title").text() 98 | val token = doc.select("meta[name=csrf-token]").attr("content") 99 | val routeCheckAvl = doc.select("input#routeCheckAvl").attr("value") 100 | 101 | val json = 102 | app.get( 103 | routeCheckAvl, 104 | headers = 105 | mapOf( 106 | "X-Requested-With" to "XMLHttpRequest", 107 | "X-CSRF-TOKEN" to token 108 | ), 109 | referer = url, 110 | cookies = req.cookies 111 | ) 112 | .parsedSafe() 113 | 114 | callback.invoke( 115 | newExtractorLink( 116 | name, 117 | name, 118 | json?.url ?: return 119 | ){ 120 | this.referer = "$mainUrl/" 121 | this.quality = getIndexQuality(title) 122 | } 123 | ) 124 | } 125 | 126 | private fun getIndexQuality(str: String?): Int { 127 | return Regex("(\\d{3,4})[pP]").find(str ?: "")?.groupValues?.getOrNull(1)?.toIntOrNull() 128 | ?: Qualities.Unknown.value 129 | } 130 | 131 | private data class Source( 132 | @JsonProperty("url") val url: String, 133 | ) 134 | } 135 | -------------------------------------------------------------------------------- /Ngefilm/src/main/kotlin/com/ngefilm/Extractors.kt: -------------------------------------------------------------------------------- 1 | package com.ngefilm 2 | 3 | import com.lagradost.cloudstream3.SubtitleFile 4 | import com.lagradost.cloudstream3.USER_AGENT 5 | import com.lagradost.cloudstream3.app 6 | import com.lagradost.cloudstream3.base64DecodeArray 7 | import com.lagradost.cloudstream3.utils.ExtractorApi 8 | import com.lagradost.cloudstream3.utils.ExtractorLink 9 | import com.lagradost.cloudstream3.utils.Qualities 10 | import com.lagradost.cloudstream3.utils.newExtractorLink 11 | 12 | class Boosterx : Chillx() { 13 | override val name = "Boosterx" 14 | override val mainUrl = "https://boosterx.stream" 15 | } 16 | 17 | // Why are so mad at us Cracking it 18 | open class Chillx : ExtractorApi() { 19 | override val name = "Chillx" 20 | override val mainUrl = "https://chillx.top" 21 | override val requiresReferer = true 22 | 23 | override suspend fun getUrl( 24 | url: String, 25 | referer: String?, 26 | subtitleCallback: (SubtitleFile) -> Unit, 27 | callback: (ExtractorLink) -> Unit 28 | ) { 29 | try { 30 | // Fetch the raw response from the URL 31 | val res = app.get(url).toString() 32 | 33 | // Extract the encoded string using regex 34 | val encodedString = 35 | Regex("const\\s+\\w+\\s*=\\s*'(.*?)'").find(res)?.groupValues?.get(1) ?: "" 36 | if (encodedString.isEmpty()) { 37 | throw Exception("Encoded string not found") 38 | } 39 | // Decrypt the encoded string 40 | val password = "~%aRg@&H3&QEK1QV" 41 | val decryptedData = decryptXOR(encodedString, password) 42 | // Extract the m3u8 URL from decrypted data 43 | val m3u8 = 44 | Regex("\"?file\"?:\\s*\"([^\"]+)") 45 | .find(decryptedData) 46 | ?.groupValues 47 | ?.get(1) 48 | ?.trim() 49 | ?: "" 50 | if (m3u8.isEmpty()) { 51 | throw Exception("m3u8 URL not found") 52 | } 53 | 54 | // Prepare headers 55 | val headers = 56 | mapOf( 57 | "accept" to "*/*", 58 | "accept-language" to "en-US,en;q=0.5", 59 | "Origin" to mainUrl, 60 | "Accept-Encoding" to "gzip, deflate, br", 61 | "Connection" to "keep-alive", 62 | "Sec-Fetch-Dest" to "empty", 63 | "Sec-Fetch-Mode" to "cors", 64 | "Sec-Fetch-Site" to "cross-site", 65 | "user-agent" to USER_AGENT 66 | ) 67 | 68 | // Return the extractor link 69 | callback.invoke( 70 | newExtractorLink( 71 | name, 72 | name, 73 | m3u8 74 | ){ 75 | this.referer = mainUrl 76 | this.quality = Qualities.P1080.value 77 | this.headers = headers 78 | } 79 | ) 80 | 81 | // Extract and return subtitles 82 | val subtitles = extractSrtSubtitles(decryptedData) 83 | subtitles.forEachIndexed { _, (language, url) -> 84 | subtitleCallback.invoke(SubtitleFile(language, url)) 85 | } 86 | } catch (e: Exception) { 87 | println("Error: ${e.message}") 88 | } 89 | } 90 | 91 | private fun extractSrtSubtitles(subtitle: String): List> { 92 | val regex = """\[([^]]+)](https?://[^\s,]+\.srt)""".toRegex() 93 | return regex.findAll(subtitle) 94 | .map { match -> 95 | val (language, url) = match.destructured 96 | language.trim() to url.trim() 97 | } 98 | .toList() 99 | } 100 | 101 | private fun decryptXOR(encryptedData: String, password: String): String { 102 | return try { 103 | val decodedBytes = base64DecodeArray(encryptedData) 104 | val keyBytes = decodedBytes.sliceArray(0 until 16) 105 | val dataBytes = decodedBytes.sliceArray(16 until decodedBytes.size) 106 | val passwordBytes = password.toByteArray(Charsets.UTF_8) 107 | 108 | val decryptedBytes = 109 | dataBytes 110 | .mapIndexed { i, byte -> 111 | byte.toInt() xor 112 | passwordBytes[i % passwordBytes.size].toInt() xor 113 | keyBytes[i % keyBytes.size].toInt() 114 | } 115 | .map { it.toByte() } 116 | .toByteArray() 117 | 118 | String(decryptedBytes, Charsets.UTF_8) 119 | } catch (e: Exception) { 120 | e.printStackTrace() 121 | "Decryption Failed" 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /Nodrakorid/src/main/kotlin/com/nodrakorid/Extractors.kt: -------------------------------------------------------------------------------- 1 | package com.nodrakorid 2 | 3 | import com.lagradost.cloudstream3.SubtitleFile 4 | import com.lagradost.cloudstream3.USER_AGENT 5 | import com.lagradost.cloudstream3.app 6 | import com.lagradost.cloudstream3.base64DecodeArray 7 | import com.lagradost.cloudstream3.utils.ExtractorApi 8 | import com.lagradost.cloudstream3.utils.ExtractorLink 9 | import com.lagradost.cloudstream3.utils.Qualities 10 | import com.lagradost.cloudstream3.utils.newExtractorLink 11 | 12 | class Boosterx : Chillx() { 13 | override val name = "Boosterx" 14 | override val mainUrl = "https://boosterx.stream" 15 | } 16 | 17 | // Why are so mad at us Cracking it 18 | open class Chillx : ExtractorApi() { 19 | override val name = "Chillx" 20 | override val mainUrl = "https://chillx.top" 21 | override val requiresReferer = true 22 | 23 | override suspend fun getUrl( 24 | url: String, 25 | referer: String?, 26 | subtitleCallback: (SubtitleFile) -> Unit, 27 | callback: (ExtractorLink) -> Unit 28 | ) { 29 | try { 30 | // Fetch the raw response from the URL 31 | val res = app.get(url).toString() 32 | 33 | // Extract the encoded string using regex 34 | val encodedString = 35 | Regex("const\\s+\\w+\\s*=\\s*'(.*?)'").find(res)?.groupValues?.get(1) ?: "" 36 | if (encodedString.isEmpty()) { 37 | throw Exception("Encoded string not found") 38 | } 39 | // Decrypt the encoded string 40 | val password = "~%aRg@&H3&QEK1QV" 41 | val decryptedData = decryptXOR(encodedString, password) 42 | // Extract the m3u8 URL from decrypted data 43 | val m3u8 = 44 | Regex("\"?file\"?:\\s*\"([^\"]+)") 45 | .find(decryptedData) 46 | ?.groupValues 47 | ?.get(1) 48 | ?.trim() 49 | ?: "" 50 | if (m3u8.isEmpty()) { 51 | throw Exception("m3u8 URL not found") 52 | } 53 | 54 | // Prepare headers 55 | val headers = 56 | mapOf( 57 | "accept" to "*/*", 58 | "accept-language" to "en-US,en;q=0.5", 59 | "Origin" to mainUrl, 60 | "Accept-Encoding" to "gzip, deflate, br", 61 | "Connection" to "keep-alive", 62 | "Sec-Fetch-Dest" to "empty", 63 | "Sec-Fetch-Mode" to "cors", 64 | "Sec-Fetch-Site" to "cross-site", 65 | "user-agent" to USER_AGENT 66 | ) 67 | 68 | // Return the extractor link 69 | callback.invoke( 70 | newExtractorLink( 71 | name, 72 | name, 73 | m3u8 74 | ){ 75 | this.referer = mainUrl 76 | this.quality = Qualities.P1080.value 77 | this.headers = headers 78 | } 79 | ) 80 | 81 | // Extract and return subtitles 82 | val subtitles = extractSrtSubtitles(decryptedData) 83 | subtitles.forEachIndexed { _, (language, url) -> 84 | subtitleCallback.invoke(SubtitleFile(language, url)) 85 | } 86 | } catch (e: Exception) { 87 | println("Error: ${e.message}") 88 | } 89 | } 90 | 91 | private fun extractSrtSubtitles(subtitle: String): List> { 92 | val regex = """\[([^]]+)](https?://[^\s,]+\.srt)""".toRegex() 93 | return regex.findAll(subtitle) 94 | .map { match -> 95 | val (language, url) = match.destructured 96 | language.trim() to url.trim() 97 | } 98 | .toList() 99 | } 100 | 101 | private fun decryptXOR(encryptedData: String, password: String): String { 102 | return try { 103 | val decodedBytes = base64DecodeArray(encryptedData) 104 | val keyBytes = decodedBytes.sliceArray(0 until 16) 105 | val dataBytes = decodedBytes.sliceArray(16 until decodedBytes.size) 106 | val passwordBytes = password.toByteArray(Charsets.UTF_8) 107 | 108 | val decryptedBytes = 109 | dataBytes 110 | .mapIndexed { i, byte -> 111 | byte.toInt() xor 112 | passwordBytes[i % passwordBytes.size].toInt() xor 113 | keyBytes[i % keyBytes.size].toInt() 114 | } 115 | .map { it.toByte() } 116 | .toByteArray() 117 | 118 | String(decryptedBytes, Charsets.UTF_8) 119 | } catch (e: Exception) { 120 | e.printStackTrace() 121 | "Decryption Failed" 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /Dubbindo/src/main/kotlin/com/dubbindo/Dubbindo.kt: -------------------------------------------------------------------------------- 1 | package com.dubbindo 2 | 3 | import com.lagradost.cloudstream3.* 4 | import com.lagradost.cloudstream3.utils.AppUtils.toJson 5 | import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson 6 | import com.lagradost.cloudstream3.utils.ExtractorLink 7 | import com.lagradost.cloudstream3.utils.newExtractorLink 8 | import com.lagradost.cloudstream3.utils.Qualities 9 | import com.lagradost.cloudstream3.utils.loadExtractor 10 | import org.jsoup.nodes.Element 11 | 12 | class Dubbindo : MainAPI() { 13 | override var mainUrl = "https://www.dubbindo.site" 14 | override var name = "Dubbindo" 15 | override val hasMainPage = true 16 | override var lang = "id" 17 | override val hasDownloadSupport = true 18 | 19 | override val supportedTypes = 20 | setOf( 21 | TvType.TvSeries, 22 | TvType.Movie, 23 | TvType.Cartoon, 24 | TvType.Anime, 25 | ) 26 | 27 | override val mainPage = 28 | mainPageOf( 29 | "$mainUrl/videos/category/1" to "Movie", 30 | "$mainUrl/videos/category/3" to "TV Series", 31 | "$mainUrl/videos/category/5" to "Anime Series", 32 | "$mainUrl/videos/category/4" to "Anime Movie", 33 | "$mainUrl/videos/category/other" to "Other", 34 | ) 35 | 36 | override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { 37 | val document = app.get("${request.data}?page_id=$page").document 38 | val home = 39 | document.select("div.videos-latest-list.pt_timeline_vids div.video-wrapper") 40 | .mapNotNull { it.toSearchResult() } 41 | return newHomePageResponse( 42 | list = HomePageList(name = request.name, list = home, isHorizontalImages = true), 43 | hasNext = true 44 | ) 45 | } 46 | 47 | private fun Element.toSearchResult(): TvSeriesSearchResponse? { 48 | val title = this.selectFirst("h4,div.video-title")?.text()?.trim() ?: "" 49 | val href = this.selectFirst("a")?.attr("href") ?: return null 50 | val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src")) 51 | return newTvSeriesSearchResponse(title, href, TvType.TvSeries) { 52 | this.posterUrl = posterUrl 53 | } 54 | } 55 | 56 | override suspend fun search(query: String): List { 57 | val searchResponse = mutableListOf() 58 | for (i in 1..10) { 59 | val document = 60 | app.get( 61 | "$mainUrl/search?keyword=$query&page_id=$i", 62 | ) 63 | .document 64 | val results = 65 | document.select("div.videos-latest-list.row div.video-wrapper").mapNotNull { 66 | it.toSearchResult() 67 | } 68 | searchResponse.addAll(results) 69 | if (results.isEmpty()) break 70 | } 71 | return searchResponse 72 | } 73 | 74 | override suspend fun load(url: String): LoadResponse? { 75 | val document = app.get(url).document 76 | 77 | val title = document.selectFirst("div.video-big-title h1")?.text() ?: return null 78 | val poster = document.selectFirst("meta[property=og:image]")?.attr("content") 79 | val tags = document.select("div.pt_categories li a").map { it.text() } 80 | val description = document.select("div.watch-video-description p").text() 81 | val recommendations = 82 | document.select("div.related-video-wrapper").mapNotNull { it.toSearchResult() } 83 | val video = 84 | document.select("video#my-video source").map { 85 | Video( 86 | it.attr("src"), 87 | it.attr("size"), 88 | it.attr("type"), 89 | ) 90 | } 91 | 92 | return newMovieLoadResponse(title, url, TvType.Movie, video.toJson()) { 93 | posterUrl = poster 94 | plot = description 95 | this.tags = tags 96 | this.recommendations = recommendations 97 | } 98 | } 99 | 100 | override suspend fun loadLinks( 101 | data: String, 102 | isCasting: Boolean, 103 | subtitleCallback: (SubtitleFile) -> Unit, 104 | callback: (ExtractorLink) -> Unit 105 | ): Boolean { 106 | 107 | tryParseJson>(data)?.map { video -> 108 | if (video.type == "video/mp4" || 109 | video.type == "video/x-msvideo" || 110 | video.type == "video/x-matroska" 111 | ) { 112 | callback.invoke( 113 | newExtractorLink( 114 | this.name, 115 | this.name, 116 | video.src.toString() 117 | ){ 118 | this.quality = video.res?.toIntOrNull() ?: Qualities.Unknown.value 119 | } 120 | ) 121 | } else { 122 | loadExtractor(video.src ?: return@map, "", subtitleCallback, callback) 123 | } 124 | } 125 | 126 | return true 127 | } 128 | 129 | data class Video( 130 | val src: String? = null, 131 | val res: String? = null, 132 | val type: String? = null, 133 | ) 134 | } 135 | -------------------------------------------------------------------------------- /Animasu/src/main/kotlin/com/animasu/Extractors.kt: -------------------------------------------------------------------------------- 1 | package com.animasu 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.lagradost.cloudstream3.SubtitleFile 5 | import com.lagradost.cloudstream3.app 6 | import com.lagradost.cloudstream3.extractors.Filesim 7 | import com.lagradost.cloudstream3.utils.AppUtils 8 | import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson 9 | import com.lagradost.cloudstream3.utils.ExtractorApi 10 | import com.lagradost.cloudstream3.utils.ExtractorLink 11 | import com.lagradost.cloudstream3.utils.INFER_TYPE 12 | import com.lagradost.cloudstream3.utils.Qualities 13 | import com.lagradost.cloudstream3.utils.newExtractorLink 14 | 15 | class Archivd : ExtractorApi() { 16 | override val name: String = "Archivd" 17 | override val mainUrl: String = "https://archivd.net" 18 | override val requiresReferer = true 19 | 20 | override suspend fun getUrl( 21 | url: String, 22 | referer: String?, 23 | subtitleCallback: (SubtitleFile) -> Unit, 24 | callback: (ExtractorLink) -> Unit 25 | ) { 26 | val res = app.get(url).document 27 | val json = res.select("div#app").attr("data-page") 28 | val video = tryParseJson(json)?.props?.datas?.data?.link?.media 29 | callback.invoke( 30 | newExtractorLink( 31 | name, 32 | name, 33 | video ?: return, 34 | INFER_TYPE 35 | ) { 36 | this.referer = mainUrl 37 | this.quality = Qualities.P1080.value 38 | this.headers = headers 39 | } 40 | ) 41 | } 42 | 43 | data class Link( 44 | @JsonProperty("media") val media: String? = null, 45 | ) 46 | 47 | data class Data( 48 | @JsonProperty("link") val link: Link? = null, 49 | ) 50 | 51 | data class Datas( 52 | @JsonProperty("data") val data: Data? = null, 53 | ) 54 | 55 | data class Props( 56 | @JsonProperty("datas") val datas: Datas? = null, 57 | ) 58 | 59 | data class Sources( 60 | @JsonProperty("props") val props: Props? = null, 61 | ) 62 | } 63 | 64 | open class Newuservideo : ExtractorApi() { 65 | override val name: String = "Uservideo" 66 | override val mainUrl: String = "https://uservideo.xyz" 67 | override val requiresReferer = false 68 | 69 | override suspend fun getUrl( 70 | url: String, 71 | referer: String?, 72 | subtitleCallback: (SubtitleFile) -> Unit, 73 | callback: (ExtractorLink) -> Unit 74 | ) { 75 | val script = app.get(url).document.selectFirst("script:containsData(hosts =)")?.data() 76 | val host = script?.substringAfter("hosts = [\"")?.substringBefore("\"];") 77 | val servers = script?.substringAfter("servers = \"")?.substringBefore("\";") 78 | 79 | val sources = app.get("$host/s/$servers").text.substringAfter("\"sources\":[").substringBefore("],").let { 80 | AppUtils.tryParseJson>("[$it]") 81 | } 82 | val quality = Regex("(\\d{3,4})[Pp]").find(url)?.groupValues?.getOrNull(1)?.toIntOrNull() 83 | 84 | sources?.map { source -> 85 | callback.invoke( 86 | newExtractorLink( 87 | name, 88 | name, 89 | source.src ?: return@map null 90 | ) { 91 | this.referer = url 92 | this.quality = quality ?: Qualities.Unknown.value 93 | } 94 | ) 95 | } 96 | 97 | } 98 | 99 | data class Sources( 100 | @JsonProperty("src") val src: String? = null, 101 | @JsonProperty("type") val type: String? = null, 102 | @JsonProperty("label") val label: String? = null, 103 | ) 104 | 105 | } 106 | 107 | class Vidhidepro : Filesim() { 108 | override val mainUrl = "https://vidhidepro.com" 109 | override val name = "Vidhidepro" 110 | } 111 | 112 | open class Blogger : ExtractorApi() { 113 | override val name = "Blogger" 114 | override val mainUrl = "https://www.blogger.com" 115 | override val requiresReferer = false 116 | 117 | override suspend fun getUrl(url: String, referer: String?): List { 118 | val sources = mutableListOf() 119 | with(app.get(url).document) { 120 | this.select("script").map { script -> 121 | if (script.data().contains("\"streams\":[")) { 122 | val data = script.data().substringAfter("\"streams\":[") 123 | .substringBefore("]") 124 | tryParseJson>("[$data]")?.map { 125 | sources.add( 126 | newExtractorLink( 127 | name, 128 | name, 129 | it.play_url, 130 | ) { 131 | this.referer = "https://www.youtube.com/" 132 | this.quality = when (it.format_id) { 133 | 18 -> 360 134 | 22 -> 720 135 | else -> Qualities.Unknown.value 136 | } 137 | } 138 | ) 139 | } 140 | } 141 | } 142 | } 143 | return sources 144 | } 145 | 146 | private data class ResponseSource( 147 | @JsonProperty("play_url") val play_url: String, 148 | @JsonProperty("format_id") val format_id: Int 149 | ) 150 | } -------------------------------------------------------------------------------- /Minioppai/src/main/kotlin/com/minioppai/Minioppai.kt: -------------------------------------------------------------------------------- 1 | package com.minioppai 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.lagradost.cloudstream3.* 5 | import com.lagradost.cloudstream3.utils.* 6 | import org.jsoup.Jsoup 7 | import org.jsoup.nodes.Element 8 | import java.net.URLDecoder 9 | 10 | class Minioppai : MainAPI() { 11 | override var mainUrl = "https://minioppai.org" 12 | override var name = "Minioppai" 13 | override val hasMainPage = true 14 | override var lang = "id" 15 | override val hasDownloadSupport = true 16 | override val hasQuickSearch = true 17 | override val supportedTypes = setOf( 18 | TvType.NSFW, 19 | ) 20 | 21 | companion object { 22 | fun getStatus(t: String?): ShowStatus { 23 | return when (t) { 24 | "Completed" -> ShowStatus.Completed 25 | "Ongoing" -> ShowStatus.Ongoing 26 | else -> ShowStatus.Completed 27 | } 28 | } 29 | } 30 | 31 | override val mainPage = mainPageOf( 32 | "$mainUrl/watch" to "New Episode", 33 | "$mainUrl/populars" to "Popular Hentai", 34 | ) 35 | 36 | override suspend fun getMainPage( 37 | page: Int, 38 | request: MainPageRequest 39 | ): HomePageResponse { 40 | val document = app.get("${request.data}/page/$page").document 41 | val home = document.select("div.latest a").mapNotNull { 42 | it.toSearchResult() 43 | } 44 | return newHomePageResponse( 45 | list = HomePageList( 46 | name = request.name, 47 | list = home, 48 | isHorizontalImages = request.name == "New Episode" 49 | ), 50 | hasNext = true 51 | ) 52 | } 53 | 54 | private fun getProperAnimeLink(uri: String): String { 55 | return if (uri.contains("-episode-")) { 56 | uri.substringBefore("-episode-") 57 | } else { 58 | uri 59 | } 60 | } 61 | 62 | private fun Element.toSearchResult(): AnimeSearchResponse? { 63 | val title = this.selectFirst("h2.entry-title")?.text()?.trim() ?: return null 64 | val href = getProperAnimeLink(this.attr("href")) 65 | val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src")) 66 | val epNum = this.selectFirst("i.dot")?.text()?.filter { it.isDigit() }?.toIntOrNull() 67 | return newAnimeSearchResponse(title, href, TvType.NSFW) { 68 | this.posterUrl = posterUrl 69 | addSub(epNum) 70 | } 71 | 72 | } 73 | 74 | override suspend fun quickSearch(query: String): List? = search(query) 75 | 76 | override suspend fun search(query: String): List? { 77 | return app.post( 78 | "$mainUrl/wp-admin/admin-ajax.php", data = mapOf( 79 | "action" to "ts_ac_do_search", 80 | "ts_ac_query" to query, 81 | ), headers = mapOf("X-Requested-With" to "XMLHttpRequest"), 82 | ).parsedSafe()?.post?.firstOrNull()?.all?.mapNotNull { item -> 83 | newAnimeSearchResponse( 84 | item.postTitle ?: "", 85 | item.postLink ?: return@mapNotNull null, 86 | TvType.NSFW 87 | ) { 88 | this.posterUrl = item.postImage 89 | } 90 | } 91 | } 92 | 93 | override suspend fun load(url: String): LoadResponse? { 94 | val document = app.get(url).document 95 | 96 | val title = document.selectFirst("h1.entry-title")?.text()?.trim() ?: return null 97 | val poster = fixUrlNull(document.selectFirst("div.limage img")?.attr("src")) 98 | val table = document.select("ul.data") 99 | val tags = table.select("ul.data li:nth-child(1) a").map { it.text() } 100 | val year = 101 | document.selectFirst("ul.data time[itemprop=dateCreated]")?.text()?.substringBefore("-") 102 | ?.toIntOrNull() 103 | val status = getStatus(document.selectFirst("ul.data li:nth-child(2) span")?.text()?.trim()) 104 | val description = document.select("div[itemprop=description] > p").text() 105 | 106 | val episodes = document.select("div.epsdlist ul li").mapNotNull { 107 | val name = it.selectFirst("div.epl-num")?.text() 108 | val link = fixUrlNull(it.selectFirst("a")?.attr("href")) ?: return@mapNotNull null 109 | newEpisode(link){ 110 | this.name = name 111 | } 112 | } 113 | 114 | return newAnimeLoadResponse(title, url, TvType.NSFW) { 115 | engName = title 116 | posterUrl = poster 117 | this.year = year 118 | addEpisodes(DubStatus.Subbed, episodes) 119 | showStatus = status 120 | plot = description 121 | this.tags = tags 122 | } 123 | } 124 | 125 | override suspend fun loadLinks( 126 | data: String, 127 | isCasting: Boolean, 128 | subtitleCallback: (SubtitleFile) -> Unit, 129 | callback: (ExtractorLink) -> Unit 130 | ): Boolean { 131 | val document = app.get(data).document 132 | document.select("div.server ul.mirror li a").mapNotNull { 133 | Jsoup.parse(base64Decode(it.attr("data-em"))).select("iframe").attr("src") 134 | }.amap { link -> 135 | loadExtractor( 136 | fixUrl(decode(link.substringAfter("data="))), 137 | mainUrl, 138 | subtitleCallback, 139 | callback 140 | ) 141 | } 142 | 143 | return true 144 | } 145 | 146 | private fun decode(input: String): String = URLDecoder.decode(input, "utf-8") 147 | 148 | data class SearchResponses( 149 | @JsonProperty("post") var post: ArrayList = arrayListOf() 150 | ) 151 | 152 | data class All( 153 | @JsonProperty("ID") var ID: Int? = null, 154 | @JsonProperty("post_image") var postImage: String? = null, 155 | @JsonProperty("post_title") var postTitle: String? = null, 156 | @JsonProperty("post_link") var postLink: String? = null, 157 | ) 158 | 159 | data class Post( 160 | @JsonProperty("all") var all: ArrayList = arrayListOf(), 161 | ) 162 | 163 | } -------------------------------------------------------------------------------- /Pusatfilm/src/main/kotlin/com/pusatfilm/Pusatfilm.kt: -------------------------------------------------------------------------------- 1 | package com.pusatfilm 2 | 3 | import com.lagradost.cloudstream3.* 4 | import com.lagradost.cloudstream3.Episode 5 | import com.lagradost.cloudstream3.LoadResponse 6 | import com.lagradost.cloudstream3.TvSeriesLoadResponse 7 | import com.lagradost.cloudstream3.MainAPI 8 | import com.lagradost.cloudstream3.SearchResponse 9 | import com.lagradost.cloudstream3.TvType 10 | import com.lagradost.cloudstream3.mainPageOf 11 | import java.net.URI 12 | import org.jsoup.nodes.Element 13 | 14 | class Pusatfilm : MainAPI() { 15 | 16 | override var mainUrl = "https://site2.pusatfilm21info.com/" 17 | 18 | override var name = "Pusatfilm" 19 | override val hasMainPage = true 20 | override var lang = "id" 21 | override val supportedTypes = 22 | setOf(TvType.Movie, TvType.TvSeries, TvType.Anime, TvType.AsianDrama) 23 | 24 | override val mainPage = 25 | mainPageOf( 26 | "film-terbaru/page/%d/" to "Film Terbaru", 27 | "trending/page/%d/" to "Film Trending", 28 | "genre/action/page/%d/" to "Film Action", 29 | "series-terbaru/page/%d/" to "Series Terbaru", 30 | "drama-korea/page/%d/" to "Drama Korea", 31 | "west-series/page/%d/" to "West Series", 32 | "drama-china/page/%d/" to "Drama China", 33 | ) 34 | override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { 35 | val data = request.data.format(page) 36 | val document = app.get("$mainUrl/$data").document 37 | val home = document.select("article.item").mapNotNull { it.toSearchResult() } 38 | return newHomePageResponse(request.name, home) 39 | } 40 | 41 | private fun Element.toSearchResult(): SearchResponse? { 42 | val title = this.selectFirst("h2.entry-title > a")?.text()?.trim() ?: return null 43 | val href = fixUrl(this.selectFirst("a")!!.attr("href")) 44 | val posterUrl = fixUrlNull(this.selectFirst("a > img")?.getImageAttr()).fixImageQuality() 45 | val quality = 46 | this.select("div.gmr-qual, div.gmr-quality-item > a").text().trim().replace("-", "") 47 | return if (quality.isEmpty()) { 48 | val episode = 49 | Regex("Episode\\s?([0-9]+)") 50 | .find(title) 51 | ?.groupValues 52 | ?.getOrNull(1) 53 | ?.toIntOrNull() 54 | ?: this.select("div.gmr-numbeps > span").text().toIntOrNull() 55 | newAnimeSearchResponse(title, href, TvType.TvSeries) { 56 | this.posterUrl = posterUrl 57 | addSub(episode) 58 | } 59 | } else { 60 | newMovieSearchResponse(title, href, TvType.Movie) { 61 | this.posterUrl = posterUrl 62 | addQuality(quality) 63 | } 64 | } 65 | } 66 | 67 | override suspend fun search(query: String): List { 68 | val document = 69 | app.get("${mainUrl}?s=$query&post_type[]=post&post_type[]=tv", timeout = 50L) 70 | .document 71 | val results = document.select("article.item").mapNotNull { it.toSearchResult() } 72 | return results 73 | } 74 | 75 | private fun Element.toRecommendResult(): SearchResponse? { 76 | val title = this.selectFirst("a > span.idmuvi-rp-title")?.text()?.trim() ?: return null 77 | val href = this.selectFirst("a")!!.attr("href") 78 | val posterUrl = fixUrlNull(this.selectFirst("a > img")?.getImageAttr().fixImageQuality()) 79 | return newMovieSearchResponse(title, href, TvType.Movie) { this.posterUrl = posterUrl } 80 | } 81 | 82 | override suspend fun load(url: String): LoadResponse { 83 | return super.load(url).apply { 84 | when (this) { 85 | is TvSeriesLoadResponse -> { 86 | val document = app.get(url).document 87 | this.episodes = 88 | document.select("div.vid-episodes a, div.gmr-listseries a") 89 | .map { eps -> 90 | val href = fixUrl(eps.attr("href")) 91 | val name = eps.attr("title") 92 | val episode = 93 | "Episode\\s*(\\d+)" 94 | .toRegex() 95 | .find(name) 96 | ?.groupValues 97 | ?.get(1) 98 | val season = 99 | "Season\\s*(\\d+)" 100 | .toRegex() 101 | .find(name) 102 | ?.groupValues 103 | ?.get(1) 104 | newEpisode( 105 | href){ 106 | this.name = name 107 | this.season = season?.toIntOrNull() 108 | this.episode = episode?.toIntOrNull() 109 | } 110 | } 111 | .filter { it.episode != null } 112 | } 113 | } 114 | }!! 115 | } 116 | 117 | private fun Element.getImageAttr(): String { 118 | return when { 119 | this.hasAttr("data-src") -> this.attr("abs:data-src") 120 | this.hasAttr("data-lazy-src") -> this.attr("abs:data-lazy-src") 121 | this.hasAttr("srcset") -> this.attr("abs:srcset").substringBefore(" ") 122 | else -> this.attr("abs:src") 123 | } 124 | } 125 | 126 | private fun Element?.getIframeAttr(): String? { 127 | return this?.attr("data-litespeed-src").takeIf { it?.isNotEmpty() == true } 128 | ?: this?.attr("src") 129 | } 130 | 131 | private fun String?.fixImageQuality(): String? { 132 | if (this == null) return null 133 | val regex = Regex("(-\\d*x\\d*)").find(this)?.groupValues?.get(0) ?: return this 134 | return this.replace(regex, "") 135 | } 136 | 137 | private fun getBaseUrl(url: String): String { 138 | return URI(url).let { "${it.scheme}://${it.host}" } 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /Pencurimovie/src/main/kotlin/com/pencurimovie/Pencurimovie.kt: -------------------------------------------------------------------------------- 1 | package com.pencurimovie 2 | 3 | import com.lagradost.api.Log 4 | import com.lagradost.cloudstream3.* 5 | import com.lagradost.cloudstream3.LoadResponse.Companion.addActors 6 | import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer 7 | import com.lagradost.cloudstream3.utils.* 8 | import org.jsoup.nodes.Element 9 | 10 | class Pencurimovie : MainAPI() { 11 | override var mainUrl = "https://ww73.pencurimovie.bond" 12 | override var name = "Pencurimovie" 13 | override val hasMainPage = true 14 | override var lang = "id" 15 | override val hasDownloadSupport = true 16 | override val supportedTypes = setOf(TvType.Movie, TvType.Anime, TvType.Cartoon) 17 | 18 | override val mainPage = 19 | mainPageOf( 20 | "movies" to "Latest Movies", 21 | "series" to "TV Series", 22 | "most-rating" to "Most Rating Movies", 23 | "top-imdb" to "Top IMDB Movies", 24 | "country/malaysia" to "Malaysia Movies", 25 | "country/indonesia" to "Indonesia Movies", 26 | "country/india" to "India Movies", 27 | "country/japan" to "Japan Movies", 28 | "country/thailand" to "Thailand Movies", 29 | "country/china" to "China Movies", 30 | ) 31 | 32 | override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { 33 | val document = app.get("$mainUrl/${request.data}/page/$page", timeout = 50L).document 34 | val home = document.select("div.ml-item").mapNotNull { it.toSearchResult() } 35 | 36 | return newHomePageResponse( 37 | list = HomePageList(name = request.name, list = home, isHorizontalImages = false), 38 | hasNext = true 39 | ) 40 | } 41 | 42 | private fun Element.toSearchResult(): SearchResponse { 43 | val title = this.select("a").attr("oldtitle").substringBefore("(") 44 | val href = fixUrl(this.select("a").attr("href")) 45 | val posterUrl = fixUrlNull(this.select("a img").attr("data-original")) 46 | val quality = getQualityFromString(this.select("span.mli-quality").text()) 47 | return newMovieSearchResponse(title, href, TvType.Movie) { 48 | this.posterUrl = posterUrl 49 | this.quality = quality 50 | } 51 | } 52 | 53 | override suspend fun search(query: String): List { 54 | val document = app.get("${mainUrl}?s=$query", timeout = 50L).document 55 | val results = document.select("div.ml-item").mapNotNull { it.toSearchResult() } 56 | return results 57 | } 58 | 59 | override suspend fun load(url: String): LoadResponse { 60 | val document = app.get(url, timeout = 50L).document 61 | val title = 62 | document.selectFirst("div.mvic-desc h3") 63 | ?.text() 64 | ?.trim() 65 | .toString() 66 | .substringBefore("(") 67 | val poster = document.select("meta[property=og:image]").attr("content") 68 | val description = document.selectFirst("div.desc p.f-desc")?.text()?.trim() 69 | val tvtag = if (url.contains("series")) TvType.TvSeries else TvType.Movie 70 | val trailer = document.select("meta[itemprop=embedUrl]").attr("content") 71 | val genre = document.select("div.mvic-info p:contains(Genre)").select("a").map { it.text() } 72 | val actors = 73 | document.select("div.mvic-info p:contains(Actors)").select("a").map { it.text() } 74 | val year = 75 | document.select("div.mvic-info p:contains(Release)") 76 | .select("a") 77 | .text() 78 | .toIntOrNull() 79 | val recommendation = document.select("div.ml-item").mapNotNull { it.toSearchResult() } 80 | return if (tvtag == TvType.TvSeries) { 81 | val episodes = mutableListOf() 82 | document.select("div.tvseason").amap { info -> 83 | val season = 84 | info.select("strong").text().substringAfter("Season").trim().toIntOrNull() 85 | info.select("div.les-content a").forEach { 86 | Log.d("Phis", "$it") 87 | val name = it.select("a").text().substringAfter("-").trim() 88 | val href = it.select("a").attr("href") 89 | val rawepisode = 90 | it.select("a") 91 | .text() 92 | .substringAfter("Episode") 93 | .substringBefore("-") 94 | .trim() 95 | .toIntOrNull() 96 | episodes.add( 97 | newEpisode(data = href){ 98 | this.episode = rawepisode 99 | this.name = name 100 | this.season = season 101 | } 102 | ) 103 | } 104 | } 105 | 106 | newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) { 107 | this.posterUrl = poster 108 | this.plot = description 109 | this.tags = genre 110 | this.year = year 111 | addTrailer(trailer) 112 | addActors(actors) 113 | this.recommendations = recommendation 114 | } 115 | } else { 116 | newMovieLoadResponse(title, url, TvType.Movie, url) { 117 | this.posterUrl = poster 118 | this.plot = description 119 | this.tags = genre 120 | this.year = year 121 | addTrailer(trailer) 122 | addActors(actors) 123 | this.recommendations = recommendation 124 | } 125 | } 126 | } 127 | 128 | override suspend fun loadLinks( 129 | data: String, 130 | isCasting: Boolean, 131 | subtitleCallback: (SubtitleFile) -> Unit, 132 | callback: (ExtractorLink) -> Unit 133 | ): Boolean { 134 | val document = app.get(data).document 135 | document.select("div.movieplay iframe").forEach { 136 | val href = it.attr("data-src") 137 | loadExtractor(href, subtitleCallback, callback) 138 | } 139 | return true 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Funmovieslix/src/main/kotlin/com/funmovieslix/Funmovieslix.kt: -------------------------------------------------------------------------------- 1 | package com.funmovieslix 2 | 3 | import com.lagradost.api.Log 4 | import com.lagradost.cloudstream3.* 5 | import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer 6 | import com.lagradost.cloudstream3.utils.* 7 | import org.jsoup.nodes.Element 8 | 9 | class Funmovieslix : MainAPI() { 10 | override var mainUrl = "https://funmovieslix.com" 11 | override var name = "Funmovieslix" 12 | override val hasMainPage = true 13 | override var lang = "id" 14 | override val hasDownloadSupport = true 15 | override val supportedTypes = setOf(TvType.Movie, TvType.Anime, TvType.Cartoon) 16 | 17 | override val mainPage = 18 | mainPageOf( 19 | "category/action" to "Action Category", 20 | "category/science-fiction" to "Sci-Fi Category", 21 | "category/drama" to "Drama Category", 22 | "category/kdrama" to "KDrama", 23 | "category/crime" to "Crime Category", 24 | "category/fantasy" to "Fantasy Category", 25 | "category/mystery" to "Mystery Category", 26 | "category/comedy" to "Comedy Category", 27 | ) 28 | 29 | override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { 30 | val document = app.get("$mainUrl/${request.data}/page/$page").document 31 | val home = document.select("#gmr-main-load article").mapNotNull { it.toSearchResult() } 32 | return newHomePageResponse( 33 | list = HomePageList(name = request.name, list = home, isHorizontalImages = false), 34 | hasNext = true 35 | ) 36 | } 37 | 38 | private fun Element.toSearchResult(): SearchResponse { 39 | val title = this.select("div.item-article h2 a").text() 40 | val href = fixUrl(this.select("div.item-article h2 a").attr("href")) 41 | val posterUrl = fixUrlNull(this.select("div.content-thumbnail img").attr("src")) 42 | val searchQuality = 43 | if (this.select("div.gmr-quality-item a").text().contains("HD")) SearchQuality.HD 44 | else SearchQuality.HDR 45 | return newMovieSearchResponse(title, href, TvType.Movie) { 46 | this.posterUrl = posterUrl 47 | this.quality = searchQuality 48 | } 49 | } 50 | 51 | override suspend fun search(query: String): List { 52 | val document = app.get("${mainUrl}?s=$query", timeout = 50L).document 53 | val results = document.select("#gmr-main-load article").mapNotNull { it.toSearchResult() } 54 | return results 55 | } 56 | 57 | override suspend fun load(url: String): LoadResponse { 58 | val document = app.get(url).document 59 | val title = 60 | document.select("meta[property=og:title]") 61 | .attr("content") 62 | .substringBefore("(") 63 | .substringBefore("-") 64 | .trim() 65 | val poster = document.select("meta[property=og:image]").attr("content") 66 | val description = document.select("div.entry-content.entry-content-single p").text() 67 | val type = if (url.contains("tv")) TvType.TvSeries else TvType.Movie 68 | val trailer = document.select("meta[itemprop=embedUrl]").attr("content") 69 | val genre = document.select("div.gmr-moviedata:contains(Genre) a").map { it.text() } 70 | val year = document.select("div.gmr-moviedata:contains(Year) a").text().toIntOrNull() 71 | val recommendation = 72 | document.select("div.row.grid-container article").mapNotNull { it.toSearchResult() } 73 | return if (type == TvType.TvSeries) { 74 | val episodes = mutableListOf() 75 | document.select("div.gmr-listseries a").forEach { info -> 76 | if (info.text().contains("All episodes", ignoreCase = true)) return@forEach 77 | val text = info.text() 78 | val season = Regex("S(\\d+)").find(text)?.groupValues?.get(1)?.toIntOrNull() 79 | val ep = Regex("Eps(\\d+)").find(text)?.groupValues?.get(1)?.toIntOrNull() 80 | val name = "Episode $ep" 81 | val href = info.attr("href") 82 | episodes.add( 83 | newEpisode(href) { 84 | this.season = season 85 | this.name = name 86 | this.episode = ep 87 | } 88 | ) 89 | } 90 | 91 | newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes) { 92 | this.posterUrl = poster 93 | this.plot = description 94 | this.tags = genre 95 | this.year = year 96 | addTrailer(trailer) 97 | this.recommendations = recommendation 98 | } 99 | } else { 100 | newMovieLoadResponse(title, url, TvType.Movie, url) { 101 | this.posterUrl = poster 102 | this.plot = description 103 | this.tags = genre 104 | this.year = year 105 | addTrailer(trailer) 106 | this.recommendations = recommendation 107 | } 108 | } 109 | } 110 | 111 | override suspend fun loadLinks( 112 | data: String, 113 | isCasting: Boolean, 114 | subtitleCallback: (SubtitleFile) -> Unit, 115 | callback: (ExtractorLink) -> Unit 116 | ): Boolean { 117 | val document = app.get(data).document 118 | val postid = document.selectFirst("#muvipro_player_content_id")?.attr("data-id") ?: "" 119 | Log.d("Phisher", postid) 120 | document.select("#gmr-tab li a").amap { 121 | val server = it.attr("href").substringAfter("#") 122 | val source = 123 | app.post( 124 | url = "$mainUrl/wp-admin/admin-ajax.php", 125 | data = 126 | mapOf( 127 | "action" to "muvipro_player_content", 128 | "tab" to server, 129 | "post_id" to postid, 130 | ), 131 | referer = data, 132 | timeout = 5000L 133 | ) 134 | .document 135 | .select("iframe") 136 | .attr("src") 137 | loadExtractor(source, subtitleCallback, callback) 138 | } 139 | return true 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Anoboy/src/main/kotlin/com/anoboy/Anoboy.kt: -------------------------------------------------------------------------------- 1 | package com.anoboy 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.lagradost.cloudstream3.* 5 | import com.lagradost.cloudstream3.utils.* 6 | import java.util.ArrayList 7 | 8 | 9 | class Anoboy : MainAPI() { 10 | override var mainUrl = "https://ww1.anoboy.app" 11 | override var name = "Anoboy" 12 | override val hasMainPage = true 13 | override var lang = "id" 14 | override val hasQuickSearch = true 15 | override val hasDownloadSupport = true 16 | 17 | override val supportedTypes = setOf( 18 | TvType.Anime, 19 | TvType.AnimeMovie, 20 | TvType.OVA 21 | ) 22 | 23 | companion object { 24 | private const val MAIN_IMAGE_URL = "https://ww25.upload.anoboy.life" // Corrected name 25 | 26 | fun getType(t: String): TvType { 27 | return if (t.contains("OVA", true) || t.contains("Special", true)) TvType.OVA 28 | else if (t.contains("Movie", true)) TvType.AnimeMovie 29 | else TvType.Anime 30 | } 31 | 32 | fun getStatus(t: String): ShowStatus { 33 | return when (t) { 34 | "Completed" -> ShowStatus.Completed 35 | "Ongoing" -> ShowStatus.Ongoing 36 | else -> ShowStatus.Completed 37 | } 38 | } 39 | } 40 | 41 | override val mainPage = mainPageOf( 42 | "$mainUrl/page/" to "Latest Release", 43 | "$mainUrl/category/anime-movie/page/" to "Anime Movie", 44 | "$mainUrl/category/live-action-movie/page/" to "Live Action Movie", 45 | "$mainUrl/category/anime/page/" to "Anime", 46 | ) 47 | 48 | override suspend fun getMainPage( 49 | page: Int, 50 | request: MainPageRequest 51 | ): HomePageResponse { 52 | val home = app.get( 53 | "$mainUrl/my-ajax?page=$page${request.data}", 54 | headers = mapOf("X-Requested-With" to "XMLHttpRequest") 55 | ) 56 | .parsedSafe()?.data 57 | ?.mapNotNull { media -> 58 | media.toSearchResponse() 59 | } ?: throw ErrorLoadingException("Invalid Json response") 60 | return newHomePageResponse(request.name, home) 61 | } 62 | 63 | private fun Anime.toSearchResponse(): SearchResponse? { 64 | return newAnimeSearchResponse( 65 | postTitle ?: return null, 66 | "$mainUrl/anime/$postName", // Assuming mainUrl is a class property 67 | TvType.TvSeries, 68 | ) { 69 | this.posterUrl = "$MAIN_IMAGE_URL/$image" // Use the updated constant name 70 | addSub(totalEpisode?.toIntOrNull()) 71 | } 72 | } 73 | 74 | override suspend fun quickSearch(query: String): List = search(query) 75 | 76 | override suspend fun search(query: String): List { 77 | return app.get( 78 | "$mainUrl/my-ajax?page=1&limit=10&action=load_search_movie&keyword=$query", 79 | referer = "$mainUrl/search/?keyword=$query", 80 | headers = mapOf("X-Requested-With" to "XMLHttpRequest") 81 | ).parsedSafe()?.data 82 | ?.mapNotNull { media -> 83 | media.toSearchResponse() 84 | } ?: throw ErrorLoadingException("Invalid Json reponse") 85 | } 86 | 87 | override suspend fun load(url: String): LoadResponse { 88 | val document = app.get(url).document 89 | 90 | val title = document.selectFirst(".entry-title")?.text().toString() 91 | val poster = document.selectFirst(".thumbposter > img")?.attr("src") 92 | val tags = document.select(".genxed > a").map { it.text() } 93 | val type = document.selectFirst("div.info-content .spe span:last-child")?.ownText()?.lowercase() ?: "tv" 94 | 95 | val year = Regex("\\d, (\\d*)").find( 96 | document.selectFirst("div.info-content .spe span.split")?.ownText().toString() 97 | )?.groupValues?.get(1)?.toIntOrNull() 98 | val status = getStatus(document.selectFirst(".spe > span")!!.ownText()) 99 | val description = document.select("div[itemprop = description] > p").text() 100 | // Inside the .map { ... } block in your load function: 101 | 102 | val episodes = document.select(".eplister > ul > li").mapNotNull { episodeElement -> // Switched to mapNotNull 103 | val anchor = episodeElement.selectFirst("a") ?: return@mapNotNull null // Get the anchor tag 104 | val link = anchor.attr("href") 105 | val episodeNameText = episodeElement.selectFirst(".epl-title")?.text() ?: anchor.text() // Get the full title 106 | 107 | val episodeNumber = Regex("Episode\\s?(\\d+)") 108 | .find(episodeNameText) 109 | ?.groupValues 110 | ?.getOrNull(1) // Group 1 for the actual number 111 | ?.toIntOrNull() 112 | newEpisode(link) { // 'link' is the 'data' argument 113 | this.name = episodeNameText // Set the 'name' property (full title) 114 | this.episode = episodeNumber // Set the 'episode' property (the number) 115 | } 116 | }.reversed() 117 | return newAnimeLoadResponse(title, url, getType(type)) { 118 | engName = title 119 | posterUrl = poster 120 | this.year = year 121 | addEpisodes(DubStatus.Subbed, episodes) 122 | showStatus = status 123 | plot = description 124 | this.tags = tags 125 | } 126 | } 127 | 128 | override suspend fun loadLinks( 129 | data: String, 130 | isCasting: Boolean, 131 | subtitleCallback: (SubtitleFile) -> Unit, 132 | callback: (ExtractorLink) -> Unit 133 | ): Boolean { 134 | 135 | val document = app.get(data).document 136 | document.select("div.player-container iframe").attr("src").substringAfter("html#") 137 | .let { id -> 138 | app.get("https://gomunimes.com/stream?id=$id") 139 | .parsedSafe()?.server?.streamsb?.link?.let { link -> 140 | loadExtractor(link.replace("vidgomunimesb.xyz", "watchsb.com"), mainUrl, subtitleCallback, callback) 141 | } 142 | } 143 | 144 | return true 145 | } 146 | 147 | data class Streamsb( 148 | @JsonProperty("link") val link: String?, 149 | ) 150 | 151 | data class Server( 152 | @JsonProperty("streamsb") val streamsb: Streamsb?, 153 | ) 154 | 155 | data class Sources( 156 | @JsonProperty("server") val server: Server?, 157 | ) 158 | 159 | data class Responses( 160 | @JsonProperty("data") val data: ArrayList? = arrayListOf(), 161 | ) 162 | 163 | data class Anime( 164 | @JsonProperty("post_title") val postTitle: String?, 165 | @JsonProperty("post_name") val postName: String?, 166 | @JsonProperty("image") val image: String?, 167 | @JsonProperty("total_episode") val totalEpisode: String?, 168 | @JsonProperty("salt") val salt: String?, 169 | ) 170 | 171 | } -------------------------------------------------------------------------------- /Kuramanime/src/main/kotlin/com/kuramanime/Kuramanime.kt: -------------------------------------------------------------------------------- 1 | package com.kuramanime 2 | 3 | import com.lagradost.cloudstream3.* 4 | import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId 5 | import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId 6 | import com.lagradost.cloudstream3.utils.ExtractorLink 7 | import org.jsoup.Jsoup 8 | import org.jsoup.nodes.Element 9 | 10 | class Kuramanime : MainAPI() { 11 | override var mainUrl = "https://v8.kuramanime.tel" 12 | override var name = "Kuramanime" 13 | override val hasQuickSearch = false 14 | override val hasMainPage = true 15 | override var lang = "id" 16 | override val hasDownloadSupport = true 17 | override val supportedTypes = setOf(TvType.Anime, TvType.AnimeMovie, TvType.OVA) 18 | 19 | companion object { 20 | fun getType(t: String, s: Int): TvType { 21 | return if (t.contains("OVA", true) || t.contains("Special")) TvType.OVA 22 | else if (t.contains("Movie", true) && s == 1) TvType.AnimeMovie else TvType.Anime 23 | } 24 | 25 | fun getStatus(t: String): ShowStatus { 26 | return when (t) { 27 | "Selesai Tayang" -> ShowStatus.Completed 28 | "Sedang Tayang" -> ShowStatus.Ongoing 29 | else -> ShowStatus.Completed 30 | } 31 | } 32 | } 33 | 34 | override val mainPage = 35 | mainPageOf( 36 | "$mainUrl/anime/ongoing?order_by=updated&page=" to "Sedang Tayang", 37 | "$mainUrl/anime/finished?order_by=updated&page=" to "Selesai Tayang", 38 | "$mainUrl/properties/season/summer-2022?order_by=most_viewed&page=" to 39 | "Dilihat Terbanyak Musim Ini", 40 | "$mainUrl/anime/movie?order_by=updated&page=" to "Film Layar Lebar", 41 | ) 42 | 43 | override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { 44 | val document = app.get(request.data + page).document 45 | 46 | val home = 47 | document.select("div.col-lg-4.col-md-6.col-sm-6").mapNotNull { it.toSearchResult() } 48 | 49 | return newHomePageResponse(request.name, home) 50 | } 51 | 52 | private fun getProperAnimeLink(uri: String): String { 53 | return if (uri.contains("/episode")) { 54 | Regex("(.*)/episode/.+").find(uri)?.groupValues?.get(1).toString() + "/" 55 | } else { 56 | uri 57 | } 58 | } 59 | 60 | private fun Element.toSearchResult(): AnimeSearchResponse? { 61 | val href = getProperAnimeLink(fixUrl(this.selectFirst("a")!!.attr("href"))) 62 | val title = this.selectFirst("h5 a")?.text() ?: return null 63 | val posterUrl = fixUrl(this.select("div.product__item__pic.set-bg").attr("data-setbg")) 64 | val episode = 65 | this.select("div.ep span").text().let { 66 | Regex("Ep\\s(\\d+)\\s/").find(it)?.groupValues?.getOrNull(1)?.toIntOrNull() 67 | } 68 | 69 | return newAnimeSearchResponse(title, href, TvType.Anime) { 70 | this.posterUrl = posterUrl 71 | addSub(episode) 72 | } 73 | } 74 | 75 | override suspend fun search(query: String): List { 76 | val link = "$mainUrl/anime?search=$query&order_by=latest" 77 | val document = app.get(link).document 78 | 79 | return document.select("div#animeList div.product__item").mapNotNull { it.toSearchResult() } 80 | } 81 | 82 | override suspend fun load(url: String): LoadResponse { 83 | val document = app.get(url).document 84 | 85 | val title = document.selectFirst(".anime__details__title > h3")!!.text().trim() 86 | val poster = document.selectFirst(".anime__details__pic")?.attr("data-setbg") 87 | val tags = 88 | document.select( 89 | "div.anime__details__widget > div > div:nth-child(2) > ul > li:nth-child(1)" 90 | ) 91 | .text() 92 | .trim() 93 | .replace("Genre: ", "") 94 | .split(", ") 95 | 96 | val year = 97 | Regex("\\D") 98 | .replace( 99 | document.select( 100 | "div.anime__details__widget > div > div:nth-child(1) > ul > li:nth-child(5)" 101 | ) 102 | .text() 103 | .trim() 104 | .replace("Musim: ", ""), 105 | "" 106 | ) 107 | .toIntOrNull() 108 | val status = 109 | getStatus( 110 | document.select( 111 | "div.anime__details__widget > div > div:nth-child(1) > ul > li:nth-child(3)" 112 | ) 113 | .text() 114 | .trim() 115 | .replace("Status: ", "") 116 | ) 117 | val description = document.select(".anime__details__text > p").text().trim() 118 | 119 | val episodes = mutableListOf() 120 | 121 | for (i in 1..10) { 122 | val doc = app.get("$url?page=$i").document 123 | val eps = 124 | Jsoup.parse(doc.select("#episodeLists").attr("data-content")) 125 | .select("a.btn.btn-sm.btn-danger") 126 | .mapNotNull { 127 | val name = it.text().trim() 128 | val episode = 129 | Regex("(\\d+[.,]?\\d*)") 130 | .find(name) 131 | ?.groupValues 132 | ?.getOrNull(0) 133 | ?.toIntOrNull() 134 | val link = it.attr("href") 135 | newEpisode(link){ 136 | this.episode = episode 137 | } 138 | } 139 | if (eps.isEmpty()) break else episodes.addAll(eps) 140 | } 141 | 142 | val type = 143 | getType( 144 | document.selectFirst("div.col-lg-6.col-md-6 ul li:contains(Tipe:) a") 145 | ?.text() 146 | ?.lowercase() 147 | ?: "tv", 148 | episodes.size 149 | ) 150 | val recommendations = 151 | document.select("div#randomList > a").mapNotNull { 152 | val epHref = it.attr("href") 153 | val epTitle = it.select("h5.sidebar-title-h5.px-2.py-2").text() 154 | val epPoster = 155 | it.select(".product__sidebar__view__item.set-bg").attr("data-setbg") 156 | newAnimeSearchResponse(epTitle, epHref, TvType.Anime) { 157 | this.posterUrl = epPoster 158 | addDubStatus(dubExist = false, subExist = true) 159 | } 160 | } 161 | 162 | val tracker = APIHolder.getTracker(listOf(title), TrackerType.getTypes(type), year, true) 163 | 164 | return newAnimeLoadResponse(title, url, type) { 165 | engName = title 166 | posterUrl = tracker?.image ?: poster 167 | backgroundPosterUrl = tracker?.cover 168 | this.year = year 169 | addEpisodes(DubStatus.Subbed, episodes) 170 | showStatus = status 171 | plot = description 172 | this.tags = tags 173 | this.recommendations = recommendations 174 | addMalId(tracker?.malId) 175 | addAniListId(tracker?.aniId?.toIntOrNull()) 176 | } 177 | } 178 | 179 | override suspend fun loadLinks( 180 | data: String, 181 | isCasting: Boolean, 182 | subtitleCallback: (SubtitleFile) -> Unit, 183 | callback: (ExtractorLink) -> Unit 184 | ): Boolean { 185 | 186 | return true 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /Dramaid/src/main/kotlin/com/dramaid/Dramaid.kt: -------------------------------------------------------------------------------- 1 | package com.dramaid 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.lagradost.cloudstream3.* 5 | import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson 6 | import com.lagradost.cloudstream3.utils.ExtractorLink 7 | import com.lagradost.cloudstream3.utils.newExtractorLink 8 | import com.lagradost.cloudstream3.utils.getQualityFromName 9 | import com.lagradost.cloudstream3.utils.loadExtractor 10 | import org.jsoup.Jsoup 11 | import org.jsoup.nodes.Element 12 | 13 | open class Dramaid : MainAPI() { 14 | override var mainUrl = "https://dramaid.nl" 15 | override var name = "DramaId" 16 | override val hasMainPage = true 17 | override var lang = "id" 18 | override val supportedTypes = setOf(TvType.AsianDrama) 19 | 20 | companion object { 21 | fun getStatus(t: String): ShowStatus { 22 | return when (t) { 23 | "Completed" -> ShowStatus.Completed 24 | "Ongoing" -> ShowStatus.Ongoing 25 | else -> ShowStatus.Completed 26 | } 27 | } 28 | 29 | fun getType(t: String?): TvType { 30 | return when { 31 | t?.contains("Movie", true) == true -> TvType.Movie 32 | t?.contains("Anime", true) == true -> TvType.Anime 33 | else -> TvType.AsianDrama 34 | } 35 | } 36 | } 37 | 38 | override val mainPage = mainPageOf( 39 | "&status=&type=&order=update" to "Drama Terbaru", 40 | "&order=latest" to "Baru Ditambahkan", 41 | "&status=&type=&order=popular" to "Drama Popular", 42 | ) 43 | 44 | override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { 45 | val document = app.get("$mainUrl/series/?page=$page${request.data}").document 46 | val home = document.select("article[itemscope=itemscope]").mapNotNull { 47 | it.toSearchResult() 48 | } 49 | return newHomePageResponse(request.name, home) 50 | } 51 | 52 | private fun getProperDramaLink(uri: String): String { 53 | return if (uri.contains("-episode-")) { 54 | "$mainUrl/series/" + Regex("$mainUrl/(.+)-ep.+").find(uri)?.groupValues?.get(1) 55 | } else { 56 | uri 57 | } 58 | } 59 | 60 | private fun Element.toSearchResult(): SearchResponse? { 61 | val href = getProperDramaLink(this.selectFirst("a.tip")!!.attr("href")) 62 | val title = this.selectFirst("h2[itemprop=headline]")?.text()?.trim() ?: return null 63 | val posterUrl = fixUrlNull(this.select("img:last-child").attr("src")) 64 | 65 | return newTvSeriesSearchResponse(title, href, TvType.AsianDrama) { 66 | this.posterUrl = posterUrl 67 | } 68 | } 69 | 70 | override suspend fun search(query: String): List { 71 | val document = app.get("$mainUrl/?s=$query").document 72 | return document.select("article[itemscope=itemscope]").mapNotNull { 73 | it.toSearchResult() 74 | } 75 | } 76 | 77 | override suspend fun load(url: String): LoadResponse { 78 | val document = app.get(url).document 79 | 80 | val title = document.selectFirst("h1.entry-title")?.text()?.trim() ?: "" 81 | val poster = fixUrlNull(document.select("div.thumb img:last-child").attr("src")) 82 | val tags = document.select(".genxed > a").map { it.text() } 83 | val type = document.selectFirst(".info-content .spe span:contains(Tipe:)")?.ownText() 84 | val year = Regex("\\d, ([0-9]*)").find( 85 | document.selectFirst(".info-content > .spe > span > time")!!.text().trim() 86 | )?.groupValues?.get(1).toString().toIntOrNull() 87 | val status = getStatus( 88 | document.select(".info-content > .spe > span:nth-child(1)") 89 | .text().trim().replace("Status: ", "") 90 | ) 91 | val description = document.select(".entry-content > p").text().trim() 92 | 93 | val episodes = document.select(".eplister > ul > li").mapNotNull { episodeElement -> 94 | val anchor = episodeElement.selectFirst("a") ?: return@mapNotNull null 95 | val link = fixUrl(anchor.attr("href")) 96 | val episodeTitle = episodeElement.selectFirst("a > .epl-title")?.text() ?: anchor.text() // Full title 97 | 98 | val episodeNumber = Regex("""(?:Episode|Eps)\s*(\d+)""", RegexOption.IGNORE_CASE) 99 | .find(episodeTitle) 100 | ?.groupValues 101 | ?.getOrNull(1) 102 | ?.toIntOrNull() 103 | newEpisode(link) { // 'link' is the 'data' argument 104 | this.name = episodeTitle // Set the 'name' property (full title) 105 | this.episode = episodeNumber // Set the 'episode' property (the parsed number) 106 | } 107 | }.reversed() 108 | 109 | val recommendations = 110 | document.select(".listupd > article[itemscope=itemscope]").mapNotNull { rec -> 111 | rec.toSearchResult() 112 | } 113 | 114 | return newTvSeriesLoadResponse( 115 | title, 116 | url, 117 | getType(type), 118 | episodes = episodes 119 | ) { 120 | posterUrl = poster 121 | this.year = year 122 | showStatus = status 123 | plot = description 124 | this.tags = tags 125 | this.recommendations = recommendations 126 | } 127 | 128 | } 129 | 130 | private data class Sources( 131 | @JsonProperty("file") val file: String, 132 | @JsonProperty("label") val label: String, 133 | @JsonProperty("type") val type: String, 134 | @JsonProperty("default") val default: Boolean? 135 | ) 136 | 137 | private data class Tracks( 138 | @JsonProperty("file") val file: String, 139 | @JsonProperty("label") val label: String, 140 | @JsonProperty("kind") val type: String, 141 | @JsonProperty("default") val default: Boolean? 142 | ) 143 | 144 | private suspend fun invokeDriveSource( 145 | url: String, 146 | name: String, 147 | subCallback: (SubtitleFile) -> Unit, 148 | sourceCallback: (ExtractorLink) -> Unit 149 | ) { 150 | val server = app.get(url).document.selectFirst(".picasa")?.nextElementSibling()?.data() 151 | 152 | val source = "[${server!!.substringAfter("sources: [").substringBefore("],")}]".trimIndent() 153 | val trackers = server.substringAfter("tracks:[").substringBefore("],") 154 | .replace("//language", "") 155 | .replace("file", "\"file\"") 156 | .replace("label", "\"label\"") 157 | .replace("kind", "\"kind\"").trimIndent() 158 | 159 | tryParseJson>(source)?.map { 160 | sourceCallback( 161 | newExtractorLink( 162 | this.name, 163 | "Drive", 164 | fixUrl(it.file) 165 | ){ 166 | this.referer = "https://motonews.club/" 167 | this.quality = getQualityFromName(it.label) 168 | } 169 | ) 170 | } 171 | 172 | tryParseJson(trackers)?.let { 173 | subCallback.invoke( 174 | SubtitleFile( 175 | if (it.label.contains("Indonesia")) "${it.label}n" else it.label, 176 | it.file 177 | ) 178 | ) 179 | } 180 | 181 | } 182 | 183 | override suspend fun loadLinks( 184 | data: String, 185 | isCasting: Boolean, 186 | subtitleCallback: (SubtitleFile) -> Unit, 187 | callback: (ExtractorLink) -> Unit 188 | ): Boolean { 189 | val document = app.get(data).document 190 | val sources = document.select(".mobius > .mirror > option").mapNotNull { 191 | fixUrl(Jsoup.parse(base64Decode(it.attr("value"))).select("iframe").attr("src")) 192 | } 193 | 194 | sources.map { 195 | it.replace("https://ndrama.xyz", "https://www.fembed.com") 196 | }.amap { 197 | when { 198 | it.contains("motonews") -> invokeDriveSource( 199 | it, 200 | this.name, 201 | subtitleCallback, 202 | callback 203 | ) 204 | 205 | else -> loadExtractor(it, "$mainUrl/", subtitleCallback, callback) 206 | } 207 | } 208 | 209 | return true 210 | } 211 | 212 | } 213 | 214 | -------------------------------------------------------------------------------- /Nimegami/src/main/kotlin/com/nimegami/Nimegami.kt: -------------------------------------------------------------------------------- 1 | package com.nimegami 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.lagradost.cloudstream3.* 5 | import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId 6 | import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId 7 | import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer 8 | import com.lagradost.cloudstream3.utils.* 9 | import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson 10 | import kotlinx.coroutines.Dispatchers 11 | import kotlinx.coroutines.coroutineScope 12 | import kotlinx.coroutines.launch 13 | import org.jsoup.nodes.Element 14 | import org.jsoup.select.Elements 15 | 16 | class Nimegami : MainAPI() { 17 | override var mainUrl = "https://nimegami.id" 18 | override var name = "Nimegami" 19 | override val hasMainPage = true 20 | override var lang = "id" 21 | override val supportedTypes = setOf(TvType.Anime, TvType.AnimeMovie, TvType.OVA) 22 | 23 | companion object { 24 | fun getType(t: String): TvType { 25 | return when { 26 | t.contains("Tv", true) -> TvType.Anime 27 | t.contains("Movie", true) -> TvType.AnimeMovie 28 | t.contains("OVA", true) || t.contains("Special", true) -> TvType.OVA 29 | else -> TvType.Anime 30 | } 31 | } 32 | 33 | fun getStatus(t: String?): ShowStatus { 34 | return when { 35 | t?.contains("On-Going", true) == true -> ShowStatus.Ongoing 36 | else -> ShowStatus.Completed 37 | } 38 | } 39 | } 40 | 41 | override val mainPage = 42 | mainPageOf( 43 | "" to "Updated Anime", 44 | "/type/drama-movie" to "Drama Movie", 45 | "/type/drama-series" to "Drama Series", 46 | "/type/live" to "Live", 47 | "/type/live-action" to "Live Action", 48 | "/type/tv" to "Anime", 49 | "/type/movie" to "Movie", 50 | "/type/ona" to "ONA", 51 | "/type/ova" to "OVA", 52 | "/type/ova/special" to "OVA Special", 53 | ) 54 | 55 | override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { 56 | val document = app.get("$mainUrl${request.data}/page/$page").document 57 | val home = 58 | document.select("div.post-article article, div.archive article").mapNotNull { 59 | it.toSearchResult() 60 | } 61 | return newHomePageResponse( 62 | list = 63 | HomePageList( 64 | name = request.name, 65 | list = home, 66 | isHorizontalImages = request.name != "Updated Anime" 67 | ), 68 | hasNext = true 69 | ) 70 | } 71 | 72 | private fun Element.toSearchResult(): AnimeSearchResponse? { 73 | val href = fixUrl(this.selectFirst("a")!!.attr("href")) 74 | val title = this.selectFirst("h2 a")?.text() ?: return null 75 | val posterUrl = (this.selectFirst("noscript img") ?: this.selectFirst("img"))?.attr("src") 76 | val episode = 77 | this.selectFirst("ul li:contains(Episode), div.eps-archive") 78 | ?.ownText() 79 | ?.filter { it.isDigit() } 80 | ?.toIntOrNull() 81 | 82 | return newAnimeSearchResponse(title, href, TvType.Anime) { 83 | this.posterUrl = posterUrl 84 | addSub(episode) 85 | } 86 | } 87 | 88 | override suspend fun search(query: String): List { 89 | val searchResponse = mutableListOf() 90 | for (i in 1..2) { 91 | val res = 92 | app.get("$mainUrl/page/$i/?s=$query&post_type=post") 93 | .document 94 | .select("div.archive article") 95 | .mapNotNull { it.toSearchResult() } 96 | searchResponse.addAll(res) 97 | } 98 | return searchResponse 99 | } 100 | 101 | override suspend fun load(url: String): LoadResponse { 102 | val document = app.get(url).document 103 | 104 | val table = document.select("div#Info table tbody") 105 | val title = table.getContent("Judul :").text() 106 | val poster = document.selectFirst("div.coverthumbnail img")?.attr("src") 107 | val bgPoster = document.selectFirst("div.thumbnail-a img")?.attr("src") 108 | val tags = table.getContent("Kategori").select("a").map { it.text() } 109 | 110 | val year = table.getContent("Musim / Rilis").text().filter { it.isDigit() }.toIntOrNull() 111 | val status = getStatus(document.selectFirst("h1[itemprop=headline]")?.text()) 112 | val type = getType(table.getContent("Type").text()) 113 | val description = document.select("div#Sinopsis p").text().trim() 114 | val trailer = document.selectFirst("div#Trailer iframe")?.attr("src") 115 | 116 | val episodes = 117 | document.select("div.list_eps_stream li").mapNotNull { 118 | val episode = 119 | Regex("Episode\\s?(\\d+)") 120 | .find(it.text()) 121 | ?.groupValues 122 | ?.getOrNull(0) 123 | ?.toIntOrNull() 124 | val link = it.attr("data") 125 | newEpisode(link){this.episode = episode} 126 | } 127 | 128 | val recommendations = 129 | document.select("div#randomList > a").mapNotNull { 130 | val epHref = it.attr("href") 131 | val epTitle = it.select("h5.sidebar-title-h5.px-2.py-2").text() 132 | val epPoster = 133 | it.select(".product__sidebar__view__item.set-bg").attr("data-setbg") 134 | 135 | newAnimeSearchResponse(epTitle, epHref, TvType.Anime) { 136 | this.posterUrl = epPoster 137 | addDubStatus(dubExist = false, subExist = true) 138 | } 139 | } 140 | 141 | val tracker = APIHolder.getTracker(listOf(title), TrackerType.getTypes(type), year, true) 142 | 143 | return newAnimeLoadResponse(title, url, type) { 144 | engName = title 145 | posterUrl = tracker?.image ?: poster 146 | backgroundPosterUrl = tracker?.cover ?: bgPoster 147 | this.year = year 148 | addEpisodes(DubStatus.Subbed, episodes) 149 | showStatus = status 150 | plot = description 151 | this.tags = tags 152 | this.recommendations = recommendations 153 | addTrailer(trailer) 154 | addMalId(tracker?.malId) 155 | addAniListId(tracker?.aniId?.toIntOrNull()) 156 | } 157 | } 158 | 159 | override suspend fun loadLinks( 160 | data: String, 161 | isCasting: Boolean, 162 | subtitleCallback: (SubtitleFile) -> Unit, 163 | callback: (ExtractorLink) -> Unit 164 | ): Boolean { 165 | 166 | tryParseJson>(base64Decode(data))?.map { sources -> 167 | sources.url?.amap { url -> 168 | loadFixedExtractor(url, sources.format, "$mainUrl/", subtitleCallback, callback) 169 | } 170 | } 171 | 172 | return true 173 | } 174 | 175 | private suspend fun loadFixedExtractor( 176 | url: String, 177 | quality: String?, 178 | referer: String? = null, 179 | subtitleCallback: (SubtitleFile) -> Unit, 180 | callback: (ExtractorLink) -> Unit 181 | ) = coroutineScope { 182 | loadExtractor(url, referer, subtitleCallback) { link -> 183 | launch(Dispatchers.IO) { 184 | callback.invoke( 185 | newExtractorLink( 186 | link.name, 187 | link.name, 188 | link.url, 189 | link.type 190 | ){ 191 | this.referer = link.referer 192 | this.quality = getQualityFromName(quality) 193 | this.headers = link.headers 194 | this.extractorData = link.extractorData 195 | } 196 | ) 197 | } 198 | } 199 | } 200 | 201 | private fun Elements.getContent(css: String): Elements { 202 | return this.select("tr:contains($css) td:last-child") 203 | } 204 | 205 | data class Sources( 206 | @JsonProperty("format") val format: String? = null, 207 | @JsonProperty("url") val url: ArrayList? = arrayListOf(), 208 | ) 209 | } 210 | -------------------------------------------------------------------------------- /Gomov/src/main/kotlin/com/gomov/Extractors.kt: -------------------------------------------------------------------------------- 1 | package com.gomov 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.lagradost.cloudstream3.* 5 | import com.lagradost.cloudstream3.SubtitleFile 6 | import com.lagradost.cloudstream3.USER_AGENT 7 | import com.lagradost.cloudstream3.app 8 | import com.lagradost.cloudstream3.extractors.VidHidePro 9 | import com.lagradost.cloudstream3.extractors.helper.AesHelper.cryptoAESHandler 10 | import com.lagradost.cloudstream3.utils.* 11 | import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson 12 | import com.lagradost.cloudstream3.utils.ExtractorApi 13 | import com.lagradost.cloudstream3.utils.ExtractorLink 14 | import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8 15 | import com.lagradost.cloudstream3.utils.getQualityFromName 16 | 17 | class Watchx : Chillx() { 18 | override val name = "Watchx" 19 | override val mainUrl = "https://watchx.top" 20 | } 21 | 22 | class Boosterx : Chillx() { 23 | override val name = "Boosterx" 24 | override val mainUrl = "https://boosterx.stream" 25 | override val requiresReferer = true 26 | } 27 | 28 | open class Chillx : ExtractorApi() { 29 | override val name = "Chillx" 30 | override val mainUrl = "https://chillx.top" 31 | override val requiresReferer = true 32 | 33 | companion object { 34 | private var key: String? = null 35 | 36 | suspend fun fetchKey(): String { 37 | return if (key != null) { 38 | key!! 39 | } else { 40 | val fetch = 41 | app.get( 42 | "https://raw.githubusercontent.com/rushi-chavan/multi-keys/keys/keys.json" 43 | ) 44 | .parsedSafe() 45 | ?.key 46 | ?.get(0) 47 | ?: throw ErrorLoadingException("Unable to get key") 48 | key = fetch 49 | key!! 50 | } 51 | } 52 | } 53 | 54 | @Suppress("NAME_SHADOWING") 55 | override suspend fun getUrl( 56 | url: String, 57 | referer: String?, 58 | subtitleCallback: (SubtitleFile) -> Unit, 59 | callback: (ExtractorLink) -> Unit 60 | ) { 61 | val master = 62 | Regex("""JScript[\w+]?\s*=\s*'([^']+)""") 63 | .find( 64 | app.get( 65 | url, 66 | referer = url, 67 | ) 68 | .text 69 | ) 70 | ?.groupValues 71 | ?.get(1) 72 | val key = fetchKey() 73 | val decrypt = 74 | cryptoAESHandler(master ?: "", key.toByteArray(), false)?.replace("\\", "") 75 | ?: throw ErrorLoadingException("failed to decrypt") 76 | val source = Regex(""""?file"?:\s*"([^"]+)""").find(decrypt)?.groupValues?.get(1) 77 | val subtitles = Regex("""subtitle"?:\s*"([^"]+)""").find(decrypt)?.groupValues?.get(1) 78 | val subtitlePattern = """\[(.*?)](https?://[^\s,]+)""".toRegex() 79 | val matches = subtitlePattern.findAll(subtitles ?: "") 80 | val languageUrlPairs = 81 | matches 82 | .map { matchResult -> 83 | val (language, url) = matchResult.destructured 84 | decodeUnicodeEscape(language) to url 85 | } 86 | .toList() 87 | 88 | languageUrlPairs.forEach { (name, file) -> 89 | subtitleCallback.invoke(SubtitleFile(name, file)) 90 | } 91 | // required 92 | val headers = 93 | mapOf( 94 | "Accept" to "*/*", 95 | "Connection" to "keep-alive", 96 | "Sec-Fetch-Dest" to "empty", 97 | "Sec-Fetch-Mode" to "cors", 98 | "Sec-Fetch-Site" to "cross-site", 99 | "Origin" to mainUrl, 100 | ) 101 | 102 | generateM3u8(name, source ?: return, "$mainUrl/", headers = headers) 103 | .forEach(callback) 104 | } 105 | 106 | private fun decodeUnicodeEscape(input: String): String { 107 | val regex = Regex("u([0-9a-fA-F]{4})") 108 | return regex.replace(input) { it.groupValues[1].toInt(16).toChar().toString() } 109 | } 110 | 111 | data class Keys(@JsonProperty("chillx") val key: List) 112 | } 113 | 114 | class Dhtpre : JWPlayer() { 115 | override val name = "Dhtpre" 116 | override val mainUrl = "https://dhtpre.com" 117 | } 118 | 119 | open class JWPlayer : ExtractorApi() { 120 | override val name = "JWPlayer" 121 | override val mainUrl = "https://www.jwplayer.com" 122 | override val requiresReferer = false 123 | 124 | override suspend fun getUrl(url: String, referer: String?): List? { 125 | val sources = mutableListOf() 126 | with(app.get(url).document) { 127 | val data = 128 | this.select("script").mapNotNull { script -> 129 | if (script.data().contains("sources: [")) { 130 | script.data() 131 | .substringAfter("sources: [") 132 | .substringBefore("],") 133 | .replace("'", "\"") 134 | } else if (script.data().contains("otakudesu('")) { 135 | script.data().substringAfter("otakudesu('").substringBefore("');") 136 | } else { 137 | null 138 | } 139 | } 140 | 141 | tryParseJson>("$data")?.map { 142 | sources.add( 143 | newExtractorLink( 144 | name, 145 | name, 146 | it.file 147 | ){ 148 | this.referer = url 149 | this.quality = getQualityFromName(Regex("(\\d{3,4}p)") 150 | .find(it.file) 151 | ?.groupValues 152 | ?.get(1) 153 | ) 154 | } 155 | ) 156 | } 157 | } 158 | return sources 159 | } 160 | 161 | private data class ResponseSource( 162 | @JsonProperty("file") val file: String, 163 | @JsonProperty("type") val type: String?, 164 | @JsonProperty("label") val label: String? 165 | ) 166 | } 167 | 168 | class Filelions : VidHidePro() { 169 | override var mainUrl = "https://filelions.site" 170 | } 171 | 172 | open class VidHidePro : ExtractorApi() { 173 | override val name = "VidHidePro" 174 | override val mainUrl = "https://vidhidepro.com" 175 | override val requiresReferer = true 176 | 177 | override suspend fun getUrl( 178 | url: String, 179 | referer: String?, 180 | subtitleCallback: (SubtitleFile) -> Unit, 181 | callback: (ExtractorLink) -> Unit 182 | ) { 183 | val headers = 184 | mapOf( 185 | "Accept" to "*/*", 186 | "Connection" to "keep-alive", 187 | "Sec-Fetch-Dest" to "empty", 188 | "Sec-Fetch-Mode" to "cors", 189 | "Sec-Fetch-Site" to "cross-site", 190 | "Origin" to "$mainUrl/", 191 | "User-Agent" to USER_AGENT, 192 | ) 193 | 194 | val response = app.get(getEmbedUrl(url), referer = referer) 195 | val script = 196 | if (!getPacked(response.text).isNullOrEmpty()) { 197 | getAndUnpack(response.text) 198 | } else { 199 | response.document.selectFirst("script:containsData(sources:)")?.data() 200 | } 201 | val m3u8 = 202 | Regex("file:\\s*\"(.*?m3u8.*?)\"").find(script ?: return)?.groupValues?.getOrNull(1) 203 | generateM3u8(name, m3u8 ?: return, mainUrl, headers = headers).forEach(callback) 204 | } 205 | 206 | private fun getEmbedUrl(url: String): String { 207 | return when { 208 | url.contains("/d/") -> url.replace("/d/", "/v/") 209 | url.contains("/download/") -> url.replace("/download/", "/v/") 210 | url.contains("/file/") -> url.replace("/file/", "/v/") 211 | else -> url.replace("/f/", "/v/") 212 | } 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /Raveeflix/src/main/kotlin/com/raveeflix/Raveeflix.kt: -------------------------------------------------------------------------------- 1 | package com.raveeflix 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.lagradost.cloudstream3.* 5 | import com.lagradost.cloudstream3.LoadResponse.Companion.addActors 6 | import com.lagradost.cloudstream3.LoadResponse.Companion.addScore 7 | import com.lagradost.cloudstream3.utils.* 8 | import com.lagradost.cloudstream3.utils.AppUtils.parseJson 9 | import com.lagradost.cloudstream3.utils.AppUtils.toJson 10 | import org.jsoup.nodes.Element 11 | import org.jsoup.select.Elements 12 | 13 | class Raveeflix : MainAPI() { 14 | override var mainUrl = "https://letflix.xyz" 15 | override var name = "Raveeflix" 16 | override val hasMainPage = true 17 | override var lang = "id" 18 | override val supportedTypes = 19 | setOf( 20 | TvType.Movie, 21 | TvType.TvSeries, 22 | TvType.AsianDrama, 23 | ) 24 | 25 | override val mainPage = 26 | mainPageOf( 27 | "categories/trending" to "Trending", 28 | "movies" to "Movies", 29 | "tv" to "Tv-Shows", 30 | "drakor" to "Drakor", 31 | "categories/anime" to "Anime", 32 | ) 33 | 34 | override suspend fun getMainPage( 35 | page: Int, 36 | request: MainPageRequest, 37 | ): HomePageResponse { 38 | val pages = if (page > 1) "page/$page/" else "" 39 | val document = app.get("$mainUrl/${request.data}/$pages").document 40 | val home = document.select("section.w-full a.min-w-full").mapNotNull { it.toSearchResult() } 41 | return newHomePageResponse( 42 | HomePageList( 43 | request.name, home, true 44 | ) 45 | ) 46 | } 47 | 48 | private fun Element.toSearchResult(): SearchResponse? { 49 | val title = this.selectFirst("div.text-xl")?.text() ?: return null 50 | val href = fixUrl(this.attr("href")) 51 | val posterUrl = this.selectFirst("div.thumbnail_card")?.attr("style")?.getPoster() 52 | 53 | return newMovieSearchResponse(title, Media(href, posterUrl).toJson(), TvType.Movie, false) { 54 | this.posterUrl = posterUrl 55 | } 56 | } 57 | 58 | override suspend fun search(query: String): List? { 59 | val res = 60 | app.get("$mainUrl/index.json").text.let { AppUtils.tryParseJson>(it) } 61 | return res?.filter { 62 | it.title?.contains( 63 | query, 64 | true 65 | ) == true && !it.section.equals("Categories", true) && !it.section.equals( 66 | "Tags", 67 | true 68 | ) && it.permalink?.contains("/episode") == false 69 | }?.mapNotNull { 70 | newMovieSearchResponse( 71 | it.title ?: return@mapNotNull null, 72 | Media( 73 | fixUrl( 74 | it.permalink?.substringBefore("episode")?.substringBefore("season") 75 | ?: return@mapNotNull null 76 | ) 77 | ).toJson(), 78 | TvType.Movie, 79 | false, 80 | ) 81 | } 82 | } 83 | 84 | override suspend fun load(url: String): LoadResponse { 85 | val media = parseJson(url) 86 | val document = app.get(media.url).document 87 | val title = document.selectFirst("h1.text-4xl")?.text() ?: "No Title" 88 | val poster = media.poster ?: document.selectFirst("div.thumbnail_card, div.w-full.thumbnail_card_related") 89 | ?.attr("style")?.getPoster() 90 | val type = 91 | if (document.select("mux-player").isEmpty()) TvType.TvSeries else TvType.Movie 92 | val tags = 93 | if (type == TvType.TvSeries) { 94 | document.selectFirst("div.movie-details > p:nth-child(1)") 95 | ?.ownText()?.split(",") 96 | ?.map { it.trim() } 97 | } else { 98 | document.select("span.mr-2") 99 | .map { it.text() }.distinct() 100 | } 101 | 102 | val year = 103 | document.selectFirst("div.movie-details > p:nth-child(2), div.max-w-prose.mb-20 > ul > li:nth-child(2) span") 104 | ?.ownText()?.substringAfter(",")?.toIntOrNull() 105 | val description = 106 | document.selectFirst("div.lead.text-neutral-500, span#storyline") 107 | ?.text()?.trim() 108 | val rating = 109 | document.selectFirst("span#rating")?.text() 110 | val actors = 111 | document.select("span#cast").text().split(", ") 112 | .map { it.trim() } 113 | 114 | val recommendations = 115 | document.select("section.w-full a.min-w-full").mapNotNull { it.toSearchResult() } 116 | 117 | return if (type == TvType.TvSeries) { 118 | val sectionSelector = "div.relative > section.w-full a.min-w-full" 119 | val section = document.select(sectionSelector) 120 | val hasMultipleSeason = section.any { it.attr("href").contains("/season-") } 121 | val episodes = if (hasMultipleSeason) { 122 | section.amap { ss -> 123 | fetchEpisodesFromPages( 124 | ss.attr("href"), 125 | 5, 126 | sectionSelector, 127 | true, 128 | ss.selectFirst("div.text-xl")?.text()?.filter { it.isDigit() } 129 | ?.toIntOrNull() 130 | ) 131 | }.toMutableList().flatten() 132 | } else { 133 | fetchEpisodesFromPages(media.url, 5, sectionSelector, false) 134 | } 135 | newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes.reversed()) { 136 | this.posterUrl = poster 137 | this.year = year 138 | this.seasonNames 139 | this.plot = description 140 | this.tags = tags 141 | addScore(rating) 142 | addActors(actors) 143 | this.recommendations = recommendations 144 | } 145 | } else { 146 | newMovieLoadResponse(title, url, TvType.Movie, media.url) { 147 | this.posterUrl = poster 148 | this.year = year 149 | this.plot = description 150 | this.tags = tags 151 | addScore(rating) 152 | addActors(actors) 153 | this.recommendations = recommendations 154 | } 155 | } 156 | } 157 | 158 | override suspend fun loadLinks( 159 | data: String, 160 | isCasting: Boolean, 161 | subtitleCallback: (SubtitleFile) -> Unit, 162 | callback: (ExtractorLink) -> Unit, 163 | ): Boolean { 164 | 165 | val video = app.get(data).document.select("mux-player").attr("src") 166 | 167 | callback.invoke( 168 | newExtractorLink( 169 | name, 170 | name, 171 | video 172 | ) 173 | ) 174 | 175 | return true 176 | } 177 | 178 | private suspend fun fetchEpisodesFromPages( 179 | baseUrl: String, 180 | maxPages: Int, 181 | sectionSelector: String, 182 | hasMultipleSeasons: Boolean, 183 | season: Int? = null 184 | ): MutableList { 185 | val epsData = mutableListOf() 186 | for (index in 1..maxPages) { 187 | val pageUrl = if (index == 1) baseUrl else "${baseUrl.removeSuffix("/")}/page/$index/" 188 | val episodeVo = app.get(fixUrl(pageUrl)).document.select(sectionSelector) 189 | .getEpisodes(if (hasMultipleSeasons) season else null) 190 | if (episodeVo.isEmpty()) break 191 | epsData.addAll(episodeVo) 192 | } 193 | return epsData 194 | } 195 | 196 | private fun Elements.getEpisodes(season: Int? = 1): List { 197 | return this.mapNotNull { eps -> 198 | val name = eps.selectFirst("div.text-xl")?.text() ?: return@mapNotNull null 199 | val href = fixUrl(eps.attr("href")) 200 | val posterUrl = 201 | eps.selectFirst("div.thumbnail_card")?.attr("style")?.getPoster() 202 | newEpisode( 203 | href){ 204 | this.name = name 205 | this.posterUrl = posterUrl 206 | this.season = season 207 | } 208 | } 209 | } 210 | 211 | private fun String.getPoster(): String? { 212 | return fixUrlNull( 213 | this.substringAfter("(") 214 | .substringBefore(")"), 215 | ) 216 | } 217 | 218 | data class Media(val url: String, val poster: String? = null) 219 | 220 | data class Index( 221 | @JsonProperty("title") val title: String? = null, 222 | @JsonProperty("permalink") val permalink: String? = null, 223 | @JsonProperty("section") val section: String? = null, 224 | ) 225 | } 226 | -------------------------------------------------------------------------------- /DramaSerial/src/main/kotlin/com/dramaserial/DramaSerial.kt: -------------------------------------------------------------------------------- 1 | package com.dramaserial 2 | 3 | import com.fasterxml.jackson.annotation.JsonProperty 4 | import com.lagradost.cloudstream3.* 5 | import com.lagradost.cloudstream3.extractors.Filesim 6 | import com.lagradost.cloudstream3.utils.AppUtils 7 | import com.lagradost.cloudstream3.utils.newExtractorLink 8 | import com.lagradost.cloudstream3.utils.ExtractorLink 9 | import com.lagradost.cloudstream3.utils.ExtractorLinkType 10 | import com.lagradost.cloudstream3.utils.Qualities 11 | import com.lagradost.cloudstream3.utils.getQualityFromName 12 | import org.jsoup.nodes.Element 13 | import java.net.URI 14 | 15 | class DramaSerial : MainAPI() { 16 | override var mainUrl = "https://tv3.dramaserial.id" 17 | private var serverUrl = "https://tv19.juragan.film" 18 | override var name = "DramaSerial" 19 | override val hasMainPage = true 20 | override var lang = "id" 21 | override val hasDownloadSupport = true 22 | override val supportedTypes = setOf(TvType.AsianDrama) 23 | 24 | override val mainPage = mainPageOf( 25 | "$mainUrl/page/" to "Latest Movie", 26 | "$mainUrl/Genre/ongoing/page/" to "Ongoing", 27 | "$mainUrl/Genre/drama-serial-korea/page/" to "Drama Serial Korea", 28 | "$mainUrl/Genre/drama-serial-jepang/page/" to "Drama Serial Jepang", 29 | "$mainUrl/Genre/drama-serial-mandarin/page/" to "Drama Serial Mandarin", 30 | "$mainUrl/Genre/drama-serial-filipina/page/" to "Drama Serial Filipina", 31 | "$mainUrl/Genre/drama-serial-india/page/" to "Drama Serial India", 32 | ) 33 | 34 | override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { 35 | val document = app.get(request.data + page).document 36 | val home = document.select("main#main article").mapNotNull { 37 | it.toSearchResult() 38 | } 39 | return newHomePageResponse(request.name, home) 40 | } 41 | 42 | private fun Element.toSearchResult(): SearchResponse? { 43 | val href = fixUrl(this.selectFirst("a")!!.attr("href")) 44 | val title = this.selectFirst("h2.entry-title a")?.text()?.trim() ?: return null 45 | val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src")) 46 | val episode = this.selectFirst("div.gmr-episode-item") 47 | ?.text() 48 | ?.filter { it.isDigit() } 49 | ?.toIntOrNull() 50 | 51 | return newAnimeSearchResponse(title, href, TvType.AsianDrama) { 52 | this.posterUrl = posterUrl 53 | addSub(episode) 54 | } 55 | } 56 | 57 | override suspend fun search(query: String): List { 58 | val link = "$mainUrl/?s=$query&post_type[]=post&post_type[]=tv" 59 | val document = app.get(link).document 60 | 61 | return document.select("main#main article").mapNotNull { 62 | it.toSearchResult() 63 | } 64 | } 65 | 66 | override suspend fun load(url: String): LoadResponse { 67 | val document = app.get(url).document 68 | 69 | val title = document.selectFirst("h1.entry-title")!!.text().trim() 70 | val poster = fixUrlNull(document.selectFirst("figure.pull-left img")?.attr("src")) 71 | val tags = document.select("div.gmr-movie-innermeta span:contains(Genre:) a").map { it.text() } 72 | val year = document.selectFirst("div.gmr-movie-innermeta span:contains(Year:) a") 73 | ?.text() 74 | ?.trim() 75 | ?.toIntOrNull() 76 | val duration = document.selectFirst("div.gmr-movie-innermeta span:contains(Duration:)") 77 | ?.text() 78 | ?.filter { it.isDigit() } 79 | ?.toIntOrNull() 80 | val description = document.select("div.entry-content.entry-content-single div.entry-content.entry-content-single") 81 | .text() 82 | .trim() 83 | val type = if (document.select("div.page-links").isEmpty()) { 84 | TvType.Movie 85 | } else { 86 | TvType.AsianDrama 87 | } 88 | 89 | return if (type == TvType.Movie) { 90 | newMovieLoadResponse(title, url, TvType.Movie, url) { 91 | posterUrl = poster 92 | this.year = year 93 | plot = description 94 | this.tags = tags 95 | this.duration = duration 96 | } 97 | } else { 98 | val episodes = document.select("div.page-links span.page-link-number").mapNotNull { epsElement -> 99 | val episodeNumber = epsElement.text().filter { it.isDigit() }.toIntOrNull() 100 | 101 | val episodePageLink = if (episodeNumber == 1) { 102 | url 103 | } else { 104 | epsElement.parent()?.attr("href")?.let { fixUrl(it) } 105 | } 106 | 107 | if (episodePageLink == null) return@mapNotNull null 108 | 109 | val episodeName = "Episode $episodeNumber" 110 | newEpisode(episodePageLink) { 111 | this.name = episodeName 112 | this.episode = episodeNumber 113 | } 114 | } 115 | 116 | newTvSeriesLoadResponse(title, url, TvType.AsianDrama, episodes) { 117 | posterUrl = poster 118 | this.year = year 119 | plot = description 120 | this.tags = tags 121 | } 122 | } 123 | } 124 | 125 | private suspend fun invokeGetbk( 126 | name: String, 127 | url: String, 128 | callback: (ExtractorLink) -> Unit 129 | ) { 130 | val script = app.get(url, referer = "$serverUrl/") 131 | .document 132 | .selectFirst("script:containsData(sources)") 133 | ?.data() 134 | ?: return 135 | 136 | val json = Regex("""sources\s*:\s*(\[[^\]]+\])""") 137 | .find(script) 138 | ?.groupValues 139 | ?.getOrNull(1) 140 | ?: return 141 | 142 | AppUtils.tryParseJson>(json)?.forEach { source -> 143 | callback.invoke( 144 | newExtractorLink( 145 | name, 146 | name, 147 | source.file.toString() 148 | ) { 149 | this.referer = "$mainUrl/" 150 | this.quality = getQualityFromName(source.label) 151 | } 152 | ) 153 | } 154 | } 155 | 156 | private suspend fun invokeGdrive( 157 | name: String, 158 | url: String, 159 | callback: (ExtractorLink) -> Unit 160 | ) { 161 | val embedUrl = app.get(url, referer = "$serverUrl/") 162 | .document 163 | .selectFirst("iframe") 164 | ?.attr("src") 165 | ?.let { fixUrl(it) } 166 | ?: return 167 | 168 | val req = app.get(embedUrl) 169 | val host = getBaseUrl(embedUrl) 170 | val token = req.document.selectFirst("div#token")?.text() ?: return 171 | 172 | callback.invoke( 173 | newExtractorLink( 174 | name, 175 | name, 176 | "$host/hlsplaylist.php?idhls=${token.trim()}.m3u8", 177 | ExtractorLinkType.M3U8 178 | ) { 179 | this.referer = "$host/" 180 | } 181 | ) 182 | } 183 | 184 | override suspend fun loadLinks( 185 | data: String, 186 | isCasting: Boolean, 187 | subtitleCallback: (SubtitleFile) -> Unit, 188 | callback: (ExtractorLink) -> Unit 189 | ): Boolean { 190 | val document = app.get(data).document 191 | val iframe = document.select("iframe[name=juraganfilm]").attr("src") 192 | 193 | app.get(iframe, referer = "$mainUrl/").document.select("div#header-slider ul li") 194 | .amap { mLink -> 195 | val iLink = mLink.attr("onclick").substringAfter("frame('").substringBefore("')") 196 | serverUrl = getBaseUrl(iLink) 197 | val iMovie = iLink.substringAfter("movie=").substringBefore("&") 198 | val mIframe = iLink.substringAfter("iframe=") 199 | val serverName = fixTitle(mIframe) 200 | 201 | when (mIframe) { 202 | "getbk" -> invokeGetbk(serverName, "$serverUrl/stream/$mIframe.php?movie=$iMovie", callback) 203 | "gdrivehls", "gdriveplayer" -> invokeGdrive(serverName, iLink, callback) 204 | else -> {} 205 | } 206 | } 207 | 208 | return true 209 | } 210 | 211 | private fun getBaseUrl(url: String): String { 212 | return URI(url).let { "${it.scheme}://${it.host}" } 213 | } 214 | 215 | data class Sources( 216 | @JsonProperty("file") val file: String? = null, 217 | @JsonProperty("label") val label: String? = null, 218 | ) 219 | } 220 | 221 | class Bk21 : Filesim() { 222 | override val name = "Bk21" 223 | override var mainUrl = "https://bk21.net" 224 | } 225 | 226 | class Lkc21 : Filesim() { 227 | override val name = "Lkc21" 228 | override var mainUrl = "https://lkc21.net" 229 | } 230 | -------------------------------------------------------------------------------- /Animasu/src/main/kotlin/com/animasu/Animasu.kt: -------------------------------------------------------------------------------- 1 | package com.animasu 2 | 3 | import com.lagradost.cloudstream3.* 4 | import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId 5 | import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId 6 | import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer 7 | import com.lagradost.cloudstream3.SubtitleFile 8 | import com.lagradost.cloudstream3.app 9 | import com.lagradost.cloudstream3.base64Decode 10 | import com.lagradost.cloudstream3.utils.* 11 | import kotlinx.coroutines.CoroutineScope 12 | import kotlinx.coroutines.Dispatchers 13 | import kotlinx.coroutines.launch 14 | import org.jsoup.Jsoup 15 | import org.jsoup.nodes.Element 16 | 17 | class Animasu : MainAPI() { 18 | override var mainUrl = "https://v1.animasu.top" 19 | override var name = "Animasu" 20 | override val hasMainPage = true 21 | override var lang = "id" 22 | override val hasDownloadSupport = true 23 | 24 | override val supportedTypes = setOf(TvType.Anime, TvType.AnimeMovie, TvType.OVA) 25 | 26 | companion object { 27 | fun getType(t: String?): TvType { 28 | if (t == null) return TvType.Anime 29 | return when { 30 | t.contains("Tv", true) -> TvType.Anime 31 | t.contains("Movie", true) -> TvType.AnimeMovie 32 | t.contains("OVA", true) || t.contains("Special", true) -> TvType.OVA 33 | else -> TvType.Anime 34 | } 35 | } 36 | 37 | fun getStatus(t: String?): ShowStatus { 38 | if (t == null) return ShowStatus.Completed 39 | return when { 40 | t.contains("Sedang Tayang", true) -> ShowStatus.Ongoing 41 | else -> ShowStatus.Completed 42 | } 43 | } 44 | } 45 | 46 | override val mainPage = 47 | mainPageOf( 48 | "urutan=update" to "Baru diupdate", 49 | "status=&tipe=&urutan=publikasi" to "Baru ditambahkan", 50 | "status=&tipe=&urutan=populer" to "Terpopuler", 51 | "status=&tipe=&urutan=rating" to "Rating Tertinggi", 52 | "status=&tipe=Movie&urutan=update" to "Movie Terbaru", 53 | "status=&tipe=Movie&urutan=populer" to "Movie Terpopuler", 54 | ) 55 | 56 | override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { 57 | val document = app.get("$mainUrl/pencarian/?${request.data}&halaman=$page").document 58 | val home = document.select("div.listupd div.bs").map { it.toSearchResult() } 59 | return newHomePageResponse(request.name, home) 60 | } 61 | 62 | private fun getProperAnimeLink(uri: String): String { 63 | return if (uri.contains("/anime/")) { 64 | uri 65 | } else { 66 | var title = uri.substringAfter("$mainUrl/") 67 | title = 68 | when { 69 | (title.contains("-episode")) && !(title.contains("-movie")) -> 70 | title.substringBefore("-episode") 71 | (title.contains("-movie")) -> title.substringBefore("-movie") 72 | else -> title 73 | } 74 | 75 | "$mainUrl/anime/$title" 76 | } 77 | } 78 | 79 | private fun Element.toSearchResult(): AnimeSearchResponse { 80 | val href = getProperAnimeLink(fixUrlNull(this.selectFirst("a")?.attr("href")).toString()) 81 | val title = this.select("div.tt").text().trim() 82 | val posterUrl = this.selectFirst("div.limit img")?.attr("src").toString() 83 | val epNum = this.selectFirst("span.epx")?.text()?.filter { it.isDigit() }?.toIntOrNull() 84 | return newAnimeSearchResponse(title, href, TvType.Anime) { 85 | this.posterUrl = posterUrl 86 | addSub(epNum) 87 | } 88 | } 89 | 90 | override suspend fun search(query: String): List { 91 | return app.get("$mainUrl/?s=$query").document.select("div.listupd div.bs").map { 92 | it.toSearchResult() 93 | } 94 | } 95 | 96 | override suspend fun load(url: String): LoadResponse { 97 | val document = app.get(url).document 98 | 99 | val title = 100 | document.selectFirst("div.infox h1") 101 | ?.text() 102 | .toString() 103 | .replace("Sub Indo", "") 104 | .trim() 105 | val poster = document.selectFirst("div.bigcontent img")?.attr("src").toString() 106 | 107 | val table = document.selectFirst("div.infox div.spe") 108 | val type = getType(table?.selectFirst("span:contains(Jenis:)")?.ownText()) 109 | val year = 110 | table?.selectFirst("span:contains(Rilis:)") 111 | ?.ownText() 112 | ?.substringAfterLast(",") 113 | ?.trim() 114 | ?.toIntOrNull() 115 | val status = table?.selectFirst("span:contains(Status:) font")?.text() 116 | val trailer = document.selectFirst("div.trailer iframe")?.attr("src") 117 | val episodes = 118 | document.select("ul#daftarepisode > li") 119 | .mapNotNull { 120 | val link = fixUrl(it.selectFirst("a")!!.attr("href")) 121 | val episodeName = it.selectFirst("a")?.text() ?: return@mapNotNull null 122 | val episodeNumber = 123 | Regex("Episode\\s?(\\d+)") 124 | .find(episodeName) 125 | ?.groupValues 126 | ?.getOrNull(1) // Corrected group index 127 | ?.toIntOrNull() 128 | newEpisode(link) { // 'link' is the 'data' argument 129 | this.name = episodeName // Set the name property 130 | this.episode = episodeNumber // Set the episode property 131 | } 132 | } 133 | .reversed() 134 | 135 | val tracker = APIHolder.getTracker(listOf(title), TrackerType.getTypes(type), year, true) 136 | 137 | return newAnimeLoadResponse(title, url, type) { 138 | posterUrl = tracker?.image ?: poster 139 | backgroundPosterUrl = tracker?.cover 140 | this.year = year 141 | addEpisodes(DubStatus.Subbed, episodes) 142 | showStatus = getStatus(status) 143 | plot = document.select("div.sinopsis p").text() 144 | this.tags = table?.select("span:contains(Genre:) a")?.map { it.text() } 145 | addTrailer(trailer) 146 | addMalId(tracker?.malId) 147 | addAniListId(tracker?.aniId?.toIntOrNull()) 148 | } 149 | } 150 | 151 | override suspend fun loadLinks( 152 | data: String, 153 | isCasting: Boolean, 154 | subtitleCallback: (SubtitleFile) -> Unit, 155 | callback: (ExtractorLink) -> Unit 156 | ): Boolean { 157 | val document = app.get(data).document 158 | document.select(".mobius > .mirror > option") 159 | .mapNotNull { 160 | fixUrl( 161 | Jsoup.parse(base64Decode(it.attr("value"))).select("iframe").attr("src") 162 | ) to it.text() 163 | } 164 | .amap { (iframe, quality) -> 165 | loadFixedExtractor( 166 | iframe.fixIframe(), 167 | quality, 168 | "$mainUrl/", 169 | subtitleCallback, 170 | callback 171 | ) 172 | } 173 | return true 174 | } 175 | 176 | private suspend fun loadFixedExtractor( 177 | name: String? = null, 178 | url: String, 179 | referer: String? = null, 180 | subtitleCallback: (SubtitleFile) -> Unit, 181 | callback: (ExtractorLink) -> Unit, 182 | quality: Int? = null, 183 | ) { 184 | loadExtractor(url, referer, subtitleCallback) { link -> 185 | CoroutineScope(Dispatchers.IO).launch { 186 | callback.invoke( 187 | newExtractorLink( 188 | name ?: link.source, 189 | name ?: link.name, 190 | link.url, 191 | ) { 192 | this.quality = when { 193 | else -> quality ?: link.quality 194 | } 195 | this.type = link.type 196 | this.referer = link.referer 197 | this.headers = link.headers 198 | this.extractorData = link.extractorData 199 | } 200 | ) 201 | } 202 | } 203 | } 204 | 205 | private fun String.fixIframe(): String { 206 | return if (this.startsWith("https://dl.berkasdrive.com")) { 207 | base64Decode(this.substringAfter("id=")) 208 | } else { 209 | this 210 | } 211 | } 212 | 213 | } 214 | --------------------------------------------------------------------------------