Skip to content

Commit

Permalink
fix(pt/anitube): Fixed pt/Anitube and pt/HinataSoul sources (#167)
Browse files Browse the repository at this point in the history
  • Loading branch information
WebDitto authored Aug 22, 2024
1 parent 5ddb5f0 commit 36ebc19
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 43 deletions.
2 changes: 1 addition & 1 deletion src/pt/anitube/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
ext {
extName = 'Anitube'
extClass = '.Anitube'
extVersionCode = 15
extVersionCode = 16
}

apply from: "$rootDir/common.gradle"
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class Anitube : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
}

override fun headersBuilder() = super.headersBuilder()
.add("Referer", baseUrl)
.add("Referer", "$baseUrl/")
.add("Accept-Language", ACCEPT_LANGUAGE)

// ============================== Popular ===============================
Expand Down Expand Up @@ -78,7 +78,11 @@ class Anitube : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun latestUpdatesNextPageSelector() = popularAnimeNextPageSelector()

// =============================== Search ===============================
override suspend fun getSearchAnime(page: Int, query: String, filters: AnimeFilterList): AnimesPage {
override suspend fun getSearchAnime(
page: Int,
query: String,
filters: AnimeFilterList,
): AnimesPage {
return if (query.startsWith(PREFIX_SEARCH)) {
val path = query.removePrefix(PREFIX_SEARCH)
client.newCall(GET("$baseUrl/$path"))
Expand All @@ -97,6 +101,7 @@ class Anitube : ConfigurableAnimeSource, ParsedAnimeHttpSource() {

return AnimesPage(listOf(details), false)
}

override fun getFilterList(): AnimeFilterList = AnitubeFilters.FILTER_LIST

override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
Expand All @@ -108,7 +113,14 @@ class Anitube : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val char = params.initialChar
when {
season.isNotBlank() -> "$baseUrl/temporada/$season/$year"
genre.isNotBlank() -> "$baseUrl/genero/$genre/page/$page/${char.replace("todos", "")}"
genre.isNotBlank() ->
"$baseUrl/genero/$genre/page/$page/${
char.replace(
"todos",
"",
)
}"

else -> "$baseUrl/anime/page/$page/letra/$char"
}
} else {
Expand Down Expand Up @@ -176,7 +188,9 @@ class Anitube : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
}

// ============================ Video Links =============================
override fun videoListParse(response: Response) = AnitubeExtractor.getVideoList(response, headers, client)
private val extractor by lazy { AnitubeExtractor(headers, client) }

override fun videoListParse(response: Response) = extractor.getVideoList(response)
override fun videoListSelector() = throw UnsupportedOperationException()
override fun videoFromElement(element: Element) = throw UnsupportedOperationException()
override fun videoUrlParse(document: Document) = throw UnsupportedOperationException()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.animeextension.pt.anitube.extractors

import android.util.Log
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
Expand All @@ -8,36 +9,35 @@ import okhttp3.FormBody
import okhttp3.Headers
import okhttp3.OkHttpClient
import okhttp3.Response
import java.util.Calendar
import java.util.Date

object AnitubeExtractor {
fun getVideoList(response: Response, headers: Headers, client: OkHttpClient): List<Video> {
val doc = response.asJsoup()
val hasFHD = doc.selectFirst("div.abaItem:contains(FULLHD)") != null
val serverUrl = doc.selectFirst("meta[itemprop=contentURL]")!!
.attr("content")
.replace("cdn1", "cdn3")
val thumbUrl = doc.selectFirst("meta[itemprop=thumbnailUrl]")!!
.attr("content")
val type = serverUrl.split("/").get(3)
val qualities = listOfNotNull("SD", "HD", if (hasFHD) "FULLHD" else null)
val paths = listOf("appsd", "apphd").let {
if (type.endsWith("2")) {
it.map { path -> path + "2" }
} else {
it
}
} + listOf("appfullhd")
class AnitubeExtractor(private val headers: Headers, private val client: OkHttpClient) {

private var authCodeCache: String = ""
private var authCodeDate: Date = Calendar.getInstance().getTime()

private fun getAuthCode(serverUrl: String, thumbUrl: String): String {
val duration = Calendar.getInstance().getTime().time - authCodeDate.time

// check the authCode in cache for 1 hour
if (authCodeCache.isNotBlank() && duration < 60 * 60 * 1000) {
Log.d("AnitubeExtractor", "Using authCode from cache")
return authCodeCache
}

Log.d("AnitubeExtractor", "Fetching new authCode")
val videoName = serverUrl.split('/').last()

val adsUrl =
client.newCall(GET("https://www.anitube.vip/playerricas.php?name=apphd/$videoName&img=$thumbUrl&url=$serverUrl"))
client.newCall(GET("$SITE_URL/playerricas.php?name=apphd/$videoName&img=$thumbUrl&url=$serverUrl"))
.execute()
.body.string()
.substringAfter("ADS_URL")
.substringAfter('"')
.substringBefore('"')

Log.d("AnitubeExtractor", "ADS URL: $adsUrl")
val adsContent = client.newCall(GET(adsUrl)).execute().body.string()

val body = FormBody.Builder()
Expand All @@ -46,24 +46,81 @@ object AnitubeExtractor {
.add("ad", adsContent)
.build()

val publicidade = client.newCall(POST("https://ads.anitube.vip/", body = body))
.execute()
.body.string()
.substringAfter("\"publicidade\"")
.substringAfter('"')
.substringBefore('"')
val newHeaders = headers.newBuilder()
.set("Referer", SITE_URL)
.add("Accept", "*/*")
.add("Cache-Control", "no-cache")
.add("Pragma", "no-cache")
.add("Connection", "keep-alive")
.add("Sec-Fetch-Dest", "empty")
.add("Sec-Fetch-Mode", "cors")
.add("Sec-Fetch-Site", "same-site")
.build()

val authCode = client.newCall(GET("https://ads.anitube.vip/?token=$publicidade"))
.execute()
.body.string()
.substringAfter("\"publicidade\"")
.substringAfter('"')
.substringBefore('"')
val publicidade =
client.newCall(POST("$ADS_URL/", headers = newHeaders, body = body))
.execute()
.body.string()
.substringAfter("\"publicidade\"")
.substringAfter('"')
.substringBefore('"')

if (publicidade.isBlank()) {
Log.e("AnitubeExtractor", "Failed to fetch \"publicidade\" code")
return ""
}

authCodeCache =
client.newCall(
GET(
"$ADS_URL/?token=$publicidade",
headers = newHeaders,
),
)
.execute()
.body.string()
.substringAfter("\"publicidade\"")
.substringAfter('"')
.substringBefore('"')

if (authCodeCache.isBlank()) {
Log.e("AnitubeExtractor", "Failed to fetch auth code")
} else {
Log.d("AnitubeExtractor", "Auth code fetched successfully")
}

return authCodeCache
}

fun getVideoList(response: Response): List<Video> {
val doc = response.asJsoup()
val hasFHD = doc.selectFirst("div.abaItem:contains(FULLHD)") != null
val serverUrl = doc.selectFirst("meta[itemprop=contentURL]")!!
.attr("content")
.replace("cdn1", "cdn3")
val thumbUrl = doc.selectFirst("meta[itemprop=thumbnailUrl]")!!
.attr("content")
val type = serverUrl.split("/").get(3)
val qualities = listOfNotNull("SD", "HD", if (hasFHD) "FULLHD" else null)
val paths = listOf("appsd", "apphd").let {
if (type.endsWith("2")) {
it.map { path -> path + "2" }
} else {
it
}
} + listOf("appfullhd")

val authCode = getAuthCode(serverUrl, thumbUrl)

return qualities.mapIndexed { index, quality ->
val path = paths[index]
val url = serverUrl.replace(type, path) + authCode
Video(url, quality, url, headers = headers)
}.reversed()
}

companion object {
val ADS_URL = "https://ads.anitube.vip"
val SITE_URL = "https://www.anitube.vip"
}
}
2 changes: 1 addition & 1 deletion src/pt/hinatasoul/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
ext {
extName = 'Hinata Soul'
extClass = '.HinataSoul'
extVersionCode = 5
extVersionCode = 6
}

apply from: "$rootDir/common.gradle"
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ class HinataSoul : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
}

// ============================ Video Links =============================
private val extractor by lazy { HinataSoulExtractor(headers) }
private val extractor by lazy { HinataSoulExtractor(headers, client) }

override fun videoListParse(response: Response) = extractor.getVideoList(response)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,126 @@
package eu.kanade.tachiyomi.animeextension.pt.hinatasoul.extractors

import android.util.Log
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.FormBody
import okhttp3.Headers
import okhttp3.OkHttpClient
import okhttp3.Response
import java.util.Calendar
import java.util.Date

class HinataSoulExtractor(private val headers: Headers) {
class HinataSoulExtractor(private val headers: Headers, private val client: OkHttpClient) {

private var authCodeCache: String = ""
private var authCodeDate: Date = Calendar.getInstance().getTime()

private fun getAuthCode(serverUrl: String, thumbUrl: String): String {
val duration = Calendar.getInstance().getTime().time - authCodeDate.time

// check the authCode in cache for 1 hour
if (authCodeCache.isNotBlank() && duration < 60 * 60 * 1000) {
Log.d("HinataSoulExtractor", "Using authCode from cache")
return authCodeCache
}

Log.d("HinataSoulExtractor", "Fetching new authCode")
val videoName = serverUrl.split('/').last()

val adsUrl =
client.newCall(GET("$SITE_URL/playerricas.php?name=apphd/$videoName&img=$thumbUrl&url=$serverUrl"))
.execute()
.body.string()
.substringAfter("ADS_URL")
.substringAfter('"')
.substringBefore('"')

Log.d("HinataSoulExtractor", "ADS URL: $adsUrl")
val adsContent = client.newCall(GET(adsUrl)).execute().body.string()

val body = FormBody.Builder()
.add("category", "client")
.add("type", "premium")
.add("ad", adsContent)
.build()

val newHeaders = headers.newBuilder()
.set("Referer", SITE_URL)
.add("Accept", "*/*")
.add("Cache-Control", "no-cache")
.add("Pragma", "no-cache")
.add("Connection", "keep-alive")
.add("Sec-Fetch-Dest", "empty")
.add("Sec-Fetch-Mode", "cors")
.add("Sec-Fetch-Site", "same-site")
.build()

val publicidade =
client.newCall(POST("$ADS_URL/", headers = newHeaders, body = body))
.execute()
.body.string()
.substringAfter("\"publicidade\"")
.substringAfter('"')
.substringBefore('"')

if (publicidade.isBlank()) {
Log.e("HinataSoulExtractor", "Failed to fetch \"publicidade\" code")
return ""
}

authCodeCache =
client.newCall(
GET(
"$ADS_URL/?token=$publicidade",
headers = newHeaders,
),
)
.execute()
.body.string()
.substringAfter("\"publicidade\"")
.substringAfter('"')
.substringBefore('"')

if (authCodeCache.isBlank()) {
Log.e("HinataSoulExtractor", "Failed to fetch auth code")
} else {
Log.d("HinataSoulExtractor", "Auth code fetched successfully")
}

return authCodeCache
}

fun getVideoList(response: Response): List<Video> {
val doc = response.asJsoup()
val hasFHD = doc.selectFirst("div.abaItem:contains(FULLHD)") != null
val serverUrl = doc.selectFirst("meta[itemprop=contentURL]")!!
.attr("content")
.replace("cdn1", "cdn3")
val type = serverUrl.split('/').get(3)
val qualities = listOfNotNull("SD", "HD", "FULLHD".takeIf { hasFHD })
val thumbUrl = doc.selectFirst("meta[itemprop=thumbnailUrl]")!!
.attr("content")
val type = serverUrl.split("/").get(3)
val qualities = listOfNotNull("SD", "HD", if (hasFHD) "FULLHD" else null)
val paths = listOf("appsd", "apphd").let {
if (type.endsWith("2")) {
it.map { path -> path + "2" }
} else {
it
}
} + listOfNotNull("appfullhd".takeIf { hasFHD })
} + listOf("appfullhd")

val authCode = getAuthCode(serverUrl, thumbUrl)

return qualities.mapIndexed { index, quality ->
val path = paths[index]
val url = serverUrl.replace(type, path)
val url = serverUrl.replace(type, path) + authCode
Video(url, quality, url, headers = headers)
}.reversed()
}

companion object {
val ADS_URL = "https://ads.anitube.vip"
val SITE_URL = "https://www.anitube.vip"
}
}

2 comments on commit 36ebc19

@Olintopinto
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error 403 is still happening to me ;(

@vtrsz
Copy link

@vtrsz vtrsz commented on 36ebc19 Aug 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error 403 is still happening to me ;(
I was bypassing this error opening the web view, close it and open the episode.

Another error is showing to me
"Expected url scheme 'http' or 'https', no scheme ....

As the error says, theres no prefix on url scheme, or is not getting the correct url scheme.

Please sign in to comment.