feat(pt/animesotaku): New Source: Animes Otaku (#440)

Co-authored-by: WebDitto <webditton@proton.me>
This commit is contained in:
WebDitto 2024-12-19 20:49:25 -03:00 committed by GitHub
parent b610a20b7f
commit ce2611d1bd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 1372 additions and 0 deletions

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<activity
android:name=".pt.animesotaku.AnimesOtakuUrlActivity"
android:excludeFromRecents="true"
android:exported="true"
android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="www.animesotaku.cc"
android:pathPattern="/anime/..*"
android:scheme="https" />
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -0,0 +1,11 @@
ext {
extName = 'AnimesOtaku'
extClass = '.AnimesOtaku'
extVersionCode = 1
}
apply from: "$rootDir/common.gradle"
dependencies {
implementation(project(":lib:blogger-extractor"))
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -0,0 +1,244 @@
package eu.kanade.tachiyomi.animeextension.pt.animesotaku
import android.util.Base64
import eu.kanade.tachiyomi.animeextension.pt.animesotaku.dto.SearchRequestDto
import eu.kanade.tachiyomi.animeextension.pt.animesotaku.dto.SearchResponseDto
import eu.kanade.tachiyomi.animeextension.pt.animesotaku.dto.SingleDto
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.AnimesPage
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.AnimeHttpSource
import eu.kanade.tachiyomi.lib.bloggerextractor.BloggerExtractor
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.awaitSuccess
import eu.kanade.tachiyomi.util.asJsoup
import eu.kanade.tachiyomi.util.parallelCatchingFlatMapBlocking
import eu.kanade.tachiyomi.util.parseAs
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import uy.kohesive.injekt.injectLazy
import java.util.concurrent.TimeUnit
class AnimesOtaku : AnimeHttpSource() {
override val name = "Animes Otaku"
override val baseUrl = "https://www.animesotaku.cc"
override val lang = "pt"
override val supportsLatest = true
private val json: Json by injectLazy()
override val client = network.client.newBuilder()
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
override fun headersBuilder() = super.headersBuilder()
.add("Referer", baseUrl)
// ============================== Popular ===============================
override fun popularAnimeRequest(page: Int) = searchOrderBy("total_kiranime_views", page)
override fun popularAnimeParse(response: Response): AnimesPage {
val results = response.parseAs<SearchResponseDto>()
val doc = Jsoup.parseBodyFragment(results.data)
val animes = doc.select("div.w-full:has(div.kira-anime)").map {
SAnime.create().apply {
thumbnail_url = it.selectFirst("img")?.attr("src")
with(it.selectFirst("h3 > a")!!) {
title = text().replace(" Assistir Online", "")
setUrlWithoutDomain(attr("href"))
}
}
}
val page = response.request.url.queryParameter("page")?.toIntOrNull() ?: 1
val hasNextPage = page < results.pages
return AnimesPage(animes, hasNextPage)
}
// =============================== Latest ===============================
override fun latestUpdatesRequest(page: Int) = searchOrderBy("kiranime_anime_updated", page)
override fun latestUpdatesParse(response: Response) = popularAnimeParse(response)
// =============================== Search ===============================
override suspend fun getSearchAnime(
page: Int,
query: String,
filters: AnimeFilterList,
): AnimesPage {
return if (query.startsWith(PREFIX_SEARCH)) { // URL intent handler
val id = query.removePrefix(PREFIX_SEARCH)
client.newCall(GET("$baseUrl/anime/$id"))
.awaitSuccess()
.use(::searchAnimeByIdParse)
} else {
super.getSearchAnime(page, query, filters)
}
}
private fun searchAnimeByIdParse(response: Response): AnimesPage {
val details = animeDetailsParse(response).apply {
setUrlWithoutDomain(response.request.url.toString())
initialized = true
}
return AnimesPage(listOf(details), false)
}
override fun getFilterList() = AnimesOtakuFilters.FILTER_LIST
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val params = AnimesOtakuFilters.getSearchParameters(filters)
val (meta, orderBy) = when (params.orderBy) {
"date", "title" -> Pair(null, params.orderBy)
else -> Pair(params.orderBy, "meta_value_num")
}
val single = SingleDto(
paged = page,
key = meta,
order = params.order,
orderBy = orderBy,
season = params.season.ifEmpty { null },
year = params.year.ifEmpty { null },
)
val taxonomies = with(params) {
listOf(genres, status, producers, studios, types).filter {
it.terms.isNotEmpty()
}
}
val requestDto = SearchRequestDto(single, query, query, taxonomies)
val requestData = json.encodeToString(requestDto)
return searchRequest(requestData, page)
}
override fun searchAnimeParse(response: Response) = popularAnimeParse(response)
private fun searchOrderBy(order: String, page: Int): Request {
val body = """
{
"keyword": "",
"query": "",
"single": {
"paged": $page,
"orderby": "meta_value_num",
"meta_key": "$order",
"order": "desc"
},
"tax": []
}
""".trimIndent()
return searchRequest(body, page)
}
private fun searchRequest(data: String, page: Int): Request {
val body = data.toRequestBody("application/json".toMediaType())
return POST(
"$baseUrl/wp-json/kiranime/v1/anime/advancedsearch?_locale=user&page=$page",
headers,
body,
)
}
// =========================== Anime Details ============================
override fun animeDetailsParse(response: Response) = SAnime.create().apply {
val document = response.asJsoup()
setUrlWithoutDomain(document.location())
thumbnail_url = document.selectFirst("div.anime-image img")?.attr("src")
title =
document.selectFirst("h1 span.show.anime")!!.text().replace(" Assistir Online", "")
genre =
document.select("span.leading-6 a[class~=border-opacity-30]").joinToString { it.text() }
description = document.selectFirst("div[data-synopsis]")?.text()
author = document.selectFirst("span.leading-6 a[href*=\"producer\"]:first-child")?.text()
artist = document.selectFirst("span.leading-6 a[href*=\"studio\"]:first-child")?.text()
}
// ============================== Episodes ==============================
override fun episodeListParse(response: Response): List<SEpisode> {
return getRealDoc(response.asJsoup())
.select(episodeListSelector())
.map(::episodeFromElement)
}
fun episodeListSelector(): String = "div[data-current-slider=\"episode-list\"] a"
fun episodeFromElement(element: Element) = SEpisode.create().apply {
setUrlWithoutDomain(element.attr("href"))
name = element.selectFirst("span.font-semibold")!!.text().trim()
episode_number = name.substringAfterLast(" ").toFloatOrNull() ?: 0F
}
// ============================ Video Links =============================
private val bloggerExtractor by lazy { BloggerExtractor(client) }
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
val players = document.select("div.player-selection span[data-embed-id]")
return players.parallelCatchingFlatMapBlocking(::getPlayerVideos)
}
private fun getPlayerVideos(player: Element): List<Video> {
val url = player.attr("data-embed-id")
.substringAfter(":")
.let { String(Base64.decode(it, Base64.DEFAULT)) }
return when {
"blogger.com" in url -> bloggerExtractor.videosFromUrl(url, headers)
"proxycdn.vip" in url -> {
val mp4Url = client.newCall(GET(url, headers)).execute()
.asJsoup()
.selectFirst("video")
?.attr("src")
?.let {
if (it.startsWith("//")) {
return@let "https:$it"
}
it
}
?: return emptyList()
listOf(
Video(mp4Url, "Proxy CDN", mp4Url),
)
}
else -> null
} ?: emptyList()
}
// ============================= Utilities ==============================
private fun getRealDoc(document: Document): Document {
val menu = document.selectFirst("div.spr.i-lista")
if (menu != null) {
val originalUrl = menu.parent()!!.attr("href")
val response = client.newCall(GET(originalUrl, headers)).execute()
return response.asJsoup()
}
return document
}
companion object {
const val PREFIX_SEARCH = "id:"
}
}

