├── 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 |
--------------------------------------------------------------------------------