Initial commit

This commit is contained in:
almightyhak 2024-06-20 11:54:12 +07:00
commit 98ed7e8839
2263 changed files with 108711 additions and 0 deletions

View file

@ -0,0 +1,17 @@
ext {
extName = 'AnimeIndo'
extClass = '.AnimeIndo'
themePkg = 'animestream'
baseUrl = 'https://animeindo.skin'
overrideVersionCode = 10
}
apply from: "$rootDir/common.gradle"
dependencies {
implementation(project(":lib:mp4upload-extractor"))
implementation(project(":lib:gdriveplayer-extractor"))
implementation(project(":lib:streamtape-extractor"))
implementation(project(":lib:yourupload-extractor"))
implementation(project(":lib:okru-extractor"))
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -0,0 +1,131 @@
package eu.kanade.tachiyomi.animeextension.id.animeindo
import android.util.Log
import eu.kanade.tachiyomi.animeextension.id.animeindo.AnimeIndoFilters.GenresFilter
import eu.kanade.tachiyomi.animeextension.id.animeindo.AnimeIndoFilters.OrderFilter
import eu.kanade.tachiyomi.animeextension.id.animeindo.AnimeIndoFilters.SeasonFilter
import eu.kanade.tachiyomi.animeextension.id.animeindo.AnimeIndoFilters.StatusFilter
import eu.kanade.tachiyomi.animeextension.id.animeindo.AnimeIndoFilters.StudioFilter
import eu.kanade.tachiyomi.animeextension.id.animeindo.AnimeIndoFilters.TypeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.lib.gdriveplayerextractor.GdrivePlayerExtractor
import eu.kanade.tachiyomi.lib.mp4uploadextractor.Mp4uploadExtractor
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
import eu.kanade.tachiyomi.lib.youruploadextractor.YourUploadExtractor
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStream
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters
import eu.kanade.tachiyomi.network.GET
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import org.jsoup.nodes.Element
class AnimeIndo : AnimeStream(
"id",
"AnimeIndo",
"https://animeindo.skin",
) {
override val animeListUrl = "$baseUrl/browse"
// ============================== Popular ===============================
override fun popularAnimeRequest(page: Int) = GET("$animeListUrl/browse?sort=view&page=$page")
// =============================== Latest ===============================
override fun latestUpdatesRequest(page: Int) = GET("$animeListUrl/browse?sort=created_at&page=$page")
// =============================== Search ===============================
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val params = AnimeIndoFilters.getSearchParameters(filters)
val multiString = buildString {
if (params.genres.isNotEmpty()) append(params.genres + "&")
if (params.seasons.isNotEmpty()) append(params.seasons + "&")
if (params.studios.isNotEmpty()) append(params.studios + "&")
}
return GET("$animeListUrl/browse?page=$page&title=$query&$multiString&status=${params.status}&type=${params.type}&order=${params.order}")
}
override fun searchAnimeSelector() = "div.animepost > div > a"
override fun searchAnimeFromElement(element: Element) = SAnime.create().apply {
setUrlWithoutDomain(element.attr("href"))
title = element.selectFirst("div.title")!!.text()
thumbnail_url = element.selectFirst("img")!!.getImageUrl()
}
override fun searchAnimeNextPageSelector() = "div.pagination a:has(i#nextpagination)"
// ============================== Filters ===============================
override val filtersSelector = "div.filtersearch tbody > tr:not(:has(td.filter_title:contains(Search))) > td.filter_act"
override fun getFilterList(): AnimeFilterList {
return if (AnimeStreamFilters.filterInitialized()) {
AnimeFilterList(
OrderFilter(orderFilterText),
StatusFilter(statusFilterText),
TypeFilter(typeFilterText),
AnimeFilter.Separator(),
GenresFilter(genresFilterText),
SeasonFilter(seasonsFilterText),
StudioFilter(studioFilterText),
)
} else {
AnimeFilterList(AnimeFilter.Header(filtersMissingWarning))
}
}
// =========================== Anime Details ============================
override fun parseStatus(statusString: String?): Int {
return when (statusString?.trim()?.lowercase()) {
"finished airing" -> SAnime.COMPLETED
"currently airing" -> SAnime.ONGOING
else -> SAnime.UNKNOWN
}
}
// ============================== Episodes ==============================
override fun episodeListSelector() = "div.listeps li:has(.epsleft)"
override fun episodeFromElement(element: Element) = SEpisode.create().apply {
val ahref = element.selectFirst("a")!!
setUrlWithoutDomain(ahref.attr("href"))
val num = ahref.text()
name = "Episode $num"
episode_number = num.trim().toFloatOrNull() ?: 0F
date_upload = element.selectFirst("span.date")?.text().toDate()
}
// ============================ Video Links =============================
private val mp4uploadExtractor by lazy { Mp4uploadExtractor(client) }
private val gdrivePlayerExtractor by lazy { GdrivePlayerExtractor(client) }
private val streamTapeExtractor by lazy { StreamTapeExtractor(client) }
private val yourUploadExtractor by lazy { YourUploadExtractor(client) }
private val okruExtractor by lazy { OkruExtractor(client) }
override fun getVideoList(url: String, name: String): List<Video> {
return with(name) {
when {
contains("streamtape") -> streamTapeExtractor.videoFromUrl(url)?.let(::listOf).orEmpty()
contains("mp4") -> mp4uploadExtractor.videosFromUrl(url, headers)
contains("yourupload") -> yourUploadExtractor.videoFromUrl(url, headers)
url.contains("ok.ru") -> okruExtractor.videosFromUrl(url)
contains("gdrive") -> {
val gdriveUrl = when {
baseUrl in url -> "https:" + url.toHttpUrl().queryParameter("data")!!
else -> url
}
gdrivePlayerExtractor.videosFromUrl(gdriveUrl, "Gdrive", headers)
}
else -> {
// just to detect video hosts easily
Log.i("AnimeIndo", "Unrecognized at getVideoList => Name -> $name || URL => $url")
emptyList()
}
}
}
}
}