View file

@ -0,0 +1,949 @@
package eu.kanade.tachiyomi.animeextension.pt.animesotaku
import eu.kanade.tachiyomi.animeextension.pt.animesotaku.dto.TaxonomyDto
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import java.util.Calendar
object AnimesOtakuFilters {
open class QueryPartFilter(
displayName: String,
val vals: Array<Pair<String, String>>,
) : AnimeFilter.Select<String>(
displayName,
vals.map { it.first }.toTypedArray(),
) {
fun toQueryPart() = vals[state].second
}
open class CheckBoxFilterList(name: String, val pairs: Array<Pair<String, Int>>) :
AnimeFilter.Group<AnimeFilter.CheckBox>(name, pairs.map { CheckBoxVal(it.first, false) })
private class CheckBoxVal(name: String, state: Boolean = false) :
AnimeFilter.CheckBox(name, state)
private inline fun <reified R> AnimeFilterList.getFirst(): R = first { it is R } as R
private inline fun <reified R> AnimeFilterList.asQueryPart(): String {
return (getFirst<R>() as QueryPartFilter).toQueryPart()
}
private inline fun <reified R> AnimeFilterList.parseCheckbox(
options: Array<Pair<String, Int>>,
name: String,
): TaxonomyDto {
return (getFirst<R>() as CheckBoxFilterList).state
.filter { it.state }
.map { checkbox -> options.find { it.first == checkbox.name }!!.second }
.let { TaxonomyDto(name, it) }
}
class GenresFilter : CheckBoxFilterList("Genero", AnimesOtakuFiltersData.GENRES)
class StatusFilter : CheckBoxFilterList("Status", AnimesOtakuFiltersData.STATUS)
class ProducersFilter : CheckBoxFilterList("Produtor", AnimesOtakuFiltersData.PRODUCERS)
class StudiosFilter : CheckBoxFilterList("Studio", AnimesOtakuFiltersData.GENRES)
class TypesFilter : CheckBoxFilterList("Tipo", AnimesOtakuFiltersData.TYPES)
class OrderFilter : AnimeFilter.Sort(
"Ordernar Por",
AnimesOtakuFiltersData.ORDERS.map { it.first }.toTypedArray(),
Selection(0, false),
)
class YearFilter : QueryPartFilter("Ano", AnimesOtakuFiltersData.YEARS)
class SeasonFilter : QueryPartFilter("Temporada", AnimesOtakuFiltersData.SEASONS)
val FILTER_LIST
get() = AnimeFilterList(
OrderFilter(),
YearFilter(),
SeasonFilter(),
AnimeFilter.Separator(),
GenresFilter(),
StatusFilter(),
ProducersFilter(),
StudiosFilter(),
TypesFilter(),
)
data class FilterSearchParams(
val genres: TaxonomyDto = TaxonomyDto(),
val status: TaxonomyDto = TaxonomyDto(),
val producers: TaxonomyDto = TaxonomyDto(),
val studios: TaxonomyDto = TaxonomyDto(),
val types: TaxonomyDto = TaxonomyDto(),
val order: String = "desc",
val orderBy: String = "total_kiranime_views",
val year: String = "",
val season: String = "",
)
internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams {
if (filters.isEmpty()) return FilterSearchParams()
val (order, orderBy) = filters.getFirst<OrderFilter>().state?.let {
val order = if (it.ascending) "asc" else "desc"
val orderBy = AnimesOtakuFiltersData.ORDERS[it.index].second
Pair(order, orderBy)
} ?: Pair("desc", "total_kiranime_views")
return FilterSearchParams(
filters.parseCheckbox<GenresFilter>(AnimesOtakuFiltersData.GENRES, "genre"),
filters.parseCheckbox<StatusFilter>(AnimesOtakuFiltersData.STATUS, "status"),
filters.parseCheckbox<ProducersFilter>(AnimesOtakuFiltersData.PRODUCERS, "producer"),
filters.parseCheckbox<StudiosFilter>(AnimesOtakuFiltersData.STUDIOS, "studio"),
filters.parseCheckbox<TypesFilter>(AnimesOtakuFiltersData.TYPES, "type"),
order,
orderBy,
filters.asQueryPart<YearFilter>(),
filters.asQueryPart<SeasonFilter>(),
)
}
private object AnimesOtakuFiltersData {
val EVERY = Pair("Selecione", "")
val GENRES = arrayOf(
Pair("Action", 10),
Pair("Adult Cast", 556),
Pair("Adventure", 11),
Pair("Boys Love", 213),
Pair("Comedy", 12),
Pair("Drama", 13),
Pair("Ecchi", 177),
Pair("Erotica", 253),
Pair("Fantasy", 14),
Pair("Girls Love", 261),
Pair("Gourmet", 17),
Pair("Hentai", 41),
Pair("Idols (male)", 528),
Pair("Kids", 440),
Pair("Music", 529),
Pair("Mystery", 104),
Pair("Otaku Culture", 550),
Pair("Racing", 434),
Pair("Romance", 170),
Pair("School", 551),
Pair("Sci-fi", 278),
Pair("Seinen", 435),
Pair("Slice Of Life", 191),
Pair("Sports", 102),
Pair("Strategy Game", 537),
Pair("Supernatural", 161),
Pair("Suspense", 162),
)
val STATUS = arrayOf(
Pair("Airing", 3),
Pair("Completed", 4),
Pair("Upcoming", 2),
)
val PRODUCERS = arrayOf(
Pair("4kids Entertainment", 355),
Pair("Abc Animation", 222),
Pair("Abematv", 125),
Pair("Agehasprings", 63),
Pair("Akita Shoten", 80),
Pair("Alphapolis", 52),
Pair("Amuse", 521),
Pair("Animax", 106),
Pair("Aniplex", 19),
Pair("Arma Bianca", 115),
Pair("Asatsu Dk", 353),
Pair("Asmik Ace", 504),
Pair("At-x", 87),
Pair("Avex Entertainment", 361),
Pair("Avex Pictures", 467),
Pair("Bandai", 68),
Pair("Bandai Namco Arts", 497),
Pair("Bandai Namco Entertainment", 69),
Pair("Bandai Namco Filmworks", 75),
Pair("Bandai Namco Music Live", 76),
Pair("Bandai Spirits", 424),
Pair("Bandai Visual", 70),
Pair("Being", 480),
Pair("Bilibili", 263),
Pair("Bit Grooove Promotion", 586),
Pair("Bloomz", 568),
Pair("Booklive", 133),
Pair("Brave Hearts", 343),
Pair("Broccoli", 542),
Pair("Bs Fuji", 134),
Pair("Bushiroad", 292),
Pair("Bushiroad Move", 405),
Pair("Bushiroad Music", 482),
Pair("Bytehoo", 524),
Pair("Cammot", 463),
Pair("Celsys", 336),
Pair("Children's Playground Entertainment", 509),
Pair("China Literature Limited", 194),
Pair("Cloud22", 320),
Pair("Comic Animation", 535),
Pair("Comicsmart", 488),
Pair("Contents Seed", 491),
Pair("Cosmic Ray", 574),
Pair("Crunchyroll", 20),
Pair("Ctw", 54),
Pair("Cucuri", 421),
Pair("Cyberagent", 126),
Pair("Cygames", 505),
Pair("D-rights", 387),
Pair("D&c Media", 21),
Pair("Dax Production", 269),
Pair("Delfi Sound", 127),
Pair("Dentsu", 516),
Pair("Dive Ii Entertainment", 363),
Pair("Dmm Music", 442),
Pair("Dmm Pictures", 567),
Pair("Dmm.com", 418),
Pair("Dmm.com Labo", 344),
Pair("Dmm.futureworks", 128),
Pair("Dugout", 166),
Pair("Dwango", 236),
Pair("Dynamic Planning", 571),
Pair("Earth Star Entertainment", 274),
Pair("East Press", 223),
Pair("Egg Firm", 369),
Pair("Emon", 319),
Pair("Exa International", 116),
Pair("F.m.f", 275),
Pair("Flying Dog", 117),
Pair("Free-will", 384),
Pair("Front Wing", 584),
Pair("Frontier Works", 118),
Pair("Fuji TV", 32),
Pair("Furyu", 492),
Pair("Futabasha", 107),
Pair("Future Vision Music", 245),
Pair("Gdh", 243),
Pair("Genco", 88),
Pair("Geneon Entertainment", 184),
Pair("Geneon Universal Entertainment", 178),
Pair("Global Solutions", 135),
Pair("Glovision", 508),
Pair("Graduate School Of Film Producing", 337),
Pair("Gree", 119),
Pair("Grooove", 417),
Pair("Hakuhodo", 108),
Pair("Hakuhodo Dy Media Partners", 71),
Pair("Hakuhodo Dy Music & Pictures", 109),
Pair("Hakusensha", 179),
Pair("Half H.p Studio", 180),
Pair("Happinet", 506),
Pair("Happinet Pictures", 356),
Pair("Happy Elements", 448),
Pair("Hexagon Pictures", 331),
Pair("Hobby Japan", 89),
Pair("Hobi Animation", 536),
Pair("Hokkaido Cultural Broadcasting", 136),
Pair("Hotzipang", 270),
Pair("Hypergryph", 281),
Pair("Ibis Capital Partners", 137),
Pair("Ichigo Animation", 534),
Pair("Imagica", 453),
Pair("Imagine", 532),
Pair("Iqiyi", 401),
Pair("Jinnan Studio", 490),
Pair("Kadokawa", 120),
Pair("Kadokawa Media House", 121),
Pair("Kadokawa Shoten", 342),
Pair("Kakao Piccoma", 22),
Pair("Kanetsu Investment", 138),
Pair("Kanon Sound", 90),
Pair("Kappa Entertainment", 552),
Pair("Khara", 37),
Pair("King Records", 55),
Pair("Kinoshita Group Holdings", 502),
Pair("Klockworx", 56),
Pair("Kodansha", 29),
Pair("Kotowari", 587),
Pair("Lantis", 91),
Pair("Legendoor", 284),
Pair("Lucent Pictures Entertainment", 129),
Pair("M.o.e.", 462),
Pair("Magic Capsule", 77),
Pair("Magnet", 57),
Pair("Mainichi Broadcasting System", 72),
Pair("Marvelous Entertainment", 572),
Pair("Media Factory", 246),
Pair("Mill Creek Entertainment", 580),
Pair("Movic", 235),
Pair("Muse International", 333),
Pair("My Theater D.d.", 169),
Pair("Nagoya Broadcasting Network", 357),
Pair("Nbcuniversal Entertainment Japan", 92),
Pair("Nelvana", 305),
Pair("Netflix", 150),
Pair("Netmarble", 23),
Pair("Nhk", 26),
Pair("Nhk Enterprises", 27),
Pair("Nihon Ad Systems", 562),
Pair("Nippon Columbia", 24),
Pair("Nippon Television Network", 97),
Pair("Nitroplus", 362),
Pair("Nobishiro Lab", 475),
Pair("Occ", 335),
Pair("Omnibus Promotion", 471),
Pair("Orchid Seed", 93),
Pair("Overlap", 557),
Pair("Picante Circus", 241),
Pair("Pierrot", 479),
Pair("Pioneer Ldc", 573),
Pair("Pony Canyon", 110),
Pair("Poplar Publishing", 433),
Pair("Production I.g", 533),
Pair("Quatre Stella", 474),
Pair("Quyue Technology", 426),
Pair("Rondo Robe", 386),
Pair("S-tar7", 487),
Pair("Sankyo Planning", 519),
Pair("Sanrio", 391),
Pair("Satelight", 122),
Pair("Sedic International", 518),
Pair("Sega", 354),
Pair("Sega Games", 370),
Pair("Shochiku", 188),
Pair("Shogakukan", 351),
Pair("Shogakukan-shueisha Productions", 185),
Pair("Showgate", 237),
Pair("Shueisha", 39),
Pair("Simplicity", 371),
Pair("Skydance", 254),
Pair("Slow Curve", 553),
Pair("Sme Records", 332),
Pair("Smiral Animation", 498),
Pair("Softx", 544),
Pair("Sol Blade", 578),
Pair("Sonilude", 40),
Pair("Sony Music Entertainment", 73),
Pair("Sony Pictures Entertainment", 579),
Pair("Sotsu", 130),
Pair("Sotsu Music Publishing", 244),
Pair("Souten No Ken", 513),
Pair("Square Enix", 465),
Pair("Starchild Records", 234),
Pair("Strawberry Meets Pictures", 140),
Pair("Studio Bus", 58),
Pair("Studio Chant", 478),
Pair("Studio Mausu", 44),
Pair("Studio Montagne", 282),
Pair("Studio Noix", 111),
Pair("Studio Tulip", 545),
Pair("Suiseisha", 45),
Pair("Sunrise Music", 265),
Pair("Takeshobo", 477),
Pair("Taki Corporation", 503),
Pair("Tbs", 181),
Pair("Techno Sound", 554),
Pair("Tencent Animation & Comics", 262),
Pair("Tencent Penguin Pictures", 196),
Pair("Three Fat Samurai", 577),
Pair("Tis", 345),
Pair("Tms Entertainment", 404),
Pair("Toei Animation", 79),
Pair("Toei Video", 112),
Pair("Toho", 527),
Pair("TOHO animation", 35),
Pair("Toho Music", 36),
Pair("Tohokushinsha Film Corporation", 378),
Pair("Tokyo Mx", 517),
Pair("Tokyu Recreation", 520),
Pair("Toranoana", 460),
Pair("Trif Studio", 522),
Pair("Truss", 450),
Pair("Tv Asahi", 131),
Pair("Tv Osaka", 390),
Pair("TV Tokyo", 31),
Pair("Tv Tokyo Music", 575),
Pair("Twin Engine", 183),
Pair("Tyo", 470),
Pair("Typhoon Graphics", 486),
Pair("Ultra Super Pictures", 430),
Pair("Unlimited Produce By Tms", 316),
Pair("VAP", 85),
Pair("Victor Entertainment", 189),
Pair("Visual Arts", 494),
Pair("Warner Bros. Japan", 297),
Pair("Watermark", 334),
Pair("Wowmax", 585),
Pair("Xebec", 561),
Pair("Y&n Brothers", 141),
Pair("Yaoqi", 495),
Pair("Yomiko Advertising", 501),
Pair("Yomiuri Telecasting", 350),
Pair("Yomiuri Tv Enterprise", 432),
Pair("Yostar", 283),
Pair("Zack Promotion", 481),
Pair("Zenta Studio", 588),
)
val STUDIOS = arrayOf(
Pair("8bit", 66),
Pair("A-1 Pictures", 18),
Pair("A-real", 349),
Pair("A.c.g.t.", 325),
Pair("Acca Effe", 514),
Pair("Actas", 205),
Pair("Adonero", 358),
Pair("Aic", 258),
Pair("Aic Asta", 455),
Pair("Aic Build", 323),
Pair("Aic Classic", 365),
Pair("Aic Plus+", 46),
Pair("Aic Spirits", 382),
Pair("Ajia-do", 396),
Pair("Akatsuki", 581),
Pair("Animation Do", 153),
Pair("Appp", 456),
Pair("Ark", 410),
Pair("Arms", 176),
Pair("Artland", 86),
Pair("Arvo Animation", 419),
Pair("Asahi Production", 247),
Pair("Ashi Productions", 436),
Pair("Ask Animation Studio", 407),
Pair("Assez Finaud Fabric", 439),
Pair("Atelierpontdarc", 203),
Pair("Axsiz", 251),
Pair("B.cmay Pictures", 217),
Pair("Bakken Record", 409),
Pair("Bandai Namco Pictures", 206),
Pair("Bandai Visual", 256),
Pair("Bee Train", 444),
Pair("Bibury Animation Studios", 295),
Pair("Big Firebird Culture", 458),
Pair("Bilibili", 564),
Pair("Blade", 173),
Pair("Bloomz", 446),
Pair("Bones", 105),
Pair("Bouncy", 395),
Pair("Brain's Base", 174),
Pair("Bridge", 95),
Pair("Bug Films", 543),
Pair("C-station", 193),
Pair("C2c", 309),
Pair("Chaos Project", 290),
Pair("Children's Playground Entertainment", 393),
Pair("Cloud Hearts", 53),
Pair("Cloverworks", 100),
Pair("Cocktail Media", 227),
Pair("Colored Pencil Animation", 218),
Pair("Connect", 157),
Pair("Craftar Studios", 398),
Pair("Creators In Pack", 321),
Pair("Cygamespictures", 132),
Pair("Daume", 348),
Pair("David Production", 67),
Pair("Digital Network Animation", 422),
Pair("Diomedéa", 101),
Pair("Dle", 397),
Pair("Dmm.futureworks", 473),
Pair("Doga Kobo", 60),
Pair("Domerica", 224),
Pair("Dr Movie", 368),
Pair("Drive", 260),
Pair("Drop", 338),
Pair("Dynamo Pictures", 257),
Pair("E&amp;amp;g Films", 546),
Pair("E&amp;amp;h Production", 214),
Pair("East Fish Studio", 225),
Pair("Ekachi Epilka", 285),
Pair("Elias", 208),
Pair("Emt Squared", 204),
Pair("Encourage Films", 248),
Pair("Engi", 221),
Pair("Ether Kitten", 489),
Pair("Ezόla", 392),
Pair("Fanworks", 272),
Pair("Felix Film", 264),
Pair("Foch Film", 195),
Pair("Fugaku", 582),
Pair("Fuji Tv", 548),
Pair("Funimation", 47),
Pair("G-angle", 389),
Pair("Gaina", 200),
Pair("Gainax", 163),
Pair("Gainax Kyoto", 560),
Pair("Gallop", 541),
Pair("Gansis", 291),
Pair("Garden Culture", 359),
Pair("Gathering", 589),
Pair("Geek Toys", 50),
Pair("Gekkou", 211),
Pair("Gemba", 311),
Pair("Geno Studio", 383),
Pair("Giga Production", 515),
Pair("Gohands", 287),
Pair("Gonzo", 78),
Pair("Gosay Studio", 476),
Pair("Graphinica", 277),
Pair("Group Tac", 280),
Pair("Hal Film Maker", 302),
Pair("Haoliners Animation League", 312),
Pair("Hero", 437),
Pair("Hoods Entertainment", 252),
Pair("Hotline", 510),
Pair("Idragons Creative Studio", 525),
Pair("Ilca", 540),
Pair("Imagica Infos", 209),
Pair("Imagin", 187),
Pair("Imagineer", 273),
Pair("Indivision", 286),
Pair("J.c.staff", 151),
Pair("Jumondo", 267),
Pair("Kamikaze Douga", 375),
Pair("Kinema Citrus", 167),
Pair("Koo-ki", 523),
Pair("Kyoto Animation", 154),
Pair("L-a-unch・box", 381),
Pair("L²studio", 496),
Pair("Lan Studio", 428),
Pair("Landq Studios", 452),
Pair("Lapin Track", 207),
Pair("Larx Entertainment", 146),
Pair("Lay-duce", 219),
Pair("Lerche", 186),
Pair("Lesprit", 530),
Pair("Lidenfilms", 103),
Pair("Lingsanwu Animation", 266),
Pair("Liyu Culture", 539),
Pair("Lyrics", 464),
Pair("M.s.c", 339),
Pair("Madhouse", 65),
Pair("Magic Bus", 242),
Pair("Maho Film", 268),
Pair("Manglobe", 158),
Pair("Mappa", 145),
Pair("Millepensee", 310),
Pair("Motion Magic", 197),
Pair("Namu Animation", 322),
Pair("Naz", 271),
Pair("Next Media Animation", 414),
Pair("Nexus", 190),
Pair("Nippon Columbia", 48),
Pair("Nomad", 139),
Pair("Nut", 171),
Pair("Okuruto Noboru", 159),
Pair("Olm", 62),
Pair("Orange", 149),
Pair("Oz", 549),
Pair("P.a. Works", 142),
Pair("Palm Studio", 379),
Pair("Passione", 152),
Pair("Pb Animation Co. Ltd.", 538),
Pair("Peak Hunt", 485),
Pair("Picture Magic", 493),
Pair("Pierrot", 28),
Pair("Pierrot Films", 555),
Pair("Pierrot Plus", 308),
Pair("Pine Jam", 377),
Pair("Platinum Vision", 352),
Pair("Polygon Pictures", 144),
Pair("Pra", 315),
Pair("Production Doa", 438),
Pair("Production I.G", 38),
Pair("Production Ims", 259),
Pair("Production Reed", 155),
Pair("Project No.9", 172),
Pair("Qiyuan Yinghua", 459),
Pair("Quad", 324),
Pair("Rabbit Gate", 511),
Pair("Radix", 388),
Pair("Revoroot", 304),
Pair("Rising Force", 276),
Pair("Roll2", 202),
Pair("Ruo Hong Culture", 441),
Pair("Saetta", 408),
Pair("Sanzigen", 279),
Pair("Satelight", 215),
Pair("Science Saru", 148),
Pair("Seven", 346),
Pair("Seven Arcs", 212),
Pair("Seven Arcs Pictures", 307),
Pair("Seven Stone Entertainment", 402),
Pair("Shaft", 164),
Pair("Shengying Animation", 364),
Pair("Shin-ei Animation", 123),
Pair("Shirogumi", 469),
Pair("Shuka", 301),
Pair("Signal.md", 156),
Pair("Silver", 298),
Pair("Space Neko Company", 376),
Pair("Sparkly Key Animation Studio", 198),
Pair("Staple Entertainment", 299),
Pair("Studio 3hz", 373),
Pair("Studio 4°c", 569),
Pair("Studio A-cat", 216),
Pair("Studio Bind", 34),
Pair("Studio Candy Box", 296),
Pair("Studio Colorido", 328),
Pair("Studio Comet", 367),
Pair("Studio Deen", 143),
Pair("Studio Durian", 583),
Pair("Studio Elle", 380),
Pair("Studio Fantasia", 255),
Pair("Studio Flad", 300),
Pair("Studio Flag", 411),
Pair("Studio Gokumi", 250),
Pair("Studio Hibari", 372),
Pair("Studio Hokiboshi", 43),
Pair("Studio Junio", 499),
Pair("Studio Kafka", 192),
Pair("Studio Kai", 220),
Pair("Studio Lan", 565),
Pair("Studio M2", 483),
Pair("Studio Matrix", 385),
Pair("Studio Mother", 226),
Pair("Studio N", 228),
Pair("Studio Palette", 201),
Pair("Studio Polon", 500),
Pair("Studio Puyukai", 399),
Pair("Studio Signpost", 403),
Pair("Studio Voln", 413),
Pair("Studio! Cucuri", 531),
Pair("Sublimation", 360),
Pair("Sunrise", 74),
Pair("Sunrise Beyond", 425),
Pair("Suoyi Technology", 427),
Pair("Synergysp", 124),
Pair("Tatsunoko Production", 366),
Pair("Team Yamahitsuji", 329),
Pair("Team Yokkyufuman", 374),
Pair("Tear Studio", 429),
Pair("Telecom Animation Film", 84),
Pair("Tezuka Productions", 182),
Pair("The Answer Studio", 114),
Pair("Thundray", 449),
Pair("Tms Entertainment", 83),
Pair("Tnk", 94),
Pair("Toei Animation", 15),
Pair("Toho Animation Studio", 570),
Pair("Tokyo Kids", 294),
Pair("Trans Arts", 327),
Pair("Triangle Staff", 340),
Pair("Trif Studio", 443),
Pair("Trigger", 168),
Pair("Troyca", 199),
Pair("Tsumugi Akita Animation Lab", 30),
Pair("Tyo Animations", 484),
Pair("Typhoon Graphics", 210),
Pair("Ufotable", 341),
Pair("Unend", 412),
Pair("Uwan Pictures", 461),
Pair("Viewworks", 576),
Pair("Voil", 566),
Pair("W-toon Studio", 472),
Pair("Wawayu Animation", 447),
Pair("White Fox", 160),
Pair("Wit Studio", 165),
Pair("Wolfsbane", 445),
Pair("Xebec", 96),
Pair("Xebec M2", 563),
Pair("Yaoyorozu", 416),
Pair("Yokohama Animation Laboratory", 59),
Pair("Yostar Pictures", 51),
Pair("Yumeta Company", 25),
Pair("Zero-g", 113),
Pair("Zexcs", 239), Pair("8bit", 66),
Pair("A-1 Pictures", 18),
Pair("A-real", 349),
Pair("A.c.g.t.", 325),
Pair("Acca Effe", 514),
Pair("Actas", 205),
Pair("Adonero", 358),
Pair("Aic", 258),
Pair("Aic Asta", 455),
Pair("Aic Build", 323),
Pair("Aic Classic", 365),
Pair("Aic Plus+", 46),
Pair("Aic Spirits", 382),
Pair("Ajia-do", 396),
Pair("Akatsuki", 581),
Pair("Animation Do", 153),
Pair("Appp", 456),
Pair("Ark", 410),
Pair("Arms", 176),
Pair("Artland", 86),
Pair("Arvo Animation", 419),
Pair("Asahi Production", 247),
Pair("Ashi Productions", 436),
Pair("Ask Animation Studio", 407),
Pair("Assez Finaud Fabric", 439),
Pair("Atelierpontdarc", 203),
Pair("Axsiz", 251),
Pair("B.cmay Pictures", 217),
Pair("Bakken Record", 409),
Pair("Bandai Namco Pictures", 206),
Pair("Bandai Visual", 256),
Pair("Bee Train", 444),
Pair("Bibury Animation Studios", 295),
Pair("Big Firebird Culture", 458),
Pair("Bilibili", 564),
Pair("Blade", 173),
Pair("Bloomz", 446),
Pair("Bones", 105),
Pair("Bouncy", 395),
Pair("Brain's Base", 174),
Pair("Bridge", 95),
Pair("Bug Films", 543),
Pair("C-station", 193),
Pair("C2c", 309),
Pair("Chaos Project", 290),
Pair("Children's Playground Entertainment", 393),
Pair("Cloud Hearts", 53),
Pair("Cloverworks", 100),
Pair("Cocktail Media", 227),
Pair("Colored Pencil Animation", 218),
Pair("Connect", 157),
Pair("Craftar Studios", 398),
Pair("Creators In Pack", 321),
Pair("Cygamespictures", 132),
Pair("Daume", 348),
Pair("David Production", 67),
Pair("Digital Network Animation", 422),
Pair("Diomedéa", 101),
Pair("Dle", 397),
Pair("Dmm.futureworks", 473),
Pair("Doga Kobo", 60),
Pair("Domerica", 224),
Pair("Dr Movie", 368),
Pair("Drive", 260),
Pair("Drop", 338),
Pair("Dynamo Pictures", 257),
Pair("E&amp;amp;g Films", 546),
Pair("E&amp;amp;h Production", 214),
Pair("East Fish Studio", 225),
Pair("Ekachi Epilka", 285),
Pair("Elias", 208),
Pair("Emt Squared", 204),
Pair("Encourage Films", 248),
Pair("Engi", 221),
Pair("Ether Kitten", 489),
Pair("Ezόla", 392),
Pair("Fanworks", 272),
Pair("Felix Film", 264),
Pair("Foch Film", 195),
Pair("Fugaku", 582),
Pair("Fuji Tv", 548),
Pair("Funimation", 47),
Pair("G-angle", 389),
Pair("Gaina", 200),
Pair("Gainax", 163),
Pair("Gainax Kyoto", 560),
Pair("Gallop", 541),
Pair("Gansis", 291),
Pair("Garden Culture", 359),
Pair("Gathering", 589),
Pair("Geek Toys", 50),
Pair("Gekkou", 211),
Pair("Gemba", 311),
Pair("Geno Studio", 383),
Pair("Giga Production", 515),
Pair("Gohands", 287),
Pair("Gonzo", 78),
Pair("Gosay Studio", 476),
Pair("Graphinica", 277),
Pair("Group Tac", 280),
Pair("Hal Film Maker", 302),
Pair("Haoliners Animation League", 312),
Pair("Hero", 437),
Pair("Hoods Entertainment", 252),
Pair("Hotline", 510),
Pair("Idragons Creative Studio", 525),
Pair("Ilca", 540),
Pair("Imagica Infos", 209),
Pair("Imagin", 187),
Pair("Imagineer", 273),
Pair("Indivision", 286),
Pair("J.c.staff", 151),
Pair("Jumondo", 267),
Pair("Kamikaze Douga", 375),
Pair("Kinema Citrus", 167),
Pair("Koo-ki", 523),
Pair("Kyoto Animation", 154),
Pair("L-a-unch・box", 381),
Pair("L²studio", 496),
Pair("Lan Studio", 428),
Pair("Landq Studios", 452),
Pair("Lapin Track", 207),
Pair("Larx Entertainment", 146),
Pair("Lay-duce", 219),
Pair("Lerche", 186),
Pair("Lesprit", 530),
Pair("Lidenfilms", 103),
Pair("Lingsanwu Animation", 266),
Pair("Liyu Culture", 539),
Pair("Lyrics", 464),
Pair("M.s.c", 339),
Pair("Madhouse", 65),
Pair("Magic Bus", 242),
Pair("Maho Film", 268),
Pair("Manglobe", 158),
Pair("Mappa", 145),
Pair("Millepensee", 310),
Pair("Motion Magic", 197),
Pair("Namu Animation", 322),
Pair("Naz", 271),
Pair("Next Media Animation", 414),
Pair("Nexus", 190),
Pair("Nippon Columbia", 48),
Pair("Nomad", 139),
Pair("Nut", 171),
Pair("Okuruto Noboru", 159),
Pair("Olm", 62),
Pair("Orange", 149),
Pair("Oz", 549),
Pair("P.a. Works", 142),
Pair("Palm Studio", 379),
Pair("Passione", 152),
Pair("Pb Animation Co. Ltd.", 538),
Pair("Peak Hunt", 485),
Pair("Picture Magic", 493),
Pair("Pierrot", 28),
Pair("Pierrot Films", 555),
Pair("Pierrot Plus", 308),
Pair("Pine Jam", 377),
Pair("Platinum Vision", 352),
Pair("Polygon Pictures", 144),
Pair("Pra", 315),
Pair("Production Doa", 438),
Pair("Production I.G", 38),
Pair("Production Ims", 259),
Pair("Production Reed", 155),
Pair("Project No.9", 172),
Pair("Qiyuan Yinghua", 459),
Pair("Quad", 324),
Pair("Rabbit Gate", 511),
Pair("Radix", 388),
Pair("Revoroot", 304),
Pair("Rising Force", 276),
Pair("Roll2", 202),
Pair("Ruo Hong Culture", 441),
Pair("Saetta", 408),
Pair("Sanzigen", 279),
Pair("Satelight", 215),
Pair("Science Saru", 148),
Pair("Seven", 346),
Pair("Seven Arcs", 212),
Pair("Seven Arcs Pictures", 307),
Pair("Seven Stone Entertainment", 402),
Pair("Shaft", 164),
Pair("Shengying Animation", 364),
Pair("Shin-ei Animation", 123),
Pair("Shirogumi", 469),
Pair("Shuka", 301),
Pair("Signal.md", 156),
Pair("Silver", 298),
Pair("Space Neko Company", 376),
Pair("Sparkly Key Animation Studio", 198),
Pair("Staple Entertainment", 299),
Pair("Studio 3hz", 373),
Pair("Studio 4°c", 569),
Pair("Studio A-cat", 216),
Pair("Studio Bind", 34),
Pair("Studio Candy Box", 296),
Pair("Studio Colorido", 328),
Pair("Studio Comet", 367),
Pair("Studio Deen", 143),
Pair("Studio Durian", 583),
Pair("Studio Elle", 380),
Pair("Studio Fantasia", 255),
Pair("Studio Flad", 300),
Pair("Studio Flag", 411),
Pair("Studio Gokumi", 250),
Pair("Studio Hibari", 372),
Pair("Studio Hokiboshi", 43),
Pair("Studio Junio", 499),
Pair("Studio Kafka", 192),
Pair("Studio Kai", 220),
Pair("Studio Lan", 565),
Pair("Studio M2", 483),
Pair("Studio Matrix", 385),
Pair("Studio Mother", 226),
Pair("Studio N", 228),
Pair("Studio Palette", 201),
Pair("Studio Polon", 500),
Pair("Studio Puyukai", 399),
Pair("Studio Signpost", 403),
Pair("Studio Voln", 413),
Pair("Studio! Cucuri", 531),
Pair("Sublimation", 360),
Pair("Sunrise", 74),
Pair("Sunrise Beyond", 425),
Pair("Suoyi Technology", 427),
Pair("Synergysp", 124),
Pair("Tatsunoko Production", 366),
Pair("Team Yamahitsuji", 329),
Pair("Team Yokkyufuman", 374),
Pair("Tear Studio", 429),
Pair("Telecom Animation Film", 84),
Pair("Tezuka Productions", 182),
Pair("The Answer Studio", 114),
Pair("Thundray", 449),
Pair("Tms Entertainment", 83),
Pair("Tnk", 94),
Pair("Toei Animation", 15),
Pair("Toho Animation Studio", 570),
Pair("Tokyo Kids", 294),
Pair("Trans Arts", 327),
Pair("Triangle Staff", 340),
Pair("Trif Studio", 443),
Pair("Trigger", 168),
Pair("Troyca", 199),
Pair("Tsumugi Akita Animation Lab", 30),
Pair("Tyo Animations", 484),
Pair("Typhoon Graphics", 210),
Pair("Ufotable", 341),
Pair("Unend", 412),
Pair("Uwan Pictures", 461),
Pair("Viewworks", 576),
Pair("Voil", 566),
Pair("W-toon Studio", 472),
Pair("Wawayu Animation", 447),
Pair("White Fox", 160),
Pair("Wit Studio", 165),
Pair("Wolfsbane", 445),
Pair("Xebec", 96),
Pair("Xebec M2", 563),
Pair("Yaoyorozu", 416),
Pair("Yokohama Animation Laboratory", 59),
Pair("Yostar Pictures", 51),
Pair("Yumeta Company", 25),
Pair("Zero-g", 113),
Pair("Zexcs", 239),
)
val TYPES = arrayOf(
Pair("Movie", 410),
Pair("ONA", 42),
Pair("OVA", 82),
Pair("Special", 547),
Pair("TV", 16),
)
val ORDERS = arrayOf(
Pair("Popular", "total_kiranime_views"),
Pair("Favoritos", "bookmark_count"),
Pair("Titulo", "title"),
Pair("Data", "date"),
Pair("Atualização", "kiranime_anime_updated"),
)
private val NEXT_YEAR by lazy {
Calendar.getInstance()[Calendar.YEAR] + 1
}
val YEARS = arrayOf(EVERY) + (NEXT_YEAR downTo 1970).map {
Pair(it.toString(), it.toString())
}.toTypedArray()
val SEASONS = arrayOf(
EVERY,
Pair("Inverno", "winter"),
Pair("Primavera", "spring"),
Pair("Verao", "summer"),
Pair("Outono", "fall"),
)
}
}

