diff --git a/src/en/slothanime/build.gradle b/src/en/slothanime/build.gradle deleted file mode 100644 index 162ed52d..00000000 --- a/src/en/slothanime/build.gradle +++ /dev/null @@ -1,7 +0,0 @@ -ext { - extName = 'SlothAnime' - extClass = '.SlothAnime' - extVersionCode = 2 -} - -apply from: "$rootDir/common.gradle" \ No newline at end of file diff --git a/src/en/slothanime/res/mipmap-hdpi/ic_launcher.png b/src/en/slothanime/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 69936bbf..00000000 Binary files a/src/en/slothanime/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/slothanime/res/mipmap-mdpi/ic_launcher.png b/src/en/slothanime/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index c67325c1..00000000 Binary files a/src/en/slothanime/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/slothanime/res/mipmap-xhdpi/ic_launcher.png b/src/en/slothanime/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 977c68e7..00000000 Binary files a/src/en/slothanime/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/slothanime/res/mipmap-xxhdpi/ic_launcher.png b/src/en/slothanime/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index efeb924b..00000000 Binary files a/src/en/slothanime/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/slothanime/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/slothanime/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 22b3b120..00000000 Binary files a/src/en/slothanime/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/en/slothanime/src/eu/kanade/tachiyomi/animeextension/en/slothanime/Filters.kt b/src/en/slothanime/src/eu/kanade/tachiyomi/animeextension/en/slothanime/Filters.kt deleted file mode 100644 index fa496d49..00000000 --- a/src/en/slothanime/src/eu/kanade/tachiyomi/animeextension/en/slothanime/Filters.kt +++ /dev/null @@ -1,122 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.en.slothanime - -import eu.kanade.tachiyomi.animesource.model.AnimeFilter - -open class UriPartFilter( - name: String, - private val vals: Array>, - defaultValue: String? = null, -) : AnimeFilter.Select( - name, - vals.map { it.first }.toTypedArray(), - vals.indexOfFirst { it.second == defaultValue }.takeIf { it != -1 } ?: 0, -) { - fun getValue(): String { - return vals[state].second - } -} - -open class UriMultiSelectOption(name: String, val value: String) : AnimeFilter.CheckBox(name) - -open class UriMultiSelectFilter( - name: String, - private val vals: Array>, -) : AnimeFilter.Group(name, vals.map { UriMultiSelectOption(it.first, it.second) }) { - fun getValues(): List { - return state.filter { it.state }.map { it.value } - } -} - -open class UriMultiTriSelectOption(name: String, val value: String) : AnimeFilter.TriState(name) - -open class UriMultiTriSelectFilter( - name: String, - private val vals: Array>, -) : AnimeFilter.Group(name, vals.map { UriMultiTriSelectOption(it.first, it.second) }) { - fun getIncluded(): List { - return state.filter { it.state == TriState.STATE_INCLUDE }.map { it.value } - } - - fun getExcluded(): List { - return state.filter { it.state == TriState.STATE_EXCLUDE }.map { it.value } - } -} - -class GenreFilter : UriMultiTriSelectFilter( - "Genre", - arrayOf( - Pair("Action", "action"), - Pair("Adventure", "adventure"), - Pair("Fantasy", "fantasy"), - Pair("Martial Arts", "martial_arts"), - Pair("Comedy", "comedy"), - Pair("School", "school"), - Pair("Slice of Life", "slice_of_life"), - Pair("Military", "military"), - Pair("Sci-Fi", "scifi"), - Pair("Isekai", "isekai"), - Pair("Kids", "kids"), - Pair("Iyashikei", "iyashikei"), - Pair("Horror", "horror"), - Pair("Supernatural", "supernatural"), - Pair("Avant Garde", "avant_garde"), - Pair("Demons", "demons"), - Pair("Gourmet", "gourmet"), - Pair("Music", "music"), - Pair("Drama", "drama"), - Pair("Seinen", "seinen"), - Pair("Ecchi", "ecchi"), - Pair("Harem", "harem"), - Pair("Romance", "romance"), - Pair("Magic", "magic"), - Pair("Mystery", "mystery"), - Pair("Suspense", "suspense"), - Pair("Parody", "parody"), - Pair("Psychological", "psychological"), - Pair("Super Power", "super_power"), - Pair("Vampire", "vampire"), - Pair("Shounen", "shounen"), - Pair("Space", "space"), - Pair("Mecha", "mecha"), - Pair("Sports", "sports"), - Pair("Shoujo", "shoujo"), - Pair("Girls Love", "girls_love"), - Pair("Josei", "josei"), - Pair("Mahou Shoujo", "mahou_shoujo"), - Pair("Thriller", "thriller"), - Pair("Reverse Harem", "reverse_harem"), - Pair("Boys Love", "boys_love"), - Pair("Uncategorized", "uncategorized"), - ), -) - -class TypeFilter : UriMultiSelectFilter( - "Type", - arrayOf( - Pair("ONA", "ona"), - Pair("TV", "tv"), - Pair("MOVIE", "movie"), - Pair("SPECIAL", "special"), - Pair("OVA", "ova"), - Pair("MUSIC", "music"), - ), -) - -class StatusFilter : UriPartFilter( - "Status", - arrayOf( - Pair("All", "2"), - Pair("Completed", "1"), - Pair("Releasing", "0"), - ), -) - -class SortFilter : UriPartFilter( - "Sort", - arrayOf( - Pair("Most Watched", "viewed"), - Pair("Scored", "scored"), - Pair("Newest", "created_at"), - Pair("Latest Update", "updated_at"), - ), -) diff --git a/src/en/slothanime/src/eu/kanade/tachiyomi/animeextension/en/slothanime/SlothAnime.kt b/src/en/slothanime/src/eu/kanade/tachiyomi/animeextension/en/slothanime/SlothAnime.kt deleted file mode 100644 index b54f381a..00000000 --- a/src/en/slothanime/src/eu/kanade/tachiyomi/animeextension/en/slothanime/SlothAnime.kt +++ /dev/null @@ -1,197 +0,0 @@ -package eu.kanade.tachiyomi.animeextension.en.slothanime - -import android.util.Base64 -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.animesource.online.ParsedAnimeHttpSource -import eu.kanade.tachiyomi.network.GET -import okhttp3.HttpUrl.Companion.toHttpUrl -import okhttp3.Request -import org.jsoup.nodes.Document -import org.jsoup.nodes.Element -import javax.crypto.Cipher -import javax.crypto.spec.IvParameterSpec -import javax.crypto.spec.SecretKeySpec -import kotlin.math.floor - -class SlothAnime : ParsedAnimeHttpSource() { - - override val name = "SlothAnime" - - override val baseUrl = "https://slothanime.com" - - override val lang = "en" - - override val supportsLatest = true - - // ============================== Popular =============================== - - override fun popularAnimeRequest(page: Int): Request { - val url = if (page > 1) { - "$baseUrl/list/viewed?page=$page" - } else { - "$baseUrl/list/viewed" - } - - return GET(url, headers) - } - - override fun popularAnimeSelector(): String = ".row > div > .anime-card-md" - - override fun popularAnimeFromElement(element: Element): SAnime = SAnime.create().apply { - thumbnail_url = element.selectFirst("img")!!.imgAttr() - with(element.selectFirst("a[href~=/anime]")!!) { - title = text() - setUrlWithoutDomain(attr("abs:href")) - } - } - - override fun popularAnimeNextPageSelector(): String = ".pagination > .active ~ li:has(a)" - - // =============================== Latest =============================== - - override fun latestUpdatesRequest(page: Int): Request { - val url = if (page > 1) { - "$baseUrl/list/latest?page=$page" - } else { - "$baseUrl/list/latest" - } - - return GET(url, headers) - } - override fun latestUpdatesSelector(): String = popularAnimeSelector() - - override fun latestUpdatesFromElement(element: Element): SAnime = popularAnimeFromElement(element) - - override fun latestUpdatesNextPageSelector(): String = popularAnimeNextPageSelector() - - // =============================== Search =============================== - - override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request { - val genreFilter = filters.filterIsInstance().first() - val typeFilter = filters.filterIsInstance().first() - val statusFilter = filters.filterIsInstance().first() - val sortFilter = filters.filterIsInstance().first() - - val url = baseUrl.toHttpUrl().newBuilder().apply { - addPathSegment("search") - addQueryParameter("q", query) - genreFilter.getIncluded().forEachIndexed { idx, value -> - addQueryParameter("genre[$idx]", value) - } - typeFilter.getValues().forEachIndexed { idx, value -> - addQueryParameter("type[$idx]", value) - } - addQueryParameter("status", statusFilter.getValue()) - addQueryParameter("sort", sortFilter.getValue()) - genreFilter.getExcluded().forEachIndexed { idx, value -> - addQueryParameter("ignore_genre[$idx]", value) - } - - if (page > 1) { - addQueryParameter("page", page.toString()) - } - }.build() - - return GET(url, headers) - } - - override fun searchAnimeSelector(): String = popularAnimeSelector() - - override fun searchAnimeFromElement(element: Element): SAnime = popularAnimeFromElement(element) - - override fun searchAnimeNextPageSelector(): String = popularAnimeNextPageSelector() - - // ============================== Filters =============================== - - override fun getFilterList(): AnimeFilterList = AnimeFilterList( - GenreFilter(), - TypeFilter(), - StatusFilter(), - SortFilter(), - ) - - // =========================== Anime Details ============================ - - override fun animeDetailsParse(document: Document): SAnime = SAnime.create().apply { - title = document.selectFirst(".single-title > *:not(.single-altername)")!!.text() - thumbnail_url = document.selectFirst(".single-cover > img")!!.imgAttr() - description = document.selectFirst(".single-detail:has(span:contains(Description)) .more-content")?.text() - genre = document.select(".single-tag > a.tag").joinToString { it.text() } - author = document.select(".single-detail:has(span:contains(Studios)) .value a").joinToString { it.text() } - } - - // ============================== Episodes ============================== - - override fun episodeListSelector() = ".list-episodes-container > a[class~=episode]" - - override fun episodeFromElement(element: Element): SEpisode = SEpisode.create().apply { - setUrlWithoutDomain(element.attr("abs:href")) - name = element.text() - .replace(Regex("""^EP """), "Episode ") - .replace(Regex("""^\d+""")) { m -> "Episode ${m.value}" } - } - - // ============================ Video Links ============================= - - fun encryptAES(input: String, key: ByteArray, iv: ByteArray): String { - val cipher = Cipher.getInstance("AES/CBC/NoPadding") - val secretKey = SecretKeySpec(key, "AES") - val ivParameterSpec = IvParameterSpec(iv) - - cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec) - val paddedInput = zeroPad(input) - val encryptedBytes = cipher.doFinal(paddedInput.toByteArray(Charsets.UTF_8)) - return Base64.encodeToString(encryptedBytes, Base64.NO_WRAP) - } - - fun zeroPad(input: String): String { - val blockSize = 16 - val padLength = blockSize - input.length % blockSize - return input.padEnd(input.length + padLength, '\u0000') - } - - override suspend fun getVideoList(episode: SEpisode): List