View file

@ -0,0 +1,62 @@
package eu.kanade.tachiyomi.animeextension.id.animeindo
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.CheckBoxFilterList
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.QueryPartFilter
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.asQueryPart
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.filterElements
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.filterInitialized
import eu.kanade.tachiyomi.multisrc.animestream.AnimeStreamFilters.parseCheckbox
object AnimeIndoFilters {
internal class GenresFilter(name: String) : CheckBoxFilterList(name, GENRES_LIST)
internal class SeasonFilter(name: String) : CheckBoxFilterList(name, SEASON_LIST)
internal class StudioFilter(name: String) : CheckBoxFilterList(name, STUDIO_LIST)
internal class StatusFilter(name: String) : QueryPartFilter(name, STATUS_LIST)
internal class TypeFilter(name: String) : QueryPartFilter(name, TYPE_LIST)
internal class OrderFilter(name: String) : QueryPartFilter(name, ORDER_LIST)
internal data class FilterSearchParams(
val genres: String = "",
val seasons: String = "",
val studios: String = "",
val status: String = "",
val type: String = "",
val order: String = "",
)
internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams {
if (filters.isEmpty()) return FilterSearchParams()
if (!filterInitialized()) return FilterSearchParams()
return FilterSearchParams(
filters.parseCheckbox<GenresFilter>(GENRES_LIST, "genre"),
filters.parseCheckbox<SeasonFilter>(SEASON_LIST, "season"),
filters.parseCheckbox<StudioFilter>(STUDIO_LIST, "studio"),
filters.asQueryPart<StatusFilter>(),
filters.asQueryPart<TypeFilter>(),
filters.asQueryPart<OrderFilter>(),
)
}
private fun getPairListByIndex(index: Int) = filterElements.get(index)
.select("ul > li, td > label")
.map { element ->
val key = element.text()
val value = element.selectFirst("input")!!.attr("value")
Pair(key, value)
}.toTypedArray()
private val ORDER_LIST by lazy {
getPairListByIndex(0)
.filterNot { it.first.contains("Most favorite", true) }
.toTypedArray()
}
private val STATUS_LIST by lazy { getPairListByIndex(1) }
private val TYPE_LIST by lazy { getPairListByIndex(2) }
private val GENRES_LIST by lazy { getPairListByIndex(3) }
private val SEASON_LIST by lazy { getPairListByIndex(4) }
private val STUDIO_LIST by lazy { getPairListByIndex(5) }
}