View file

@ -0,0 +1,41 @@
package eu.kanade.tachiyomi.animeextension.pt.animesotaku
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Bundle
import android.util.Log
import kotlin.system.exitProcess
/**
* Springboard that accepts https://animesotaku.me/anime/<item> intents
* and redirects them to the main Aniyomi process.
*/
class AnimesOtakuUrlActivity : Activity() {
private val tag = javaClass.simpleName
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val pathSegments = intent?.data?.pathSegments
if (pathSegments != null && pathSegments.size > 1) {
val item = pathSegments[1]
val mainIntent = Intent().apply {
action = "eu.kanade.tachiyomi.ANIMESEARCH"
putExtra("query", "${AnimesOtaku.PREFIX_SEARCH}$item")
putExtra("filter", packageName)
}
try {
startActivity(mainIntent)
} catch (e: ActivityNotFoundException) {
Log.e(tag, e.toString())
}
} else {
Log.e(tag, "could not parse uri from intent $intent")
}
finish()
exitProcess(0)
}
}

View file

@ -0,0 +1,105 @@
package eu.kanade.tachiyomi.animeextension.pt.animesotaku.dto
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonPrimitive
@Serializable
data class SearchResponseDto(val data: String, val pages: Int)
@Serializable
data class PostDto(
val post_title: String,
val post_content: String? = null,
)
@Serializable
data class ThumbnailDto(private val featured_url: JsonPrimitive) {
val url = if (featured_url.isString) featured_url.content else null
}
@Serializable
data class TaxonomyDto(val taxonomy: String = "", val terms: List<Int> = emptyList())
@Serializable
data class SearchRequestDto(
val single: SingleDto,
val keyword: String,
val query: String,
val tax: List<TaxonomyDto>,
)
@Serializable
data class SingleDto(
val paged: Int,
@SerialName("meta_key")
val key: String?,
val order: String,
val orderBy: String,
val season: String?,
val year: String?,
)
@Serializable
data class FullAnimeDto(
val url: String,
val post: PostDto,
val meta: MetaDto,
private val taxonomies: TaxonomiesDto,
private val image: String = "",
private val images: ThumbnailDto? = null,
) {
val thumbnail = image.ifEmpty { images?.url }
val title = post.post_title
@Serializable
data class MetaDto(
val native: String? = null,
val synonyms: String? = null,
val score: String? = null,
val premiered: String? = null,
val aired: String? = null,
val duration: String? = null,
val rate: String? = null,
)
@Serializable
data class TaxonomiesDto(
val producer: List<ItemDto> = emptyList(),
val studio: List<ItemDto> = emptyList(),
val genre: List<ItemDto> = emptyList(),
)
val genres = taxonomies.genre.parseItems()
val studios = taxonomies.studio.parseItems()
val producers = taxonomies.producer.parseItems()
}
@Serializable
data class ItemDto(val name: String)
private fun List<ItemDto>.parseItems() = joinToString { it.name }.takeIf(String::isNotBlank)
@Serializable
data class AnimeEpisodes(val episodes: List<EpisodeDto>)
@Serializable
data class EpisodeDto(
val url: String,
val post: EpisodePostDto,
val meta: EpisodeMetaDto,
) {
@Serializable
data class EpisodeMetaDto(val number: String)
@Serializable
data class EpisodePostDto(val post_modified_gmt: String? = null)
val date = post.post_modified_gmt ?: ""
}
@Serializable
data class SourcesDto(val sourceList: Map<String, String>)
@Serializable
data class VideoDto(val videoSrc: String)