remove 2dgirls.tech and add gogoanime
This commit is contained in:
@ -1,7 +1,7 @@
|
|||||||
// used both in common.gradle and themesources library
|
// used both in common.gradle and themesources library
|
||||||
dependencies {
|
dependencies {
|
||||||
// Lib 1.3, but using specific commit so we don't need to bump up the version
|
// Lib 1.3, but using specific commit so we don't need to bump up the version
|
||||||
compileOnly "com.github.jmir1:extensions-lib:92b69d1"
|
compileOnly "com.github.jmir1:extensions-lib:6467320"
|
||||||
|
|
||||||
// These are provided by the app itself
|
// These are provided by the app itself
|
||||||
compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||||
|
@ -2,10 +2,10 @@ apply plugin: 'com.android.application'
|
|||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
extName = '2dgirls.tech'
|
extName = 'Gogoanime'
|
||||||
pkgNameSuffix = 'en.twodgirlstech'
|
pkgNameSuffix = 'en.gogoanime'
|
||||||
extClass = '.TwoDGirlsTech'
|
extClass = '.GogoAnime'
|
||||||
extVersionCode = 12
|
extVersionCode = 1
|
||||||
libVersion = '11'
|
libVersion = '11'
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
@ -0,0 +1,144 @@
|
|||||||
|
package eu.kanade.tachiyomi.animeextension.en.gogoanime
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.Link
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
||||||
|
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
||||||
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
|
import eu.kanade.tachiyomi.network.await
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
import org.jsoup.nodes.Document
|
||||||
|
import org.jsoup.nodes.Element
|
||||||
|
import rx.Observable
|
||||||
|
|
||||||
|
class GogoAnime : ParsedAnimeHttpSource() {
|
||||||
|
|
||||||
|
override val name = "Gogoanime"
|
||||||
|
|
||||||
|
override val baseUrl = "https://www1.gogoanime.ai"
|
||||||
|
|
||||||
|
override val lang = "en"
|
||||||
|
|
||||||
|
override val supportsLatest = true
|
||||||
|
|
||||||
|
override fun popularAnimeSelector(): String = "div.img a"
|
||||||
|
|
||||||
|
override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/popular.html?page=$page")
|
||||||
|
|
||||||
|
override fun popularAnimeFromElement(element: Element): SAnime {
|
||||||
|
val anime = SAnime.create()
|
||||||
|
anime.setUrlWithoutDomain(element.attr("href"))
|
||||||
|
anime.thumbnail_url = element.select("img").first().attr("src")
|
||||||
|
anime.title = element.attr("title")
|
||||||
|
return anime
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popularAnimeNextPageSelector(): String = "ul.pagination-list li:last-child:not(.selected)"
|
||||||
|
|
||||||
|
override fun episodeListSelector() = "ul#episode_page li a"
|
||||||
|
|
||||||
|
override fun episodeListParse(response: Response): List<SEpisode> {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
val totalEpisodes = document.select(episodeListSelector()).last().attr("ep_end")
|
||||||
|
val id = document.select("input#movie_id").attr("value")
|
||||||
|
return runBlocking { episodesRequest(totalEpisodes, id) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun episodesRequest(totalEpisodes: String, id: String): List<SEpisode> {
|
||||||
|
val request = GET("https://ajax.gogo-load.com/ajax/load-list-episode?ep_start=0&ep_end=$totalEpisodes&id=$id")
|
||||||
|
val epResponse = client.newCall(request)
|
||||||
|
.await()
|
||||||
|
val document = epResponse.asJsoup()
|
||||||
|
return document.select("a").map { episodeFromElement(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fetchEpisodeLink(episode: SEpisode): Observable<List<Link>> {
|
||||||
|
return client.newCall(GET(baseUrl + episode.url))
|
||||||
|
.asObservableSuccess()
|
||||||
|
.map { response ->
|
||||||
|
runBlocking { linkRequest(response) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun linkRequest(response: Response): List<Link> {
|
||||||
|
val elements = response.asJsoup()
|
||||||
|
val link = elements.select("li.dowloads a").attr("href")
|
||||||
|
val dlResponse = client.newCall(GET(link))
|
||||||
|
.await()
|
||||||
|
val document = dlResponse.asJsoup()
|
||||||
|
return linksFromElement(document.select(episodeLinkSelector()).first())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun episodeFromElement(element: Element): SEpisode {
|
||||||
|
val episode = SEpisode.create()
|
||||||
|
episode.setUrlWithoutDomain(baseUrl + element.attr("href").substringAfter(" "))
|
||||||
|
val ep = element.selectFirst("div.name").ownText().substringAfter(" ")
|
||||||
|
episode.episode_number = ep.toFloat()
|
||||||
|
episode.name = "Episode $ep"
|
||||||
|
episode.date_upload = System.currentTimeMillis()
|
||||||
|
return episode
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun episodeLinkSelector() = "div.mirror_link:has(a[download])"
|
||||||
|
|
||||||
|
override fun linksFromElement(element: Element): List<Link> {
|
||||||
|
val links = mutableListOf<Link>()
|
||||||
|
val linkElements = element.select("a[download]")
|
||||||
|
for (e in linkElements) {
|
||||||
|
val quality = e.text().substringAfter("Download (").replace("P - mp4)", "p")
|
||||||
|
links.add(Link(e.attr("href"), quality))
|
||||||
|
}
|
||||||
|
return links
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun searchAnimeFromElement(element: Element): SAnime {
|
||||||
|
val anime = SAnime.create()
|
||||||
|
anime.setUrlWithoutDomain(element.attr("href"))
|
||||||
|
anime.thumbnail_url = element.select("img").first().attr("src")
|
||||||
|
anime.title = element.attr("title")
|
||||||
|
return anime
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun searchAnimeNextPageSelector(): String = "ul.pagination-list li:last-child:not(.selected)"
|
||||||
|
|
||||||
|
override fun searchAnimeSelector(): String = "div.img a"
|
||||||
|
|
||||||
|
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request = GET("$baseUrl/search.html?keyword=$query&page=$page")
|
||||||
|
|
||||||
|
override fun animeDetailsParse(document: Document): SAnime {
|
||||||
|
val anime = SAnime.create()
|
||||||
|
anime.title = document.select("div.anime_info_body_bg h1").text()
|
||||||
|
anime.genre = document.select("p.type:eq(5) a").joinToString("") { it.text() }
|
||||||
|
anime.description = document.select("p.type:eq(4)").first().ownText()
|
||||||
|
anime.status = parseStatus(document.select("p.type:eq(7) a").text())
|
||||||
|
return anime
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseStatus(statusString: String): Int {
|
||||||
|
return when (statusString) {
|
||||||
|
"Ongoing" -> SAnime.ONGOING
|
||||||
|
"Completed" -> SAnime.COMPLETED
|
||||||
|
else -> SAnime.UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun latestUpdatesNextPageSelector(): String = "ul.pagination-list li:last-child:not(.selected)"
|
||||||
|
|
||||||
|
override fun latestUpdatesFromElement(element: Element): SAnime {
|
||||||
|
val anime = SAnime.create()
|
||||||
|
anime.setUrlWithoutDomain(baseUrl + element.attr("href"))
|
||||||
|
val style = element.select("div.thumbnail-popular").attr("style")
|
||||||
|
anime.thumbnail_url = style.substringAfter("background: url('").substringBefore("');")
|
||||||
|
anime.title = element.attr("title")
|
||||||
|
return anime
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun latestUpdatesRequest(page: Int): Request = GET("https://ajax.gogo-load.com/ajax/page-recent-release-ongoing.html?page=$page&type=1")
|
||||||
|
|
||||||
|
override fun latestUpdatesSelector(): String = "div.added_series_body.popular li a:has(div)"
|
||||||
|
}
|
Binary file not shown.
Before Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 2.7 KiB |
Binary file not shown.
Before Width: | Height: | Size: 6.1 KiB |
Binary file not shown.
Before Width: | Height: | Size: 10 KiB |
Binary file not shown.
Before Width: | Height: | Size: 15 KiB |
Binary file not shown.
Before Width: | Height: | Size: 81 KiB |
@ -1,203 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.animeextension.en.twodgirlstech
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.Link
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.SAnime
|
|
||||||
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
|
||||||
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import okhttp3.Call
|
|
||||||
import okhttp3.Callback
|
|
||||||
import okhttp3.Request
|
|
||||||
import okhttp3.Response
|
|
||||||
import org.json.JSONArray
|
|
||||||
import org.json.JSONObject
|
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import org.jsoup.nodes.Element
|
|
||||||
import rx.Observable
|
|
||||||
import java.io.IOException
|
|
||||||
import java.net.URLEncoder
|
|
||||||
import kotlin.coroutines.resume
|
|
||||||
import kotlin.coroutines.suspendCoroutine
|
|
||||||
|
|
||||||
class TwoDGirlsTech : ParsedAnimeHttpSource() {
|
|
||||||
|
|
||||||
override val name = "2dgirls.tech"
|
|
||||||
|
|
||||||
override val baseUrl = "https://2dgirls.tech"
|
|
||||||
|
|
||||||
override val lang = "en"
|
|
||||||
|
|
||||||
override val supportsLatest = false
|
|
||||||
|
|
||||||
override fun fetchPopularAnime(page: Int): Observable<AnimesPage> {
|
|
||||||
return Observable.just(runBlocking { get(page) })
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun get(page: Int): AnimesPage {
|
|
||||||
var hasNextPage = true
|
|
||||||
val request = GET("$baseUrl/api/popular/$page")
|
|
||||||
val arrayListDetails: ArrayList<SAnime> = ArrayList()
|
|
||||||
return suspendCoroutine<AnimesPage> { continuation ->
|
|
||||||
client.newCall(request).enqueue(object : Callback {
|
|
||||||
override fun onFailure(call: Call, e: IOException) {
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
override fun onResponse(call: Call, response: Response) {
|
|
||||||
val strResponse = response.body!!.string()
|
|
||||||
// creating json object
|
|
||||||
val json = JSONObject(strResponse)
|
|
||||||
// creating json array
|
|
||||||
val jsonArrayInfo: JSONArray = json.getJSONArray("results")
|
|
||||||
val size: Int = jsonArrayInfo.length()
|
|
||||||
for (i in 0 until size) {
|
|
||||||
val anime = SAnime.create()
|
|
||||||
val jsonObjectDetail: JSONObject = jsonArrayInfo.getJSONObject(i)
|
|
||||||
anime.title = jsonObjectDetail.getString("title")
|
|
||||||
anime.thumbnail_url = jsonObjectDetail.getString("image")
|
|
||||||
anime.setUrlWithoutDomain("/api/detailshtml/" + jsonObjectDetail.getString("id"))
|
|
||||||
arrayListDetails.add(anime)
|
|
||||||
}
|
|
||||||
hasNextPage = (arrayListDetails.isNotEmpty())
|
|
||||||
continuation.resume(AnimesPage(arrayListDetails, hasNextPage))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun setDetails(anime: SAnime): SAnime {
|
|
||||||
val request = GET("$baseUrl/api/details/${anime.url.split("/api/detailshtml/").last()}")
|
|
||||||
return suspendCoroutine<SAnime> { continuation ->
|
|
||||||
client.newCall(request).enqueue(object : Callback {
|
|
||||||
override fun onFailure(call: Call, e: IOException) {
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResponse(call: Call, response: Response) {
|
|
||||||
val strResponse = response.body!!.string()
|
|
||||||
// creating json object
|
|
||||||
val json = JSONObject(strResponse)
|
|
||||||
// creating json array
|
|
||||||
val jsonArrayInfo: JSONArray = json.getJSONArray("results")
|
|
||||||
val size: Int = jsonArrayInfo.length()
|
|
||||||
for (i in 0..size - 1) {
|
|
||||||
val jsonObjectDetail: JSONObject = jsonArrayInfo.getJSONObject(i)
|
|
||||||
anime.genre = jsonObjectDetail.getString("genres")
|
|
||||||
when (jsonObjectDetail.getString("status").replace("\\s".toRegex(), "")) {
|
|
||||||
"Ongoing" -> anime.status = SAnime.ONGOING
|
|
||||||
"Completed" -> anime.status = SAnime.COMPLETED
|
|
||||||
}
|
|
||||||
anime.description = jsonObjectDetail.getString("summary")
|
|
||||||
}
|
|
||||||
continuation.resume(anime)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
|
|
||||||
return Observable.just(runBlocking { getSearch(page, query) })
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun getSearch(page: Int, query: String): AnimesPage {
|
|
||||||
var hasNextPage: Boolean
|
|
||||||
val queryEncoded = withContext(Dispatchers.IO) { URLEncoder.encode(query, "utf-8") }
|
|
||||||
val request = GET("$baseUrl/api/search/$queryEncoded/$page")
|
|
||||||
val arrayListDetails: ArrayList<SAnime> = ArrayList()
|
|
||||||
return suspendCoroutine<AnimesPage> { continuation ->
|
|
||||||
client.newCall(request).enqueue(object : Callback {
|
|
||||||
override fun onFailure(call: Call, e: IOException) {
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
override fun onResponse(call: Call, response: Response) {
|
|
||||||
val strResponse = response.body!!.string()
|
|
||||||
// creating json object
|
|
||||||
val json = JSONObject(strResponse)
|
|
||||||
// creating json array
|
|
||||||
val jsonArrayInfo: JSONArray = json.getJSONArray("results")
|
|
||||||
val size: Int = jsonArrayInfo.length()
|
|
||||||
for (i in 0..size - 1) {
|
|
||||||
val anime = SAnime.create()
|
|
||||||
val jsonObjectDetail: JSONObject = jsonArrayInfo.getJSONObject(i)
|
|
||||||
anime.title = jsonObjectDetail.getString("title")
|
|
||||||
anime.thumbnail_url = jsonObjectDetail.getString("image")
|
|
||||||
anime.setUrlWithoutDomain("/api/detailshtml/" + jsonObjectDetail.getString("id"))
|
|
||||||
arrayListDetails.add(anime)
|
|
||||||
}
|
|
||||||
hasNextPage = json.getBoolean("nextpage")
|
|
||||||
continuation.resume(AnimesPage(arrayListDetails, hasNextPage))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun fetchAnimeDetails(anime: SAnime): Observable<SAnime> {
|
|
||||||
return Observable.just(runBlocking { setDetails(anime) })
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun episodeListSelector() = "div[id^=episode-]"
|
|
||||||
|
|
||||||
override fun fetchEpisodeList(anime: SAnime): Observable<List<SEpisode>> {
|
|
||||||
return super.fetchEpisodeList(anime).flatMap { Observable.just(it.reversed()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun episodeFromElement(element: Element): SEpisode {
|
|
||||||
val id = element.id().split(":").last()
|
|
||||||
val episodeNumber = element.id().split("episode-").last().split(":").first()
|
|
||||||
val episode = SEpisode.create()
|
|
||||||
episode.episode_number = episodeNumber.toFloat()
|
|
||||||
episode.name = "Episode $episodeNumber"
|
|
||||||
episode.url = "/api/watchinghtml/$id/$episodeNumber"
|
|
||||||
episode.date_upload = System.currentTimeMillis()
|
|
||||||
return episode
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun episodeLinkSelector() = "body"
|
|
||||||
|
|
||||||
override fun linksFromElement(element: Element): List<Link> {
|
|
||||||
val json = JSONObject(element.text())
|
|
||||||
val jsonArrayInfo: JSONArray = json.getJSONArray("links")
|
|
||||||
val size: Int = jsonArrayInfo.length()
|
|
||||||
val urls = mutableListOf<Link>()
|
|
||||||
for (i in 0..size - 1) {
|
|
||||||
val jsonObjectDetail: JSONObject = jsonArrayInfo.getJSONObject(i)
|
|
||||||
urls.add(Link(jsonObjectDetail.getString("src"), jsonObjectDetail.getString("size")))
|
|
||||||
}
|
|
||||||
return urls
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularAnimeSelector(): String = throw Exception("Not used")
|
|
||||||
|
|
||||||
override fun searchAnimeFromElement(element: Element): SAnime = throw Exception("Not used")
|
|
||||||
|
|
||||||
override fun searchAnimeNextPageSelector(): String? = throw Exception("Not used")
|
|
||||||
|
|
||||||
override fun searchAnimeSelector(): String = throw Exception("Not used")
|
|
||||||
|
|
||||||
override fun popularAnimeRequest(page: Int): Request = throw Exception("Not used")
|
|
||||||
|
|
||||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request = throw Exception("Not used")
|
|
||||||
|
|
||||||
override fun popularAnimeNextPageSelector(): String? = throw Exception("Not used")
|
|
||||||
|
|
||||||
override fun popularAnimeFromElement(element: Element): SAnime = throw Exception("Not used")
|
|
||||||
|
|
||||||
override fun animeDetailsParse(document: Document): SAnime = throw Exception("Not used")
|
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector(): String? = throw Exception("Not used")
|
|
||||||
|
|
||||||
override fun latestUpdatesFromElement(element: Element): SAnime = throw Exception("Not used")
|
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request = throw Exception("Not used")
|
|
||||||
|
|
||||||
override fun latestUpdatesSelector(): String = throw Exception("Not used")
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val baseAltTextUrl = "https://fakeimg.pl/1500x2126/ffffff/000000/?text="
|
|
||||||
const val baseAltTextPostUrl = "&font_size=42&font=museo"
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user