From b3f33b368a15a571eb99fdf389881b5168f42979 Mon Sep 17 00:00:00 2001
From: Blatzar <46196380+Blatzar@users.noreply.github.com>
Date: Thu, 11 Aug 2022 16:55:58 +0200
Subject: [PATCH] Add anime providers
---
AA_BLANK/build.gradle.kts | 22 +
AA_BLANK/src/main/AndroidManifest.xml | 2 +
AllAnimeProvider/build.gradle.kts | 22 +
AllAnimeProvider/src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/AllAnimeProvider.kt | 404 +++++++++++++
.../com/lagradost/AllAnimeProviderPlugin.kt | 14 +
AniPlayProvider/build.gradle.kts | 22 +
AniPlayProvider/src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/AniPlayProvider.kt | 215 +++++++
.../com/lagradost/AniPlayProviderPlugin.kt | 14 +
AniflixProvider/build.gradle.kts | 22 +
AniflixProvider/src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/AniflixProvider.kt | 274 +++++++++
.../com/lagradost/AniflixProviderPlugin.kt | 14 +
AnimeFlickProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../com/lagradost/AnimeFlickProvider.kt | 119 ++++
.../com/lagradost/AnimeFlickProviderPlugin.kt | 14 +
AnimeIndoProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/AnimeIndoProvider.kt | 192 ++++++
.../com/lagradost/AnimeIndoProviderPlugin.kt | 14 +
AnimePaheProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/AnimePaheProvider.kt | 562 ++++++++++++++++++
.../com/lagradost/AnimePaheProviderPlugin.kt | 14 +
AnimeSailProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/AnimeSailProvider.kt | 191 ++++++
.../com/lagradost/AnimeSailProviderPlugin.kt | 14 +
AnimeSaturnProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../com/lagradost/AnimeSaturnProvider.kt | 201 +++++++
.../lagradost/AnimeSaturnProviderPlugin.kt | 14 +
AnimeWorldProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../com/lagradost/AnimeWorldProvider.kt | 265 +++++++++
.../com/lagradost/AnimeWorldProviderPlugin.kt | 14 +
AnimefenixProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../com/lagradost/AnimefenixProvider.kt | 249 ++++++++
.../com/lagradost/AnimefenixProviderPlugin.kt | 14 +
AnimeflvIOProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../com/lagradost/AnimeflvIOProvider.kt | 239 ++++++++
.../com/lagradost/AnimeflvIOProviderPlugin.kt | 14 +
AnimeflvnetProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../com/lagradost/AnimeflvnetProvider.kt | 182 ++++++
.../lagradost/AnimeflvnetProviderPlugin.kt | 14 +
AnimekisaProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/AnimekisaProvider.kt | 131 ++++
.../com/lagradost/AnimekisaProviderPlugin.kt | 14 +
.../kotlin/com/lagradost/DoramasYTProvider.kt | 14 +-
.../main/kotlin/com/lagradost/XStreamCdn.kt | 67 +++
DubbedAnimeProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../com/lagradost/DubbedAnimeProvider.kt | 270 +++++++++
.../lagradost/DubbedAnimeProviderPlugin.kt | 14 +
GogoanimeProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/GogoanimeProvider.kt | 412 +++++++++++++
.../com/lagradost/GogoanimeProviderPlugin.kt | 14 +
GomunimeProvider/build.gradle.kts | 22 +
GomunimeProvider/src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/GomunimeProvider.kt | 232 ++++++++
.../com/lagradost/GomunimeProviderPlugin.kt | 14 +
JKAnimeProvider/build.gradle.kts | 22 +
JKAnimeProvider/src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/JKAnimeProvider.kt | 319 ++++++++++
.../com/lagradost/JKAnimeProviderPlugin.kt | 14 +
KawaiifuProvider/build.gradle.kts | 22 +
KawaiifuProvider/src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/KawaiifuProvider.kt | 174 ++++++
.../com/lagradost/KawaiifuProviderPlugin.kt | 14 +
KimCartoonProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../com/lagradost/KimCartoonProvider.kt | 152 +++++
.../com/lagradost/KimCartoonProviderPlugin.kt | 14 +
KuramanimeProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../com/lagradost/KuramanimeProvider.kt | 176 ++++++
.../com/lagradost/KuramanimeProviderPlugin.kt | 14 +
KuronimeProvider/build.gradle.kts | 22 +
KuronimeProvider/src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/KuronimeProvider.kt | 197 ++++++
.../com/lagradost/KuronimeProviderPlugin.kt | 14 +
MonoschinosProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../com/lagradost/MonoschinosProvider.kt | 155 +++++
.../lagradost/MonoschinosProviderPlugin.kt | 14 +
.../main/kotlin/com/lagradost/XStreamCdn.kt | 67 +++
MundoDonghuaProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../com/lagradost/MundoDonghuaProvider.kt | 217 +++++++
.../lagradost/MundoDonghuaProviderPlugin.kt | 14 +
NeonimeProvider/build.gradle.kts | 22 +
NeonimeProvider/src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/NeonimeProvider.kt | 178 ++++++
.../com/lagradost/NeonimeProviderPlugin.kt | 14 +
NineAnimeProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/NineAnimeProvider.kt | 357 +++++++++++
.../com/lagradost/NineAnimeProviderPlugin.kt | 27 +
.../main/kotlin/com/lagradost/WcoProvider.kt | 238 ++++++++
.../main/kotlin/com/lagradost/WcoStream.kt | 133 +++++
NontonAnimeIDProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../com/lagradost/NontonAnimeIDProvider.kt | 257 ++++++++
.../lagradost/NontonAnimeIDProviderPlugin.kt | 14 +
OploverzProvider/build.gradle.kts | 22 +
OploverzProvider/src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/OploverzProvider.kt | 203 +++++++
.../com/lagradost/OploverzProviderPlugin.kt | 14 +
OtakudesuProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/OtakudesuProvider.kt | 204 +++++++
.../com/lagradost/OtakudesuProviderPlugin.kt | 14 +
SflixProvider/build.gradle.kts | 4 +-
.../com/lagradost/SflixProviderPlugin.kt | 1 +
.../main/kotlin/com/lagradost/ZoroProvider.kt | 371 ++++++++++++
TenshiProvider/build.gradle.kts | 22 +
TenshiProvider/src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/TenshiProvider.kt | 352 +++++++++++
.../com/lagradost/TenshiProviderPlugin.kt | 14 +
TocanimeProvider/build.gradle.kts | 22 +
TocanimeProvider/src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/TocanimeProvider.kt | 178 ++++++
.../com/lagradost/TocanimeProviderPlugin.kt | 14 +
WatchCartoonOnlineProvider/build.gradle.kts | 22 +
.../src/main/AndroidManifest.xml | 2 +
.../lagradost/WatchCartoonOnlineProvider.kt | 270 +++++++++
.../WatchCartoonOnlineProviderPlugin.kt | 14 +
WcofunProvider/build.gradle.kts | 22 +
WcofunProvider/src/main/AndroidManifest.xml | 2 +
.../kotlin/com/lagradost/WcofunProvider.kt | 172 ++++++
.../com/lagradost/WcofunProviderPlugin.kt | 14 +
settings.gradle.kts | 35 ++
139 files changed, 9873 insertions(+), 9 deletions(-)
create mode 100644 AA_BLANK/build.gradle.kts
create mode 100644 AA_BLANK/src/main/AndroidManifest.xml
create mode 100644 AllAnimeProvider/build.gradle.kts
create mode 100644 AllAnimeProvider/src/main/AndroidManifest.xml
create mode 100644 AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProvider.kt
create mode 100644 AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProviderPlugin.kt
create mode 100644 AniPlayProvider/build.gradle.kts
create mode 100644 AniPlayProvider/src/main/AndroidManifest.xml
create mode 100644 AniPlayProvider/src/main/kotlin/com/lagradost/AniPlayProvider.kt
create mode 100644 AniPlayProvider/src/main/kotlin/com/lagradost/AniPlayProviderPlugin.kt
create mode 100644 AniflixProvider/build.gradle.kts
create mode 100644 AniflixProvider/src/main/AndroidManifest.xml
create mode 100644 AniflixProvider/src/main/kotlin/com/lagradost/AniflixProvider.kt
create mode 100644 AniflixProvider/src/main/kotlin/com/lagradost/AniflixProviderPlugin.kt
create mode 100644 AnimeFlickProvider/build.gradle.kts
create mode 100644 AnimeFlickProvider/src/main/AndroidManifest.xml
create mode 100644 AnimeFlickProvider/src/main/kotlin/com/lagradost/AnimeFlickProvider.kt
create mode 100644 AnimeFlickProvider/src/main/kotlin/com/lagradost/AnimeFlickProviderPlugin.kt
create mode 100644 AnimeIndoProvider/build.gradle.kts
create mode 100644 AnimeIndoProvider/src/main/AndroidManifest.xml
create mode 100644 AnimeIndoProvider/src/main/kotlin/com/lagradost/AnimeIndoProvider.kt
create mode 100644 AnimeIndoProvider/src/main/kotlin/com/lagradost/AnimeIndoProviderPlugin.kt
create mode 100644 AnimePaheProvider/build.gradle.kts
create mode 100644 AnimePaheProvider/src/main/AndroidManifest.xml
create mode 100644 AnimePaheProvider/src/main/kotlin/com/lagradost/AnimePaheProvider.kt
create mode 100644 AnimePaheProvider/src/main/kotlin/com/lagradost/AnimePaheProviderPlugin.kt
create mode 100644 AnimeSailProvider/build.gradle.kts
create mode 100644 AnimeSailProvider/src/main/AndroidManifest.xml
create mode 100644 AnimeSailProvider/src/main/kotlin/com/lagradost/AnimeSailProvider.kt
create mode 100644 AnimeSailProvider/src/main/kotlin/com/lagradost/AnimeSailProviderPlugin.kt
create mode 100644 AnimeSaturnProvider/build.gradle.kts
create mode 100644 AnimeSaturnProvider/src/main/AndroidManifest.xml
create mode 100644 AnimeSaturnProvider/src/main/kotlin/com/lagradost/AnimeSaturnProvider.kt
create mode 100644 AnimeSaturnProvider/src/main/kotlin/com/lagradost/AnimeSaturnProviderPlugin.kt
create mode 100644 AnimeWorldProvider/build.gradle.kts
create mode 100644 AnimeWorldProvider/src/main/AndroidManifest.xml
create mode 100644 AnimeWorldProvider/src/main/kotlin/com/lagradost/AnimeWorldProvider.kt
create mode 100644 AnimeWorldProvider/src/main/kotlin/com/lagradost/AnimeWorldProviderPlugin.kt
create mode 100644 AnimefenixProvider/build.gradle.kts
create mode 100644 AnimefenixProvider/src/main/AndroidManifest.xml
create mode 100644 AnimefenixProvider/src/main/kotlin/com/lagradost/AnimefenixProvider.kt
create mode 100644 AnimefenixProvider/src/main/kotlin/com/lagradost/AnimefenixProviderPlugin.kt
create mode 100644 AnimeflvIOProvider/build.gradle.kts
create mode 100644 AnimeflvIOProvider/src/main/AndroidManifest.xml
create mode 100644 AnimeflvIOProvider/src/main/kotlin/com/lagradost/AnimeflvIOProvider.kt
create mode 100644 AnimeflvIOProvider/src/main/kotlin/com/lagradost/AnimeflvIOProviderPlugin.kt
create mode 100644 AnimeflvnetProvider/build.gradle.kts
create mode 100644 AnimeflvnetProvider/src/main/AndroidManifest.xml
create mode 100644 AnimeflvnetProvider/src/main/kotlin/com/lagradost/AnimeflvnetProvider.kt
create mode 100644 AnimeflvnetProvider/src/main/kotlin/com/lagradost/AnimeflvnetProviderPlugin.kt
create mode 100644 AnimekisaProvider/build.gradle.kts
create mode 100644 AnimekisaProvider/src/main/AndroidManifest.xml
create mode 100644 AnimekisaProvider/src/main/kotlin/com/lagradost/AnimekisaProvider.kt
create mode 100644 AnimekisaProvider/src/main/kotlin/com/lagradost/AnimekisaProviderPlugin.kt
create mode 100644 DoramasYTProvider/src/main/kotlin/com/lagradost/XStreamCdn.kt
create mode 100644 DubbedAnimeProvider/build.gradle.kts
create mode 100644 DubbedAnimeProvider/src/main/AndroidManifest.xml
create mode 100644 DubbedAnimeProvider/src/main/kotlin/com/lagradost/DubbedAnimeProvider.kt
create mode 100644 DubbedAnimeProvider/src/main/kotlin/com/lagradost/DubbedAnimeProviderPlugin.kt
create mode 100644 GogoanimeProvider/build.gradle.kts
create mode 100644 GogoanimeProvider/src/main/AndroidManifest.xml
create mode 100644 GogoanimeProvider/src/main/kotlin/com/lagradost/GogoanimeProvider.kt
create mode 100644 GogoanimeProvider/src/main/kotlin/com/lagradost/GogoanimeProviderPlugin.kt
create mode 100644 GomunimeProvider/build.gradle.kts
create mode 100644 GomunimeProvider/src/main/AndroidManifest.xml
create mode 100644 GomunimeProvider/src/main/kotlin/com/lagradost/GomunimeProvider.kt
create mode 100644 GomunimeProvider/src/main/kotlin/com/lagradost/GomunimeProviderPlugin.kt
create mode 100644 JKAnimeProvider/build.gradle.kts
create mode 100644 JKAnimeProvider/src/main/AndroidManifest.xml
create mode 100644 JKAnimeProvider/src/main/kotlin/com/lagradost/JKAnimeProvider.kt
create mode 100644 JKAnimeProvider/src/main/kotlin/com/lagradost/JKAnimeProviderPlugin.kt
create mode 100644 KawaiifuProvider/build.gradle.kts
create mode 100644 KawaiifuProvider/src/main/AndroidManifest.xml
create mode 100644 KawaiifuProvider/src/main/kotlin/com/lagradost/KawaiifuProvider.kt
create mode 100644 KawaiifuProvider/src/main/kotlin/com/lagradost/KawaiifuProviderPlugin.kt
create mode 100644 KimCartoonProvider/build.gradle.kts
create mode 100644 KimCartoonProvider/src/main/AndroidManifest.xml
create mode 100644 KimCartoonProvider/src/main/kotlin/com/lagradost/KimCartoonProvider.kt
create mode 100644 KimCartoonProvider/src/main/kotlin/com/lagradost/KimCartoonProviderPlugin.kt
create mode 100644 KuramanimeProvider/build.gradle.kts
create mode 100644 KuramanimeProvider/src/main/AndroidManifest.xml
create mode 100644 KuramanimeProvider/src/main/kotlin/com/lagradost/KuramanimeProvider.kt
create mode 100644 KuramanimeProvider/src/main/kotlin/com/lagradost/KuramanimeProviderPlugin.kt
create mode 100644 KuronimeProvider/build.gradle.kts
create mode 100644 KuronimeProvider/src/main/AndroidManifest.xml
create mode 100644 KuronimeProvider/src/main/kotlin/com/lagradost/KuronimeProvider.kt
create mode 100644 KuronimeProvider/src/main/kotlin/com/lagradost/KuronimeProviderPlugin.kt
create mode 100644 MonoschinosProvider/build.gradle.kts
create mode 100644 MonoschinosProvider/src/main/AndroidManifest.xml
create mode 100644 MonoschinosProvider/src/main/kotlin/com/lagradost/MonoschinosProvider.kt
create mode 100644 MonoschinosProvider/src/main/kotlin/com/lagradost/MonoschinosProviderPlugin.kt
create mode 100644 MonoschinosProvider/src/main/kotlin/com/lagradost/XStreamCdn.kt
create mode 100644 MundoDonghuaProvider/build.gradle.kts
create mode 100644 MundoDonghuaProvider/src/main/AndroidManifest.xml
create mode 100644 MundoDonghuaProvider/src/main/kotlin/com/lagradost/MundoDonghuaProvider.kt
create mode 100644 MundoDonghuaProvider/src/main/kotlin/com/lagradost/MundoDonghuaProviderPlugin.kt
create mode 100644 NeonimeProvider/build.gradle.kts
create mode 100644 NeonimeProvider/src/main/AndroidManifest.xml
create mode 100644 NeonimeProvider/src/main/kotlin/com/lagradost/NeonimeProvider.kt
create mode 100644 NeonimeProvider/src/main/kotlin/com/lagradost/NeonimeProviderPlugin.kt
create mode 100644 NineAnimeProvider/build.gradle.kts
create mode 100644 NineAnimeProvider/src/main/AndroidManifest.xml
create mode 100644 NineAnimeProvider/src/main/kotlin/com/lagradost/NineAnimeProvider.kt
create mode 100644 NineAnimeProvider/src/main/kotlin/com/lagradost/NineAnimeProviderPlugin.kt
create mode 100644 NineAnimeProvider/src/main/kotlin/com/lagradost/WcoProvider.kt
create mode 100644 NineAnimeProvider/src/main/kotlin/com/lagradost/WcoStream.kt
create mode 100644 NontonAnimeIDProvider/build.gradle.kts
create mode 100644 NontonAnimeIDProvider/src/main/AndroidManifest.xml
create mode 100644 NontonAnimeIDProvider/src/main/kotlin/com/lagradost/NontonAnimeIDProvider.kt
create mode 100644 NontonAnimeIDProvider/src/main/kotlin/com/lagradost/NontonAnimeIDProviderPlugin.kt
create mode 100644 OploverzProvider/build.gradle.kts
create mode 100644 OploverzProvider/src/main/AndroidManifest.xml
create mode 100644 OploverzProvider/src/main/kotlin/com/lagradost/OploverzProvider.kt
create mode 100644 OploverzProvider/src/main/kotlin/com/lagradost/OploverzProviderPlugin.kt
create mode 100644 OtakudesuProvider/build.gradle.kts
create mode 100644 OtakudesuProvider/src/main/AndroidManifest.xml
create mode 100644 OtakudesuProvider/src/main/kotlin/com/lagradost/OtakudesuProvider.kt
create mode 100644 OtakudesuProvider/src/main/kotlin/com/lagradost/OtakudesuProviderPlugin.kt
create mode 100644 SflixProvider/src/main/kotlin/com/lagradost/ZoroProvider.kt
create mode 100644 TenshiProvider/build.gradle.kts
create mode 100644 TenshiProvider/src/main/AndroidManifest.xml
create mode 100644 TenshiProvider/src/main/kotlin/com/lagradost/TenshiProvider.kt
create mode 100644 TenshiProvider/src/main/kotlin/com/lagradost/TenshiProviderPlugin.kt
create mode 100644 TocanimeProvider/build.gradle.kts
create mode 100644 TocanimeProvider/src/main/AndroidManifest.xml
create mode 100644 TocanimeProvider/src/main/kotlin/com/lagradost/TocanimeProvider.kt
create mode 100644 TocanimeProvider/src/main/kotlin/com/lagradost/TocanimeProviderPlugin.kt
create mode 100644 WatchCartoonOnlineProvider/build.gradle.kts
create mode 100644 WatchCartoonOnlineProvider/src/main/AndroidManifest.xml
create mode 100644 WatchCartoonOnlineProvider/src/main/kotlin/com/lagradost/WatchCartoonOnlineProvider.kt
create mode 100644 WatchCartoonOnlineProvider/src/main/kotlin/com/lagradost/WatchCartoonOnlineProviderPlugin.kt
create mode 100644 WcofunProvider/build.gradle.kts
create mode 100644 WcofunProvider/src/main/AndroidManifest.xml
create mode 100644 WcofunProvider/src/main/kotlin/com/lagradost/WcofunProvider.kt
create mode 100644 WcofunProvider/src/main/kotlin/com/lagradost/WcofunProviderPlugin.kt
diff --git a/AA_BLANK/build.gradle.kts b/AA_BLANK/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/AA_BLANK/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // description = "Lorem Ipsum"
+ // authors = listOf("Cloudburst")
+
+ /**
+ * Status int as the following:
+ * 0: Down
+ * 1: Ok
+ * 2: Slow
+ * 3: Beta only
+ * */
+ status = 1 // will be 3 if unspecified
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/AA_BLANK/src/main/AndroidManifest.xml b/AA_BLANK/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/AA_BLANK/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/AllAnimeProvider/build.gradle.kts b/AllAnimeProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/AllAnimeProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // description = "Lorem Ipsum"
+ // authors = listOf("Cloudburst")
+
+ /**
+ * Status int as the following:
+ * 0: Down
+ * 1: Ok
+ * 2: Slow
+ * 3: Beta only
+ * */
+ status = 1 // will be 3 if unspecified
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/AllAnimeProvider/src/main/AndroidManifest.xml b/AllAnimeProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/AllAnimeProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProvider.kt b/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProvider.kt
new file mode 100644
index 0000000..6a340e5
--- /dev/null
+++ b/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProvider.kt
@@ -0,0 +1,404 @@
+package com.lagradost
+
+import com.fasterxml.jackson.annotation.JsonProperty
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
+import com.lagradost.cloudstream3.mvvm.safeApiCall
+import com.lagradost.cloudstream3.utils.AppUtils.parseJson
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.M3u8Helper
+import com.lagradost.cloudstream3.utils.Qualities
+import org.jsoup.Jsoup
+import org.mozilla.javascript.Context
+import org.mozilla.javascript.Scriptable
+import java.net.URI
+import java.net.URLDecoder
+
+
+class AllAnimeProvider : MainAPI() {
+ override var mainUrl = "https://allanime.site"
+ override var name = "AllAnime"
+ override val hasQuickSearch = false
+ override val hasMainPage = true
+
+ private fun getStatus(t: String): ShowStatus {
+ return when (t) {
+ "Finished" -> ShowStatus.Completed
+ "Releasing" -> ShowStatus.Ongoing
+ else -> ShowStatus.Completed
+ }
+ }
+
+ override val supportedTypes = setOf(TvType.Anime, TvType.AnimeMovie)
+
+ private data class Data(
+ @JsonProperty("shows") val shows: Shows
+ )
+
+ private data class Shows(
+ @JsonProperty("pageInfo") val pageInfo: PageInfo,
+ @JsonProperty("edges") val edges: List,
+ @JsonProperty("__typename") val _typename: String
+ )
+
+ private data class Edges(
+ @JsonProperty("_id") val Id: String?,
+ @JsonProperty("name") val name: String,
+ @JsonProperty("englishName") val englishName: String?,
+ @JsonProperty("nativeName") val nativeName: String?,
+ @JsonProperty("thumbnail") val thumbnail: String?,
+ @JsonProperty("type") val type: String?,
+ @JsonProperty("season") val season: Season?,
+ @JsonProperty("score") val score: Double?,
+ @JsonProperty("airedStart") val airedStart: AiredStart?,
+ @JsonProperty("availableEpisodes") val availableEpisodes: AvailableEpisodes?,
+ @JsonProperty("availableEpisodesDetail") val availableEpisodesDetail: AvailableEpisodesDetail?,
+ @JsonProperty("studios") val studios: List?,
+ @JsonProperty("description") val description: String?,
+ @JsonProperty("status") val status: String?,
+ )
+
+ private data class AvailableEpisodes(
+ @JsonProperty("sub") val sub: Int,
+ @JsonProperty("dub") val dub: Int,
+ @JsonProperty("raw") val raw: Int
+ )
+
+ private data class AiredStart(
+ @JsonProperty("year") val year: Int,
+ @JsonProperty("month") val month: Int,
+ @JsonProperty("date") val date: Int
+ )
+
+ private data class Season(
+ @JsonProperty("quarter") val quarter: String,
+ @JsonProperty("year") val year: Int
+ )
+
+ private data class PageInfo(
+ @JsonProperty("total") val total: Int,
+ @JsonProperty("__typename") val _typename: String
+ )
+
+ private data class AllAnimeQuery(
+ @JsonProperty("data") val data: Data
+ )
+
+ data class RandomMain(
+ @JsonProperty("data") var data: DataRan? = DataRan()
+ )
+
+ data class DataRan(
+ @JsonProperty("queryRandomRecommendation") var queryRandomRecommendation: ArrayList = arrayListOf()
+ )
+
+ data class QueryRandomRecommendation(
+ @JsonProperty("_id") val Id: String? = null,
+ @JsonProperty("name") val name: String? = null,
+ @JsonProperty("englishName") val englishName: String? = null,
+ @JsonProperty("nativeName") val nativeName: String? = null,
+ @JsonProperty("thumbnail") val thumbnail: String? = null,
+ @JsonProperty("airedStart") val airedStart: String? = null,
+ @JsonProperty("availableChapters") val availableChapters: String? = null,
+ @JsonProperty("availableEpisodes") val availableEpisodes: String? = null,
+ @JsonProperty("__typename") val _typename: String? = null
+ )
+
+ override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
+ val items = ArrayList()
+ val urls = listOf(
+// Pair(
+// "Top Anime",
+// """$mainUrl/graphql?variables={"type":"anime","size":30,"dateRange":30}&extensions={"persistedQuery":{"version":1,"sha256Hash":"276d52ba09ca48ce2b8beb3affb26d9d673b22f9d1fd4892aaa39524128bc745"}}"""
+// ),
+ // "countryOrigin":"JP" for Japanese only
+ Pair(
+ "Recently updated",
+ """$mainUrl/graphql?variables={"search":{"allowAdult":false,"allowUnknown":false},"limit":30,"page":1,"translationType":"dub","countryOrigin":"ALL"}&extensions={"persistedQuery":{"version":1,"sha256Hash":"d2670e3e27ee109630991152c8484fce5ff5e280c523378001f9a23dc1839068"}}"""
+ ),
+ )
+
+ val random =
+ """$mainUrl/graphql?variables={"format":"anime"}&extensions={"persistedQuery":{"version":1,"sha256Hash":"21ac672633498a3698e8f6a93ce6c2b3722b29a216dcca93363bf012c360cd54"}}"""
+ val ranlink = app.get(random).text
+ val jsonran = parseJson(ranlink)
+ val ranhome = jsonran.data?.queryRandomRecommendation?.map {
+ newAnimeSearchResponse(it.name!!, "$mainUrl/anime/${it.Id}", fix = false) {
+ this.posterUrl = it.thumbnail
+ this.otherName = it.nativeName
+ }
+ }
+
+ items.add(HomePageList("Random", ranhome!!))
+
+ urls.apmap { (HomeName, url) ->
+ val test = app.get(url).text
+ val json = parseJson(test)
+ val home = ArrayList()
+ val results = json.data.shows.edges.filter {
+ // filtering in case there is an anime with 0 episodes available on the site.
+ !(it.availableEpisodes?.raw == 0 && it.availableEpisodes.sub == 0 && it.availableEpisodes.dub == 0)
+ }
+ results.map {
+ home.add(
+ newAnimeSearchResponse(it.name, "$mainUrl/anime/${it.Id}", fix = false) {
+ this.posterUrl = it.thumbnail
+ this.year = it.airedStart?.year
+ this.otherName = it.englishName
+ addDub(it.availableEpisodes?.dub)
+ addSub(it.availableEpisodes?.sub)
+ })
+ }
+ items.add(HomePageList(HomeName, home))
+ }
+
+ if (items.size <= 0) throw ErrorLoadingException()
+ return HomePageResponse(items)
+ }
+
+ override suspend fun search(query: String): List {
+ val link =
+ """ $mainUrl/graphql?variables={"search":{"allowAdult":false,"allowUnknown":false,"query":"$query"},"limit":26,"page":1,"translationType":"dub","countryOrigin":"ALL"}&extensions={"persistedQuery":{"version":1,"sha256Hash":"d2670e3e27ee109630991152c8484fce5ff5e280c523378001f9a23dc1839068"}}"""
+ var res = app.get(link).text
+ if (res.contains("PERSISTED_QUERY_NOT_FOUND")) {
+ res = app.get(link).text
+ if (res.contains("PERSISTED_QUERY_NOT_FOUND")) return emptyList()
+ }
+ val response = parseJson(res)
+
+ val results = response.data.shows.edges.filter {
+ // filtering in case there is an anime with 0 episodes available on the site.
+ !(it.availableEpisodes?.raw == 0 && it.availableEpisodes.sub == 0 && it.availableEpisodes.dub == 0)
+ }
+
+ return results.map {
+ newAnimeSearchResponse(it.name, "$mainUrl/anime/${it.Id}", fix = false) {
+ this.posterUrl = it.thumbnail
+ this.year = it.airedStart?.year
+ this.otherName = it.englishName
+ addDub(it.availableEpisodes?.dub)
+ addSub(it.availableEpisodes?.sub)
+ }
+ }
+ }
+
+ private data class AvailableEpisodesDetail(
+ @JsonProperty("sub") val sub: List,
+ @JsonProperty("dub") val dub: List,
+ @JsonProperty("raw") val raw: List
+ )
+
+
+ override suspend fun load(url: String): LoadResponse? {
+ val rhino = Context.enter()
+ rhino.initStandardObjects()
+ rhino.optimizationLevel = -1
+ val scope: Scriptable = rhino.initStandardObjects()
+
+ val html = app.get(url).text
+ val soup = Jsoup.parse(html)
+
+ val script = soup.select("script").firstOrNull {
+ it.html().contains("window.__NUXT__")
+ } ?: return null
+
+ val js = """
+ const window = {}
+ ${script.html()}
+ const returnValue = JSON.stringify(window.__NUXT__.fetch[0].show)
+ """.trimIndent()
+
+ rhino.evaluateString(scope, js, "JavaScript", 1, null)
+ val jsEval = scope.get("returnValue", scope) ?: return null
+ val showData = parseJson(jsEval as String)
+
+ val title = showData.name
+ val description = showData.description
+ val poster = showData.thumbnail
+
+ val episodes = showData.availableEpisodes.let {
+ if (it == null) return@let Pair(null, null)
+ Pair(if (it.sub != 0) ((1..it.sub).map { epNum ->
+ Episode(
+ "$mainUrl/anime/${showData.Id}/episodes/sub/$epNum", episode = epNum
+ )
+ }) else null, if (it.dub != 0) ((1..it.dub).map { epNum ->
+ Episode(
+ "$mainUrl/anime/${showData.Id}/episodes/dub/$epNum", episode = epNum
+ )
+ }) else null)
+ }
+
+ val characters = soup.select("div.character > div.card-character-box").mapNotNull {
+ val img = it?.selectFirst("img")?.attr("src") ?: return@mapNotNull null
+ val name = it.selectFirst("div > a")?.ownText() ?: return@mapNotNull null
+ val role = when (it.selectFirst("div > .text-secondary")?.text()?.trim()) {
+ "Main" -> ActorRole.Main
+ "Supporting" -> ActorRole.Supporting
+ "Background" -> ActorRole.Background
+ else -> null
+ }
+ Pair(Actor(name, img), role)
+ }
+
+ // bruh, they use graphql
+ //val recommendations = soup.select("#suggesction > div > div.p > .swipercard")?.mapNotNull {
+ // val recTitle = it?.selectFirst(".showname > a") ?: return@mapNotNull null
+ // val recName = recTitle.text() ?: return@mapNotNull null
+ // val href = fixUrlNull(recTitle.attr("href")) ?: return@mapNotNull null
+ // val img = it.selectFirst(".image > img").attr("src") ?: return@mapNotNull null
+ // AnimeSearchResponse(recName, href, this.name, TvType.Anime, img)
+ //}
+
+ return newAnimeLoadResponse(title, url, TvType.Anime) {
+ posterUrl = poster
+ year = showData.airedStart?.year
+
+ addEpisodes(DubStatus.Subbed, episodes.first)
+ addEpisodes(DubStatus.Dubbed, episodes.second)
+ addActors(characters)
+ //this.recommendations = recommendations
+
+ showStatus = getStatus(showData.status.toString())
+
+ plot = description?.replace(Regex("""<(.*?)>"""), "")
+ }
+ }
+
+ private val embedBlackList = listOf(
+ "https://mp4upload.com/",
+ "https://streamsb.net/",
+ "https://dood.to/",
+ "https://videobin.co/",
+ "https://ok.ru",
+ "https://streamlare.com",
+ )
+
+ private fun embedIsBlacklisted(url: String): Boolean {
+ embedBlackList.forEach {
+ if (it.javaClass.name == "kotlin.text.Regex") {
+ if ((it as Regex).matches(url)) {
+ return true
+ }
+ } else {
+ if (url.contains(it)) {
+ return true
+ }
+ }
+ }
+ return false
+ }
+
+ private fun String.sanitize(): String {
+ var out = this
+ listOf(Pair("\\u002F", "/")).forEach {
+ out = out.replace(it.first, it.second)
+ }
+ return out
+ }
+
+ private data class Links(
+ @JsonProperty("link") val link: String,
+ @JsonProperty("hls") val hls: Boolean?,
+ @JsonProperty("resolutionStr") val resolutionStr: String,
+ @JsonProperty("src") val src: String?
+ )
+
+ private data class AllAnimeVideoApiResponse(
+ @JsonProperty("links") val links: List
+ )
+
+ private data class ApiEndPoint(
+ @JsonProperty("episodeIframeHead") val episodeIframeHead: String
+ )
+
+ private suspend fun getM3u8Qualities(
+ m3u8Link: String,
+ referer: String,
+ qualityName: String,
+ ): List {
+ return M3u8Helper.generateM3u8(
+ this.name,
+ m3u8Link,
+ referer,
+ name = "${this.name} - $qualityName"
+ )
+ }
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+ var apiEndPoint =
+ parseJson(app.get("$mainUrl/getVersion").text).episodeIframeHead
+ if (apiEndPoint.endsWith("/")) apiEndPoint =
+ apiEndPoint.slice(0 until apiEndPoint.length - 1)
+
+ val html = app.get(data).text
+
+ val sources = Regex("""sourceUrl[:=]"(.+?)"""").findAll(html).toList()
+ .map { URLDecoder.decode(it.destructured.component1().sanitize(), "UTF-8") }
+ sources.apmap {
+ safeApiCall {
+ var link = it.replace(" ", "%20")
+ if (URI(link).isAbsolute || link.startsWith("//")) {
+ if (link.startsWith("//")) link = "https:$it"
+
+ if (Regex("""streaming\.php\?""").matches(link)) {
+ // for now ignore
+ } else if (!embedIsBlacklisted(link)) {
+ if (URI(link).path.contains(".m3u")) {
+ getM3u8Qualities(link, data, URI(link).host).forEach(callback)
+ } else {
+ callback(
+ ExtractorLink(
+ "AllAnime - " + URI(link).host,
+ "",
+ link,
+ data,
+ Qualities.P1080.value,
+ false
+ )
+ )
+ }
+ }
+ } else {
+ link = apiEndPoint + URI(link).path + ".json?" + URI(link).query
+ val response = app.get(link)
+
+ if (response.code < 400) {
+ val links = parseJson(response.text).links
+ links.forEach { server ->
+ if (server.hls != null && server.hls) {
+ getM3u8Qualities(
+ server.link,
+ "$apiEndPoint/player?uri=" + (if (URI(server.link).host.isNotEmpty()) server.link else apiEndPoint + URI(
+ server.link
+ ).path),
+ server.resolutionStr
+ ).forEach(callback)
+ } else {
+ callback(
+ ExtractorLink(
+ "AllAnime - " + URI(server.link).host,
+ server.resolutionStr,
+ server.link,
+ "$apiEndPoint/player?uri=" + (if (URI(server.link).host.isNotEmpty()) server.link else apiEndPoint + URI(
+ server.link
+ ).path),
+ Qualities.P1080.value,
+ false
+ )
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+ return true
+ }
+
+}
diff --git a/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProviderPlugin.kt b/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProviderPlugin.kt
new file mode 100644
index 0000000..8b2169a
--- /dev/null
+++ b/AllAnimeProvider/src/main/kotlin/com/lagradost/AllAnimeProviderPlugin.kt
@@ -0,0 +1,14 @@
+
+package com.lagradost
+
+import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
+import com.lagradost.cloudstream3.plugins.Plugin
+import android.content.Context
+
+@CloudstreamPlugin
+class AllAnimeProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(AllAnimeProvider())
+ }
+}
\ No newline at end of file
diff --git a/AniPlayProvider/build.gradle.kts b/AniPlayProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/AniPlayProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // description = "Lorem Ipsum"
+ // authors = listOf("Cloudburst")
+
+ /**
+ * Status int as the following:
+ * 0: Down
+ * 1: Ok
+ * 2: Slow
+ * 3: Beta only
+ * */
+ status = 1 // will be 3 if unspecified
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/AniPlayProvider/src/main/AndroidManifest.xml b/AniPlayProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/AniPlayProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/AniPlayProvider/src/main/kotlin/com/lagradost/AniPlayProvider.kt b/AniPlayProvider/src/main/kotlin/com/lagradost/AniPlayProvider.kt
new file mode 100644
index 0000000..15eb860
--- /dev/null
+++ b/AniPlayProvider/src/main/kotlin/com/lagradost/AniPlayProvider.kt
@@ -0,0 +1,215 @@
+package com.lagradost
+
+import com.fasterxml.jackson.annotation.JsonProperty
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
+import com.lagradost.cloudstream3.LoadResponse.Companion.addDuration
+import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.M3u8Helper
+import com.lagradost.cloudstream3.utils.Qualities
+
+class AniPlayProvider : MainAPI() {
+ override var mainUrl = "https://aniplay.it"
+ override var name = "AniPlay"
+ override var lang = "it"
+ override val hasMainPage = true
+ private val dubIdentifier = " (ITA)"
+
+ override val supportedTypes = setOf(
+ TvType.Anime,
+ TvType.AnimeMovie,
+ TvType.OVA
+ )
+
+ companion object {
+ fun getStatus(t: String?): ShowStatus? {
+ return when (t?.lowercase()) {
+ "completato" -> ShowStatus.Completed
+ "in corso" -> ShowStatus.Ongoing
+ else -> null // "annunciato"
+ }
+ }
+ fun getType(t: String?): TvType {
+ return when (t?.lowercase()) {
+ "ona" -> TvType.OVA
+ "movie" -> TvType.AnimeMovie
+ else -> TvType.Anime //"serie", "special"
+ }
+ }
+ }
+
+ private fun isDub(title: String): Boolean{
+ return title.contains(dubIdentifier)
+ }
+
+ data class ApiPoster(
+ @JsonProperty("imageFull") val posterUrl: String
+ )
+
+ data class ApiMainPageAnime(
+ @JsonProperty("animeId") val id: Int,
+ @JsonProperty("episodeNumber") val episode: String?,
+ @JsonProperty("animeTitle") val title: String,
+ @JsonProperty("animeType") val type: String,
+ @JsonProperty("fullHd") val fullHD: Boolean,
+ @JsonProperty("animeVerticalImages") val posters: List
+ )
+
+ data class ApiSearchResult(
+ @JsonProperty("id") val id: Int,
+ @JsonProperty("title") val title: String,
+ @JsonProperty("status") val status: String,
+ @JsonProperty("type") val type: String,
+ @JsonProperty("verticalImages") val posters: List
+ )
+
+ data class ApiGenres(
+ @JsonProperty("description") val name: String
+ )
+ data class ApiWebsite(
+ @JsonProperty("listWebsiteId") val websiteId: Int,
+ @JsonProperty("url") val url: String
+ )
+
+ data class ApiEpisode(
+ @JsonProperty("id") val id: Int,
+ @JsonProperty("title") val title: String?,
+ @JsonProperty("episodeNumber") val number: String,
+ )
+
+ private fun ApiEpisode.toEpisode() : Episode? {
+ val number = this.number.toIntOrNull() ?: return null
+ return Episode(
+ data = "$mainUrl/api/episode/${this.id}",
+ episode = number,
+ name = this.title
+ )
+ }
+
+ data class ApiSeason(
+ @JsonProperty("id") val id: Int,
+ @JsonProperty("name") val name: String
+ )
+
+ private suspend fun ApiSeason.toEpisodeList(url: String) : List {
+ return app.get("$url/season/${this.id}").parsed>().mapNotNull { it.toEpisode() }
+ }
+
+ data class ApiAnime(
+ @JsonProperty("title") val title: String,
+ @JsonProperty("alternativeTitle") val japTitle: String?,
+ @JsonProperty("episodeDuration") val duration: Int,
+ @JsonProperty("storyline") val plot: String,
+ @JsonProperty("type") val type: String,
+ @JsonProperty("status") val status: String,
+ @JsonProperty("genres") val genres: List,
+ @JsonProperty("verticalImages") val posters: List,
+ @JsonProperty("listWebsites") val websites: List,
+ @JsonProperty("episodes") val episodes: List,
+ @JsonProperty("seasons") val seasons: List?
+ )
+
+ data class ApiEpisodeUrl(
+ @JsonProperty("videoUrl") val url: String
+ )
+
+ override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
+ val response = app.get("$mainUrl/api/home/latest-episodes?page=0").parsed>()
+
+ val results = response.map{
+ val isDub = isDub(it.title)
+ newAnimeSearchResponse(
+ name = if (isDub) it.title.replace(dubIdentifier, "") else it.title,
+ url = "$mainUrl/api/anime/${it.id}",
+ type = getType(it.type),
+ ){
+ addDubStatus(isDub, it.episode?.toIntOrNull())
+ this.posterUrl = it.posters.first().posterUrl
+ this.quality = if (it.fullHD) SearchQuality.HD else null
+ }
+ }
+ return HomePageResponse(listOf(HomePageList("Ultime uscite",results)))
+ }
+
+ override suspend fun search(query: String): List {
+ val response = app.get("$mainUrl/api/anime/advanced-search?page=0&size=36&query=$query").parsed>()
+
+ return response.map {
+ val isDub = isDub(it.title)
+
+ newAnimeSearchResponse(
+ name = if (isDub) it.title.replace(dubIdentifier, "") else it.title,
+ url = "$mainUrl/api/anime/${it.id}",
+ type = getType(it.type),
+ ){
+ addDubStatus(isDub)
+ this.posterUrl = it.posters.first().posterUrl
+ }
+ }
+ }
+
+ override suspend fun load(url: String): LoadResponse {
+
+ val response = app.get(url).parsed()
+
+ val tags: List = response.genres.map { it.name }
+
+ val malId: Int? = response.websites.find { it.websiteId == 1 }?.url?.removePrefix("https://myanimelist.net/anime/")?.split("/")?.first()?.toIntOrNull()
+ val aniListId: Int? = response.websites.find { it.websiteId == 4 }?.url?.removePrefix("https://anilist.co/anime/")?.split("/")?.first()?.toIntOrNull()
+
+ val episodes = if (response.seasons.isNullOrEmpty()) response.episodes.mapNotNull { it.toEpisode() } else response.seasons.map{ it.toEpisodeList(url) }.flatten()
+ val isDub = isDub(response.title)
+
+ return newAnimeLoadResponse(response.title, url, getType(response.type)) {
+ this.name = if (isDub) response.title.replace(dubIdentifier, "") else response.title
+ this.japName = response.japTitle
+ this.plot = response.plot
+ this.tags = tags
+ this.showStatus = getStatus(response.status)
+ addPoster(response.posters.first().posterUrl)
+ addEpisodes(if (isDub) DubStatus.Dubbed else DubStatus.Subbed, episodes)
+ addMalId(malId)
+ addAniListId(aniListId)
+ addDuration(response.duration.toString())
+ }
+ }
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+
+ val episode = app.get(data).parsed()
+
+ if(episode.url.contains(".m3u8")){
+ val m3u8Helper = M3u8Helper()
+ val streams = m3u8Helper.m3u8Generation(M3u8Helper.M3u8Stream(episode.url,Qualities.Unknown.value), false)
+
+ streams.forEach {
+ callback.invoke(
+ ExtractorLink(
+ name,
+ name,
+ it.streamUrl,
+ referer = mainUrl,
+ quality = it.quality ?: Qualities.Unknown.value,
+ isM3u8 = it.streamUrl.contains(".m3u8"))) }
+ return true
+ }
+
+ callback.invoke(
+ ExtractorLink(
+ name,
+ name,
+ episode.url,
+ referer = mainUrl,
+ quality = Qualities.Unknown.value,
+ isM3u8 = false,
+ )
+ )
+ return true
+ }
+}
\ No newline at end of file
diff --git a/AniPlayProvider/src/main/kotlin/com/lagradost/AniPlayProviderPlugin.kt b/AniPlayProvider/src/main/kotlin/com/lagradost/AniPlayProviderPlugin.kt
new file mode 100644
index 0000000..de3dccb
--- /dev/null
+++ b/AniPlayProvider/src/main/kotlin/com/lagradost/AniPlayProviderPlugin.kt
@@ -0,0 +1,14 @@
+
+package com.lagradost
+
+import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
+import com.lagradost.cloudstream3.plugins.Plugin
+import android.content.Context
+
+@CloudstreamPlugin
+class AniPlayProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(AniPlayProvider())
+ }
+}
\ No newline at end of file
diff --git a/AniflixProvider/build.gradle.kts b/AniflixProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/AniflixProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // description = "Lorem Ipsum"
+ // authors = listOf("Cloudburst")
+
+ /**
+ * Status int as the following:
+ * 0: Down
+ * 1: Ok
+ * 2: Slow
+ * 3: Beta only
+ * */
+ status = 1 // will be 3 if unspecified
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/AniflixProvider/src/main/AndroidManifest.xml b/AniflixProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/AniflixProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/AniflixProvider/src/main/kotlin/com/lagradost/AniflixProvider.kt b/AniflixProvider/src/main/kotlin/com/lagradost/AniflixProvider.kt
new file mode 100644
index 0000000..c62d891
--- /dev/null
+++ b/AniflixProvider/src/main/kotlin/com/lagradost/AniflixProvider.kt
@@ -0,0 +1,274 @@
+package com.lagradost
+
+import com.fasterxml.jackson.annotation.JsonProperty
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.getQualityFromName
+import java.net.URLDecoder
+
+class AniflixProvider : MainAPI() {
+ override var mainUrl = "https://aniflix.pro"
+ override var name = "Aniflix"
+ override val hasMainPage = true
+
+ override val supportedTypes = setOf(
+ TvType.AnimeMovie,
+ TvType.OVA,
+ TvType.Anime,
+ )
+
+ companion object {
+ var token: String? = null
+ }
+
+ private suspend fun getToken(): String {
+ return token ?: run {
+ Regex("([^/]*)/_buildManifest\\.js").find(app.get(mainUrl).text)?.groupValues?.getOrNull(
+ 1
+ )
+ ?.also {
+ token = it
+ }
+ ?: throw ErrorLoadingException("No token found")
+ }
+ }
+
+ private fun Anime.toSearchResponse(): SearchResponse? {
+ return newAnimeSearchResponse(
+ title?.english ?: title?.romaji ?: return null,
+ "$mainUrl/anime/${id ?: return null}"
+ ) {
+ posterUrl = coverImage?.large ?: coverImage?.medium
+ }
+ }
+
+
+ override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
+ val items = ArrayList()
+ val soup = app.get(mainUrl).document
+ val elements = listOf(
+ Pair("Trending Now", "div:nth-child(3) > div a"),
+ Pair("Popular", "div:nth-child(4) > div a"),
+ Pair("Top Rated", "div:nth-child(5) > div a"),
+ )
+
+ elements.map { (name, element) ->
+ val home = soup.select(element).map {
+ val href = it.attr("href")
+ val title = it.selectFirst("p.mt-2")!!.text()
+ val image = it.selectFirst("img.rounded-md[sizes]")!!.attr("src").replace("/_next/image?url=","")
+ .replace(Regex("\\&.*\$"),"")
+ val realposter = URLDecoder.decode(image, "UTF-8")
+ newAnimeSearchResponse(title, fixUrl(href)) {
+ this.posterUrl = realposter
+ }
+ }
+ items.add(HomePageList(name, home))
+ }
+
+ return HomePageResponse(items)
+ }
+
+ override suspend fun search(query: String): List? {
+ val token = getToken()
+ val url = "$mainUrl/_next/data/$token/search.json?keyword=$query"
+ val response = app.get(url)
+ val searchResponse =
+ response.parsedSafe()
+ ?: throw ErrorLoadingException("No Media")
+ return searchResponse.pageProps?.searchResults?.Page?.media?.mapNotNull { media ->
+ media.toSearchResponse()
+ }
+ }
+
+ override suspend fun load(url: String): LoadResponse {
+ val token = getToken()
+
+ val id = Regex("$mainUrl/anime/([0-9]*)").find(url)?.groupValues?.getOrNull(1)
+ ?: throw ErrorLoadingException("Error parsing link for id")
+
+ val res = app.get("https://aniflix.pro/_next/data/$token/anime/$id.json?id=$id")
+ .parsedSafe()?.pageProps
+ ?: throw ErrorLoadingException("Invalid Json reponse")
+ val isMovie = res.anime.format == "MOVIE"
+ return newAnimeLoadResponse(
+ res.anime.title?.english ?: res.anime.title?.romaji
+ ?: throw ErrorLoadingException("Invalid title reponse"),
+ url, if (isMovie) TvType.AnimeMovie else TvType.Anime
+ ) {
+ recommendations = res.recommended.mapNotNull { it.toSearchResponse() }
+ tags = res.anime.genres
+ posterUrl = res.anime.coverImage?.large ?: res.anime.coverImage?.medium
+ plot = res.anime.description
+ showStatus = when (res.anime.status) {
+ "FINISHED" -> ShowStatus.Completed
+ "RELEASING" -> ShowStatus.Ongoing
+ else -> null
+ }
+ addAniListId(id.toIntOrNull())
+
+ // subbed because they are both subbed and dubbed
+ if (isMovie)
+ addEpisodes(
+ DubStatus.Subbed,
+ listOf(newEpisode("$mainUrl/api/anime/?id=$id&episode=1"))
+ )
+ else
+ addEpisodes(DubStatus.Subbed, res.episodes.episodes?.nodes?.mapIndexed { index, node ->
+ val episodeIndex = node?.number ?: (index + 1)
+ //"$mainUrl/_next/data/$token/watch/$id.json?episode=${node.number ?: return@mapNotNull null}&id=$id"
+ newEpisode("$mainUrl/api/anime?id=$id&episode=${episodeIndex}") {
+ episode = episodeIndex
+ posterUrl = node?.thumbnail?.original?.url
+ name = node?.titles?.canonical
+ }
+ })
+ }
+ }
+
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+ return app.get(data).parsed().let { res ->
+ val dubReferer = res.dub?.Referer ?: ""
+ res.dub?.sources?.forEach { source ->
+ callback(
+ ExtractorLink(
+ name,
+ "${source.label ?: name} (DUB)",
+ source.file ?: return@forEach,
+ dubReferer,
+ getQualityFromName(source.label),
+ source.type == "hls"
+ )
+ )
+ }
+
+ val subReferer = res.dub?.Referer ?: ""
+ res.sub?.sources?.forEach { source ->
+ callback(
+ ExtractorLink(
+ name,
+ "${source.label ?: name} (SUB)",
+ source.file ?: return@forEach,
+ subReferer,
+ getQualityFromName(source.label),
+ source.type == "hls"
+ )
+ )
+ }
+
+ !res.dub?.sources.isNullOrEmpty() && !res.sub?.sources.isNullOrEmpty()
+ }
+ }
+
+ data class AniLoadResponse(
+ @JsonProperty("sub") val sub: DubSubSource?,
+ @JsonProperty("dub") val dub: DubSubSource?,
+ @JsonProperty("episodes") val episodes: Int?
+ )
+
+ data class Sources(
+ @JsonProperty("file") val file: String?,
+ @JsonProperty("label") val label: String?,
+ @JsonProperty("type") val type: String?
+ )
+
+ data class DubSubSource(
+ @JsonProperty("Referer") var Referer: String?,
+ @JsonProperty("sources") var sources: ArrayList = arrayListOf()
+ )
+
+ data class PageProps(
+ @JsonProperty("searchResults") val searchResults: SearchResults?
+ )
+
+ data class SearchResults(
+ @JsonProperty("Page") val Page: Page?
+ )
+
+ data class Page(
+ @JsonProperty("media") val media: ArrayList = arrayListOf()
+ )
+
+ data class CoverImage(
+ @JsonProperty("color") val color: String?,
+ @JsonProperty("medium") val medium: String?,
+ @JsonProperty("large") val large: String?,
+ )
+
+ data class Title(
+ @JsonProperty("english") val english: String?,
+ @JsonProperty("romaji") val romaji: String?,
+ )
+
+ data class Search(
+ @JsonProperty("pageProps") val pageProps: PageProps?,
+ @JsonProperty("__N_SSP") val _NSSP: Boolean?
+ )
+
+ data class Anime(
+ @JsonProperty("status") val status: String?,
+ @JsonProperty("id") val id: Int?,
+ @JsonProperty("title") val title: Title?,
+ @JsonProperty("coverImage") val coverImage: CoverImage?,
+ @JsonProperty("format") val format: String?,
+ @JsonProperty("duration") val duration: Int?,
+ @JsonProperty("meanScore") val meanScore: Int?,
+ @JsonProperty("nextAiringEpisode") val nextAiringEpisode: String?,
+ @JsonProperty("bannerImage") val bannerImage: String?,
+ @JsonProperty("description") val description: String?,
+ @JsonProperty("genres") val genres: ArrayList? = null,
+ @JsonProperty("season") val season: String?,
+ @JsonProperty("startDate") val startDate: StartDate?,
+ )
+
+ data class StartDate(
+ @JsonProperty("year") val year: Int?
+ )
+
+ data class AnimeResponsePage(
+ @JsonProperty("pageProps") val pageProps: AnimeResponse?,
+ )
+
+ data class AnimeResponse(
+ @JsonProperty("anime") val anime: Anime,
+ @JsonProperty("recommended") val recommended: ArrayList,
+ @JsonProperty("episodes") val episodes: EpisodesParent,
+ )
+
+ data class EpisodesParent(
+ @JsonProperty("id") val id: String?,
+ @JsonProperty("season") val season: String?,
+ @JsonProperty("startDate") val startDate: String?,
+ @JsonProperty("episodeCount") val episodeCount: Int?,
+ @JsonProperty("episodes") val episodes: Episodes?,
+ )
+
+ data class Episodes(
+ @JsonProperty("nodes") val nodes: ArrayList = arrayListOf()
+ )
+
+ data class Nodes(
+ @JsonProperty("number") val number: Int? = null,
+ @JsonProperty("titles") val titles: Titles?,
+ @JsonProperty("thumbnail") val thumbnail: Thumbnail?,
+ )
+
+ data class Titles(
+ @JsonProperty("canonical") val canonical: String?,
+ )
+
+ data class Original(
+ @JsonProperty("url") val url: String?,
+ )
+
+ data class Thumbnail(
+ @JsonProperty("original") val original: Original?,
+ )
+}
\ No newline at end of file
diff --git a/AniflixProvider/src/main/kotlin/com/lagradost/AniflixProviderPlugin.kt b/AniflixProvider/src/main/kotlin/com/lagradost/AniflixProviderPlugin.kt
new file mode 100644
index 0000000..54d3391
--- /dev/null
+++ b/AniflixProvider/src/main/kotlin/com/lagradost/AniflixProviderPlugin.kt
@@ -0,0 +1,14 @@
+
+package com.lagradost
+
+import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
+import com.lagradost.cloudstream3.plugins.Plugin
+import android.content.Context
+
+@CloudstreamPlugin
+class AniflixProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(AniflixProvider())
+ }
+}
\ No newline at end of file
diff --git a/AnimeFlickProvider/build.gradle.kts b/AnimeFlickProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/AnimeFlickProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // description = "Lorem Ipsum"
+ // authors = listOf("Cloudburst")
+
+ /**
+ * Status int as the following:
+ * 0: Down
+ * 1: Ok
+ * 2: Slow
+ * 3: Beta only
+ * */
+ status = 1 // will be 3 if unspecified
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/AnimeFlickProvider/src/main/AndroidManifest.xml b/AnimeFlickProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/AnimeFlickProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/AnimeFlickProvider/src/main/kotlin/com/lagradost/AnimeFlickProvider.kt b/AnimeFlickProvider/src/main/kotlin/com/lagradost/AnimeFlickProvider.kt
new file mode 100644
index 0000000..4c76bfa
--- /dev/null
+++ b/AnimeFlickProvider/src/main/kotlin/com/lagradost/AnimeFlickProvider.kt
@@ -0,0 +1,119 @@
+package com.lagradost
+
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.Qualities
+import com.lagradost.cloudstream3.utils.extractorApis
+import org.jsoup.Jsoup
+import java.util.*
+
+class AnimeFlickProvider : MainAPI() {
+ companion object {
+ fun getType(t: String): TvType {
+ return if (t.contains("OVA") || t.contains("Special")) TvType.OVA
+ else if (t.contains("Movie")) TvType.AnimeMovie
+ else TvType.Anime
+ }
+ }
+
+ override var mainUrl = "https://animeflick.net"
+ override var name = "AnimeFlick"
+ override val hasQuickSearch = false
+ override val hasMainPage = false
+
+ override val supportedTypes = setOf(
+ TvType.AnimeMovie,
+ TvType.Anime,
+ TvType.OVA
+ )
+
+ override suspend fun search(query: String): List {
+ val link = "https://animeflick.net/search.php?search=$query"
+ val html = app.get(link).text
+ val doc = Jsoup.parse(html)
+
+ return doc.select(".row.mt-2").mapNotNull {
+ val href = mainUrl + it.selectFirst("a")?.attr("href")
+ val title = it.selectFirst("h5 > a")?.text() ?: return@mapNotNull null
+ val poster = mainUrl + it.selectFirst("img")?.attr("src")?.replace("70x110", "225x320")
+ AnimeSearchResponse(
+ title,
+ href,
+ this.name,
+ getType(title),
+ poster,
+ null,
+ EnumSet.of(DubStatus.Subbed),
+ )
+ }
+ }
+
+ override suspend fun load(url: String): LoadResponse {
+ val html = app.get(url).text
+ val doc = Jsoup.parse(html)
+
+ val poster = mainUrl + doc.selectFirst("img.rounded")?.attr("src")
+ val title = doc.selectFirst("h2.title")!!.text()
+
+ val yearText = doc.selectFirst(".trending-year")?.text()
+ val year =
+ if (yearText != null) Regex("""(\d{4})""").find(yearText)?.destructured?.component1()
+ ?.toIntOrNull() else null
+ val description = doc.selectFirst("p")?.text()
+
+ val genres = doc.select("a[href*=\"genre-\"]").map { it.text() }
+
+ val episodes = doc.select("#collapseOne .block-space > .row > div:nth-child(2)").map {
+ val name = it.selectFirst("a")?.text()
+ val link = mainUrl + it.selectFirst("a")?.attr("href")
+ Episode(link, name)
+ }.reversed()
+
+ return newAnimeLoadResponse(title, url, getType(title)) {
+ posterUrl = poster
+ this.year = year
+
+ addEpisodes(DubStatus.Subbed, episodes)
+
+ plot = description
+ tags = genres
+ }
+ }
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+ val html = app.get(data).text
+
+ val episodeRegex = Regex("""(https://.*?\.mp4)""")
+ val links = episodeRegex.findAll(html).map {
+ it.value
+ }.toList()
+ for (link in links) {
+ var alreadyAdded = false
+ for (extractor in extractorApis) {
+ if (link.startsWith(extractor.mainUrl)) {
+ extractor.getSafeUrl(link, data, subtitleCallback, callback)
+ alreadyAdded = true
+ break
+ }
+ }
+ if (!alreadyAdded) {
+ callback(
+ ExtractorLink(
+ this.name,
+ "${this.name} - Auto",
+ link,
+ "",
+ Qualities.P1080.value
+ )
+ )
+ }
+ }
+
+ return true
+ }
+}
diff --git a/AnimeFlickProvider/src/main/kotlin/com/lagradost/AnimeFlickProviderPlugin.kt b/AnimeFlickProvider/src/main/kotlin/com/lagradost/AnimeFlickProviderPlugin.kt
new file mode 100644
index 0000000..0e9d53c
--- /dev/null
+++ b/AnimeFlickProvider/src/main/kotlin/com/lagradost/AnimeFlickProviderPlugin.kt
@@ -0,0 +1,14 @@
+
+package com.lagradost
+
+import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
+import com.lagradost.cloudstream3.plugins.Plugin
+import android.content.Context
+
+@CloudstreamPlugin
+class AnimeFlickProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(AnimeFlickProvider())
+ }
+}
\ No newline at end of file
diff --git a/AnimeIndoProvider/build.gradle.kts b/AnimeIndoProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/AnimeIndoProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // description = "Lorem Ipsum"
+ // authors = listOf("Cloudburst")
+
+ /**
+ * Status int as the following:
+ * 0: Down
+ * 1: Ok
+ * 2: Slow
+ * 3: Beta only
+ * */
+ status = 1 // will be 3 if unspecified
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/AnimeIndoProvider/src/main/AndroidManifest.xml b/AnimeIndoProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/AnimeIndoProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/AnimeIndoProvider/src/main/kotlin/com/lagradost/AnimeIndoProvider.kt b/AnimeIndoProvider/src/main/kotlin/com/lagradost/AnimeIndoProvider.kt
new file mode 100644
index 0000000..fb132b7
--- /dev/null
+++ b/AnimeIndoProvider/src/main/kotlin/com/lagradost/AnimeIndoProvider.kt
@@ -0,0 +1,192 @@
+package com.lagradost
+
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
+import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.loadExtractor
+import com.lagradost.nicehttp.NiceResponse
+import org.jsoup.Jsoup
+import org.jsoup.nodes.Element
+
+class AnimeIndoProvider : MainAPI() {
+ override var mainUrl = "https://animeindo.sbs"
+ override var name = "AnimeIndo"
+ override val hasMainPage = true
+ override var lang = "id"
+ override val hasDownloadSupport = true
+
+ override val supportedTypes = setOf(
+ TvType.Anime,
+ TvType.AnimeMovie,
+ TvType.OVA
+ )
+
+ companion object {
+ fun getType(t: String): TvType {
+ return if (t.contains("OVA") || t.contains("Special")) TvType.OVA
+ else if (t.contains("Movie")) TvType.AnimeMovie
+ else TvType.Anime
+ }
+
+ fun getStatus(t: String): ShowStatus {
+ return when (t) {
+ "Finished Airing" -> ShowStatus.Completed
+ "Currently Airing" -> ShowStatus.Ongoing
+ else -> ShowStatus.Completed
+ }
+ }
+
+ private suspend fun request(url: String): NiceResponse {
+ val req = app.get(
+ url,
+ cookies = mapOf("recaptcha_cookie" to "#Asia/Jakarta#-420#win32#Windows#0,false,false#Google Inc. (Intel)~ANGLE (Intel, Intel(R) HD Graphics 400 Direct3D11 vs_5_0 ps_5_0)")
+ )
+ if (req.isSuccessful) {
+ return req
+ } else {
+ val document = app.get(url).document
+ val captchaKey =
+ document.select("script[src*=https://www.google.com/recaptcha/api.js?render=]")
+ .attr("src").substringAfter("render=").substringBefore("&")
+ val token = getCaptchaToken(url, captchaKey)
+ return app.post(
+ url,
+ data = mapOf(
+ "action" to "recaptcha_for_all",
+ "token" to "$token",
+ "sitekey" to captchaKey
+ )
+ )
+ }
+ }
+ }
+
+ override val mainPage = mainPageOf(
+ "$mainUrl/anime-terbaru/page/" to "Anime Terbaru",
+ "$mainUrl/donghua-terbaru/page/" to "Donghua Terbaru"
+ )
+
+ override suspend fun getMainPage(
+ page: Int,
+ request: MainPageRequest
+ ): HomePageResponse {
+ val document = request(request.data + page).document
+ val home = document.select("div.post-show > article").mapNotNull {
+ it.toSearchResult()
+ }
+ return newHomePageResponse(request.name, home)
+ }
+
+ private fun getProperAnimeLink(uri: String): String {
+ return if (uri.contains("/anime/")) {
+ uri
+ } else {
+ var title = uri.substringAfter("$mainUrl/")
+ title = when {
+ (title.contains("-episode")) && !(title.contains("-movie")) -> Regex("(.+)-episode").find(
+ title
+ )?.groupValues?.get(1).toString()
+ (title.contains("-movie")) -> Regex("(.+)-movie").find(title)?.groupValues?.get(
+ 1
+ ).toString()
+ else -> title
+ }
+ "$mainUrl/anime/$title"
+ }
+ }
+
+ private fun Element.toSearchResult(): AnimeSearchResponse? {
+ val title = this.selectFirst("div.title")?.text()?.trim() ?: return null
+ val href = getProperAnimeLink(this.selectFirst("a")!!.attr("href"))
+ val posterUrl = this.select("img[itemprop=image]").attr("src").toString()
+ val type = getType(this.select("div.type").text().trim())
+ val epNum =
+ this.selectFirst("span.episode")?.ownText()?.replace(Regex("[^0-9]"), "")?.trim()
+ ?.toIntOrNull()
+ return newAnimeSearchResponse(title, href, type) {
+ this.posterUrl = posterUrl
+ addSub(epNum)
+ }
+
+ }
+
+ override suspend fun search(query: String): List {
+ val link = "$mainUrl/?s=$query"
+ val document = request(link).document
+
+ return document.select(".site-main.relat > article").map {
+ val title = it.selectFirst("div.title > h2")!!.ownText().trim()
+ val href = it.selectFirst("a")!!.attr("href")
+ val posterUrl = it.selectFirst("img")!!.attr("src").toString()
+ val type = getType(it.select("div.type").text().trim())
+ newAnimeSearchResponse(title, href, type) {
+ this.posterUrl = posterUrl
+ }
+ }
+ }
+
+ override suspend fun load(url: String): LoadResponse {
+ val document = request(url).document
+
+ val title = document.selectFirst("h1.entry-title")?.text().toString().trim()
+ val poster = document.selectFirst("div.thumb > img[itemprop=image]")?.attr("src")
+ val tags = document.select("div.genxed > a").map { it.text() }
+ val type = getType(
+ document.selectFirst("div.info-content > div.spe > span:nth-child(6)")?.ownText()
+ .toString()
+ )
+ val year = Regex("\\d, ([0-9]*)").find(
+ document.select("div.info-content > div.spe > span:nth-child(9) > time").text()
+ )?.groupValues?.get(1)?.toIntOrNull()
+ val status = getStatus(
+ document.selectFirst("div.info-content > div.spe > span:nth-child(1)")!!.ownText()
+ .trim()
+ )
+ val description = document.select("div[itemprop=description] > p").text()
+ val trailer = document.selectFirst("div.player-embed iframe")?.attr("src")
+ val episodes = document.select("div.lstepsiode.listeps ul li").mapNotNull {
+ val header = it.selectFirst("span.lchx > a") ?: return@mapNotNull null
+ val name = header.text().trim()
+ val episode = header.text().trim().replace("Episode", "").trim().toIntOrNull()
+ val link = fixUrl(header.attr("href"))
+ Episode(link, name = name, episode = episode)
+ }.reversed()
+
+ return newAnimeLoadResponse(title, url, type) {
+ engName = title
+ posterUrl = poster
+ this.year = year
+ addEpisodes(DubStatus.Subbed, episodes)
+ showStatus = status
+ plot = description
+ this.tags = tags
+ addTrailer(trailer)
+ }
+ }
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+
+ val document = request(data).document
+ document.select("div.itemleft > .mirror > option").mapNotNull {
+ fixUrl(Jsoup.parse(base64Decode(it.attr("value"))).select("iframe").attr("src"))
+ }.apmap {
+ if (it.startsWith("https://uservideo.xyz")) {
+ app.get(it, referer = "$mainUrl/").document.select("iframe").attr("src")
+ } else {
+ it
+ }
+ }.apmap {
+ loadExtractor(it, data, subtitleCallback, callback)
+ }
+
+ return true
+ }
+
+
+}
\ No newline at end of file
diff --git a/AnimeIndoProvider/src/main/kotlin/com/lagradost/AnimeIndoProviderPlugin.kt b/AnimeIndoProvider/src/main/kotlin/com/lagradost/AnimeIndoProviderPlugin.kt
new file mode 100644
index 0000000..d1dab81
--- /dev/null
+++ b/AnimeIndoProvider/src/main/kotlin/com/lagradost/AnimeIndoProviderPlugin.kt
@@ -0,0 +1,14 @@
+
+package com.lagradost
+
+import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
+import com.lagradost.cloudstream3.plugins.Plugin
+import android.content.Context
+
+@CloudstreamPlugin
+class AnimeIndoProviderPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(AnimeIndoProvider())
+ }
+}
\ No newline at end of file
diff --git a/AnimePaheProvider/build.gradle.kts b/AnimePaheProvider/build.gradle.kts
new file mode 100644
index 0000000..e7d2158
--- /dev/null
+++ b/AnimePaheProvider/build.gradle.kts
@@ -0,0 +1,22 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ // All of these properties are optional, you can safely remove them
+
+ // description = "Lorem Ipsum"
+ // authors = listOf("Cloudburst")
+
+ /**
+ * Status int as the following:
+ * 0: Down
+ * 1: Ok
+ * 2: Slow
+ * 3: Beta only
+ * */
+ status = 1 // will be 3 if unspecified
+
+ // Set to true to get an 18+ symbol next to the plugin
+ adult = false // will be false if unspecified
+}
\ No newline at end of file
diff --git a/AnimePaheProvider/src/main/AndroidManifest.xml b/AnimePaheProvider/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..29aec9d
--- /dev/null
+++ b/AnimePaheProvider/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/AnimePaheProvider/src/main/kotlin/com/lagradost/AnimePaheProvider.kt b/AnimePaheProvider/src/main/kotlin/com/lagradost/AnimePaheProvider.kt
new file mode 100644
index 0000000..56c0e4a
--- /dev/null
+++ b/AnimePaheProvider/src/main/kotlin/com/lagradost/AnimePaheProvider.kt
@@ -0,0 +1,562 @@
+package com.lagradost
+
+import com.fasterxml.jackson.annotation.JsonProperty
+import com.fasterxml.jackson.module.kotlin.readValue
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId
+import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId
+import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
+import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
+import com.lagradost.cloudstream3.utils.AppUtils.parseJson
+import com.lagradost.cloudstream3.utils.ExtractorLink
+import com.lagradost.cloudstream3.utils.JsUnpacker
+import com.lagradost.cloudstream3.utils.getQualityFromName
+import com.lagradost.nicehttp.NiceResponse
+import org.jsoup.Jsoup
+import kotlin.math.pow
+
+class AnimePaheProvider : MainAPI() {
+ // credit to https://github.com/justfoolingaround/animdl/tree/master/animdl/core/codebase/providers/animepahe
+ companion object {
+ const val MAIN_URL = "https://animepahe.com"
+
+ var cookies: Map = mapOf()
+ private fun getType(t: String): TvType {
+ return if (t.contains("OVA") || t.contains("Special")) TvType.OVA
+ else if (t.contains("Movie")) TvType.AnimeMovie
+ else TvType.Anime
+ }
+
+ suspend fun generateSession(): Boolean {
+ if (cookies.isNotEmpty()) return true
+ return try {
+ val response = app.get("$MAIN_URL/")
+ cookies = response.cookies
+ true
+ } catch (e: Exception) {
+ false
+ }
+ }
+
+ val YTSM = Regex("ysmm = '([^']+)")
+
+ val KWIK_PARAMS_RE = Regex("""\("(\w+)",\d+,"(\w+)",(\d+),(\d+),\d+\)""")
+ val KWIK_D_URL = Regex("action=\"([^\"]+)\"")
+ val KWIK_D_TOKEN = Regex("value=\"([^\"]+)\"")
+ val YOUTUBE_VIDEO_LINK =
+ Regex("""(^(?:https?:)?(?://)?(?:www\.)?(?:youtu\.be/|youtube(?:-nocookie)?\.(?:[A-Za-z]{2,4}|[A-Za-z]{2,3}\.[A-Za-z]{2})/)(?:watch|embed/|vi?/)*(?:\?[\w=&]*vi?=)?[^#&?/]{11}.*${'$'})""")
+ }
+
+ override var mainUrl = MAIN_URL
+ override var name = "AnimePahe"
+ override val hasQuickSearch = false
+ override val hasMainPage = true
+
+ override val supportedTypes = setOf(
+ TvType.AnimeMovie,
+ TvType.Anime,
+ TvType.OVA
+ )
+
+ override suspend fun getMainPage(page: Int, request : MainPageRequest): HomePageResponse {
+ data class Data(
+ @JsonProperty("id") val id: Int,
+ @JsonProperty("anime_id") val animeId: Int,
+ @JsonProperty("anime_title") val animeTitle: String,
+ @JsonProperty("anime_slug") val animeSlug: String,
+ @JsonProperty("episode") val episode: Int,
+ @JsonProperty("snapshot") val snapshot: String,
+ @JsonProperty("created_at") val createdAt: String,
+ @JsonProperty("anime_session") val animeSession: String,
+ )
+
+ data class AnimePaheLatestReleases(
+ @JsonProperty("total") val total: Int,
+ @JsonProperty("data") val data: List
+ )
+
+ val urls = listOf(
+ Pair("$mainUrl/api?m=airing&page=1", "Latest Releases"),
+ )
+
+ val items = ArrayList()
+ for (i in urls) {
+ try {
+ val response = app.get(i.first).text
+ val episodes = parseJson(response).data.map {
+ newAnimeSearchResponse(
+ it.animeTitle,
+ "https://pahe.win/a/${it.animeId}?slug=${it.animeTitle}",
+ fix = false
+ ) {
+ this.posterUrl = it.snapshot
+ addDubStatus(DubStatus.Subbed, it.episode)
+ }
+ }
+
+ items.add(HomePageList(i.second, episodes))
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ if (items.size <= 0) throw ErrorLoadingException()
+ return HomePageResponse(items)
+ }
+
+ data class AnimePaheSearchData(
+ @JsonProperty("id") val id: Int,
+ @JsonProperty("slug") val slug: String,
+ @JsonProperty("title") val title: String,
+ @JsonProperty("type") val type: String,
+ @JsonProperty("episodes") val episodes: Int,
+ @JsonProperty("status") val status: String,
+ @JsonProperty("season") val season: String,
+ @JsonProperty("year") val year: Int,
+ @JsonProperty("score") val score: Double,
+ @JsonProperty("poster") val poster: String,
+ @JsonProperty("session") val session: String,
+ @JsonProperty("relevance") val relevance: String
+ )
+
+ data class AnimePaheSearch(
+ @JsonProperty("total") val total: Int,
+ @JsonProperty("data") val data: List
+ )
+
+ private suspend fun getAnimeByIdAndTitle(title: String, animeId: Int): String? {
+ val url = "$mainUrl/api?m=search&l=8&q=$title"
+ val headers = mapOf("referer" to "$mainUrl/")
+
+ val req = app.get(url, headers = headers).text
+ val data = parseJson(req)
+ for (anime in data.data) {
+ if (anime.id == animeId) {
+ return "https://animepahe.com/anime/${anime.session}"
+ }
+ }
+ return null
+ }
+
+
+ override suspend fun search(query: String): List {
+ val url = "$mainUrl/api?m=search&l=8&q=$query"
+ val headers = mapOf("referer" to "$mainUrl/")
+
+ val req = app.get(url, headers = headers).text
+ val data = parseJson(req)
+
+ return data.data.map {
+ newAnimeSearchResponse(
+ it.title,
+ "https://pahe.win/a/${it.id}?slug=${it.title}",
+ fix = false
+ ) {
+ this.posterUrl = it.poster
+ addDubStatus(DubStatus.Subbed, it.episodes)
+ }
+ }
+ }
+
+ private data class AnimeData(
+ @JsonProperty("id") val id: Int,
+ @JsonProperty("anime_id") val animeId: Int,
+ @JsonProperty("episode") val episode: Int,
+ @JsonProperty("title") val title: String,
+ @JsonProperty("snapshot") val snapshot: String,
+ @JsonProperty("session") val session: String,
+ @JsonProperty("filler") val filler: Int,
+ @JsonProperty("created_at") val createdAt: String
+ )
+
+ private data class AnimePaheAnimeData(
+ @JsonProperty("total") val total: Int,
+ @JsonProperty("per_page") val perPage: Int,
+ @JsonProperty("current_page") val currentPage: Int,
+ @JsonProperty("last_page") val lastPage: Int,
+ @JsonProperty("next_page_url") val nextPageUrl: String?,
+ @JsonProperty("prev_page_url") val prevPageUrl: String?,
+ @JsonProperty("from") val from: Int,
+ @JsonProperty("to") val to: Int,
+ @JsonProperty("data") val data: List
+ )
+
+ private suspend fun generateListOfEpisodes(link: String): ArrayList {
+ try {
+ val attrs = link.split('/')
+ val id = attrs[attrs.size - 1].split("?")[0]
+
+ val uri = "$mainUrl/api?m=release&id=$id&sort=episode_asc&page=1"
+ val headers = mapOf("referer" to "$mainUrl/")
+
+ val req = app.get(uri, headers = headers).text
+ val data = parseJson(req)
+
+ val lastPage = data.lastPage
+ val perPage = data.perPage
+ val total = data.total
+ var ep = 1
+ val episodes = ArrayList()
+
+ fun getEpisodeTitle(k: AnimeData): String {
+ return k.title.ifEmpty {
+ "Episode ${k.episode}"
+ }
+ }
+
+ if (lastPage == 1 && perPage > total) {
+ data.data.forEach {
+ episodes.add(
+ newEpisode("$mainUrl/api?m=links&id=${it.animeId}&session=${it.session}&p=kwik!!TRUE!!") {
+ addDate(it.createdAt)
+ this.name = getEpisodeTitle(it)
+ this.posterUrl = it.snapshot
+ }
+ )
+ }
+ } else {
+ for (page in 0 until lastPage) {
+ for (i in 0 until perPage) {
+ if (ep <= total) {
+ episodes.add(
+ Episode(
+ "$mainUrl/api?m=release&id=${id}&sort=episode_asc&page=${page + 1}&ep=${ep}!!FALSE!!"
+ )
+ )
+ ++ep
+ }
+ }
+ }
+ }
+ return episodes
+ } catch (e: Exception) {
+ return ArrayList()
+ }
+ }
+
+ override suspend fun load(url: String): LoadResponse? {
+ return suspendSafeApiCall {
+ val regex = Regex("""a/(\d+)\?slug=(.+)""")
+ val (animeId, animeTitle) = regex.find(url)!!.destructured
+ val link = getAnimeByIdAndTitle(animeTitle, animeId.toInt())!!
+
+ val html = app.get(link).text
+ val doc = Jsoup.parse(html)
+
+ val japTitle = doc.selectFirst("h2.japanese")?.text()
+ val poster = doc.selectFirst(".anime-poster a")?.attr("href")
+
+ val tvType = doc.selectFirst("""a[href*="/anime/type/"]""")?.text()
+
+ val trailer: String? = if (html.contains("https://www.youtube.com/watch")) {
+ YOUTUBE_VIDEO_LINK.find(html)?.destructured?.component1()
+ } else {
+ null
+ }
+
+ val episodes = generateListOfEpisodes(url)
+ val year = Regex("""Aired:[^,]*, (\d+)""")
+ .find(html)!!.destructured.component1()
+ .toIntOrNull()
+ val status =
+ when (Regex("""Status:[^a]*a href=["']/anime/(.*?)["']""")
+ .find(html)!!.destructured.component1()) {
+ "airing" -> ShowStatus.Ongoing
+ "completed" -> ShowStatus.Completed
+ else -> null
+ }
+ val synopsis = doc.selectFirst(".anime-synopsis")?.text()
+
+ var anilistId: Int? = null
+ var malId: Int? = null
+
+ doc.select(".external-links > a").forEach { aTag ->
+ val split = aTag.attr("href").split("/")
+
+ if (aTag.attr("href").contains("anilist.co")) {
+ anilistId = split[split.size - 1].toIntOrNull()
+ } else if (aTag.attr("href").contains("myanimelist.net")) {
+ malId = split[split.size - 1].toIntOrNull()
+ }
+ }
+
+ newAnimeLoadResponse(animeTitle, url, getType(tvType.toString())) {
+ engName = animeTitle
+ japName = japTitle
+
+ this.posterUrl = poster
+ this.year = year
+
+ addEpisodes(DubStatus.Subbed, episodes)
+ this.showStatus = status
+ plot = synopsis
+ tags = if (!doc.select(".anime-genre > ul a").isEmpty()) {
+ ArrayList(doc.select(".anime-genre > ul a").map { it.text().toString() })
+ } else {
+ null
+ }
+
+ addMalId(malId)
+ addAniListId(anilistId)
+ addTrailer(trailer)
+ }
+ }
+ }
+
+
+ private fun isNumber(s: String?): Boolean {
+ return s?.toIntOrNull() != null
+ }
+
+ private fun cookieStrToMap(cookie: String): Map {
+ val cookies = mutableMapOf()
+ for (string in cookie.split("; ")) {
+ val split = string.split("=").toMutableList()
+ val name = split.removeFirst().trim()
+ val value = if (split.size == 0) {
+ "true"
+ } else {
+ split.joinToString("=")
+ }
+ cookies[name] = value
+ }
+ return cookies.toMap()
+ }
+
+ private fun getString(content: String, s1: Int, s2: Int): String {
+ val characterMap = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/"
+
+ val slice2 = characterMap.slice(0 until s2)
+ var acc: Long = 0
+
+ for ((n, i) in content.reversed().withIndex()) {
+ acc += (when (isNumber("$i")) {
+ true -> "$i".toLong()
+ false -> "0".toLong()
+ }) * s1.toDouble().pow(n.toDouble()).toInt()
+ }
+
+ var k = ""
+
+ while (acc > 0) {
+ k = slice2[(acc % s2).toInt()] + k
+ acc = (acc - (acc % s2)) / s2
+ }
+
+ return when (k != "") {
+ true -> k
+ false -> "0"
+ }
+ }
+
+ private fun decrypt(fullString: String, key: String, v1: Int, v2: Int): String {
+ var r = ""
+ var i = 0
+
+ while (i < fullString.length) {
+ var s = ""
+
+ while (fullString[i] != key[v2]) {
+ s += fullString[i]
+ ++i
+ }
+ var j = 0
+
+ while (j < key.length) {
+ s = s.replace(key[j].toString(), j.toString())
+ ++j
+ }
+ r += (getString(s, v2, 10).toInt() - v1).toChar()
+ ++i
+ }
+ return r
+ }
+
+ private fun zipGen(gen: Sequence>): ArrayList, Pair>> {
+ val allItems = gen.toList().toMutableList()
+ val newList = ArrayList, Pair>>()
+
+ while (allItems.size > 1) {
+ newList.add(Pair(allItems[0], allItems[1]))
+ allItems.removeAt(0)
+ allItems.removeAt(0)
+ }
+ return newList
+ }
+
+ private fun decodeAdfly(codedKey: String): String {
+ var r = ""
+ var j = ""
+
+ for ((n, l) in codedKey.withIndex()) {
+ if (n % 2 != 0) {
+ j = l + j
+ } else {
+ r += l
+ }
+ }
+
+ val encodedUri = ((r + j).toCharArray().map { it.toString() }).toMutableList()
+ val numbers = sequence {
+ for ((i, n) in encodedUri.withIndex()) {
+ if (isNumber(n)) {
+ yield(Pair(i, n.toInt()))
+ }
+ }
+ }
+
+ for ((first, second) in zipGen(numbers)) {
+ val xor = first.second.xor(second.second)
+ if (xor < 10) {
+ encodedUri[first.first] = xor.toString()
+ }
+ }
+ var returnValue = String(encodedUri.joinToString("").toByteArray(), Charsets.UTF_8)
+ returnValue = base64Decode(returnValue)
+ return returnValue.slice(16..returnValue.length - 17)
+ }
+
+ private data class VideoQuality(
+ @JsonProperty("id") val id: Int?,
+ @JsonProperty("audio") val audio: String?,
+ @JsonProperty("kwik") val kwik: String?,
+ @JsonProperty("kwik_pahewin") val kwikPahewin: String
+ )
+
+ private data class AnimePaheEpisodeLoadLinks(
+ @JsonProperty("data") val data: List