normalize line endings

This commit is contained in:
jmir1 2022-03-04 00:37:09 +01:00
parent 18a40f5c4e
commit 39a16c68b0
11 changed files with 617 additions and 616 deletions

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
* text=auto

178
gradlew.bat vendored
View file

@ -1,89 +1,89 @@
@rem @rem
@rem Copyright 2015 the original author or authors. @rem Copyright 2015 the original author or authors.
@rem @rem
@rem Licensed under the Apache License, Version 2.0 (the "License"); @rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License. @rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at @rem You may obtain a copy of the License at
@rem @rem
@rem https://www.apache.org/licenses/LICENSE-2.0 @rem https://www.apache.org/licenses/LICENSE-2.0
@rem @rem
@rem Unless required by applicable law or agreed to in writing, software @rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS, @rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and @rem See the License for the specific language governing permissions and
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem Gradle startup script for Windows
@rem @rem
@rem ########################################################################## @rem ##########################################################################
@rem Set local scope for the variables with windows NT shell @rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=. if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter. @rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute if "%ERRORLEVEL%" == "0" goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo. echo.
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation. echo location of your Java installation.
goto fail goto fail
:findJavaFromJavaHome :findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute if exist "%JAVA_EXE%" goto execute
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo. echo.
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation. echo location of your Java installation.
goto fail goto fail
:execute :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd if "%ERRORLEVEL%"=="0" goto mainEnd
:fail :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1 exit /b 1
:mainEnd :mainEnd
if "%OS%"=="Windows_NT" endlocal if "%OS%"=="Windows_NT" endlocal
:omega :omega

View file

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest package="eu.kanade.tachiyomi.animeextension" /> <manifest package="eu.kanade.tachiyomi.animeextension" />

View file

@ -1,12 +1,12 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
ext { ext {
extName = 'GenoAnime' extName = 'GenoAnime'
pkgNameSuffix = 'en.genoanime' pkgNameSuffix = 'en.genoanime'
extClass = '.GenoAnime' extClass = '.GenoAnime'
extVersionCode = 8 extVersionCode = 8
libVersion = '12' libVersion = '12'
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -1,12 +1,12 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
ext { ext {
extName = 'Gogoanime' extName = 'Gogoanime'
pkgNameSuffix = 'en.gogoanime' pkgNameSuffix = 'en.gogoanime'
extClass = '.GogoAnime' extClass = '.GogoAnime'
extVersionCode = 30 extVersionCode = 30
libVersion = '12' libVersion = '12'
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View file

@ -1,274 +1,274 @@
package eu.kanade.tachiyomi.animeextension.en.gogoanime package eu.kanade.tachiyomi.animeextension.en.gogoanime
import android.app.Application import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.en.gogoanime.extractors.DoodExtractor import eu.kanade.tachiyomi.animeextension.en.gogoanime.extractors.DoodExtractor
import eu.kanade.tachiyomi.animeextension.en.gogoanime.extractors.GogoCdnExtractor import eu.kanade.tachiyomi.animeextension.en.gogoanime.extractors.GogoCdnExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.SAnime import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.lang.Exception import java.lang.Exception
@ExperimentalSerializationApi @ExperimentalSerializationApi
class GogoAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class GogoAnime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val name = "Gogoanime" override val name = "Gogoanime"
override val baseUrl = "https://gogoanime.fi" override val baseUrl = "https://gogoanime.fi"
override val lang = "en" override val lang = "en"
override val supportsLatest = true override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient override val client: OkHttpClient = network.cloudflareClient
private val json: Json by injectLazy() private val json: Json by injectLazy()
private val preferences: SharedPreferences by lazy { private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
} }
override fun popularAnimeSelector(): String = "div.img a" override fun popularAnimeSelector(): String = "div.img a"
override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/popular.html?page=$page") override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/popular.html?page=$page")
override fun popularAnimeFromElement(element: Element): SAnime { override fun popularAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create() val anime = SAnime.create()
anime.setUrlWithoutDomain(element.attr("href")) anime.setUrlWithoutDomain(element.attr("href"))
anime.thumbnail_url = element.select("img").first().attr("src") anime.thumbnail_url = element.select("img").first().attr("src")
anime.title = element.attr("title") anime.title = element.attr("title")
return anime return anime
} }
override fun popularAnimeNextPageSelector(): String = "ul.pagination-list li:last-child:not(.selected)" override fun popularAnimeNextPageSelector(): String = "ul.pagination-list li:last-child:not(.selected)"
override fun episodeListSelector() = "ul#episode_page li a" override fun episodeListSelector() = "ul#episode_page li a"
override fun episodeListParse(response: Response): List<SEpisode> { override fun episodeListParse(response: Response): List<SEpisode> {
val document = response.asJsoup() val document = response.asJsoup()
val totalEpisodes = document.select(episodeListSelector()).last().attr("ep_end") val totalEpisodes = document.select(episodeListSelector()).last().attr("ep_end")
val id = document.select("input#movie_id").attr("value") val id = document.select("input#movie_id").attr("value")
return episodesRequest(totalEpisodes, id) return episodesRequest(totalEpisodes, id)
} }
private fun episodesRequest(totalEpisodes: String, id: String): List<SEpisode> { private 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", headers) val request = GET("https://ajax.gogo-load.com/ajax/load-list-episode?ep_start=0&ep_end=$totalEpisodes&id=$id", headers)
val epResponse = client.newCall(request).execute() val epResponse = client.newCall(request).execute()
val document = epResponse.asJsoup() val document = epResponse.asJsoup()
return document.select("a").map { episodeFromElement(it) } return document.select("a").map { episodeFromElement(it) }
} }
override fun episodeFromElement(element: Element): SEpisode { override fun episodeFromElement(element: Element): SEpisode {
val episode = SEpisode.create() val episode = SEpisode.create()
episode.setUrlWithoutDomain(baseUrl + element.attr("href").substringAfter(" ")) episode.setUrlWithoutDomain(baseUrl + element.attr("href").substringAfter(" "))
val ep = element.selectFirst("div.name").ownText().substringAfter(" ") val ep = element.selectFirst("div.name").ownText().substringAfter(" ")
episode.episode_number = ep.toFloat() episode.episode_number = ep.toFloat()
episode.name = "Episode $ep" episode.name = "Episode $ep"
episode.date_upload = System.currentTimeMillis() episode.date_upload = System.currentTimeMillis()
return episode return episode
} }
override fun videoListParse(response: Response): List<Video> { override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup() val document = response.asJsoup()
val serverUrl = "https:" + document.select("div.anime_muti_link > ul > li.anime > a") val serverUrl = "https:" + document.select("div.anime_muti_link > ul > li.anime > a")
.attr("data-video") .attr("data-video")
val doodUrl = document.select("div.anime_muti_link > ul > li.doodstream > a") val doodUrl = document.select("div.anime_muti_link > ul > li.doodstream > a")
.attr("data-video") .attr("data-video")
val gogoVideos = GogoCdnExtractor(client, json).videosFromUrl(serverUrl) val gogoVideos = GogoCdnExtractor(client, json).videosFromUrl(serverUrl)
return gogoVideos.ifEmpty { return gogoVideos.ifEmpty {
DoodExtractor(client).videosFromUrl(doodUrl) DoodExtractor(client).videosFromUrl(doodUrl)
} }
} }
override fun videoListSelector() = throw Exception("not used") override fun videoListSelector() = throw Exception("not used")
override fun videoFromElement(element: Element) = throw Exception("not used") override fun videoFromElement(element: Element) = throw Exception("not used")
override fun videoUrlParse(document: Document) = throw Exception("not used") override fun videoUrlParse(document: Document) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "1080") val quality = preferences.getString("preferred_quality", "1080")
if (quality != null) { if (quality != null) {
val newList = mutableListOf<Video>() val newList = mutableListOf<Video>()
var preferred = 0 var preferred = 0
for (video in this) { for (video in this) {
if (video.quality.contains(quality)) { if (video.quality.contains(quality)) {
newList.add(preferred, video) newList.add(preferred, video)
preferred++ preferred++
} else { } else {
newList.add(video) newList.add(video)
} }
} }
return newList return newList
} }
return this return this
} }
override fun searchAnimeFromElement(element: Element): SAnime { override fun searchAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create() val anime = SAnime.create()
anime.setUrlWithoutDomain(element.attr("href")) anime.setUrlWithoutDomain(element.attr("href"))
anime.thumbnail_url = element.select("img").first().attr("src") anime.thumbnail_url = element.select("img").first().attr("src")
anime.title = element.attr("title") anime.title = element.attr("title")
return anime return anime
} }
override fun searchAnimeNextPageSelector(): String = "ul.pagination-list li:last-child:not(.selected)" override fun searchAnimeNextPageSelector(): String = "ul.pagination-list li:last-child:not(.selected)"
override fun searchAnimeSelector(): String = "div.img a" override fun searchAnimeSelector(): String = "div.img a"
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request { override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val filterList = if (filters.isEmpty()) getFilterList() else filters val filterList = if (filters.isEmpty()) getFilterList() else filters
val genreFilter = filterList.find { it is GenreFilter } as GenreFilter val genreFilter = filterList.find { it is GenreFilter } as GenreFilter
return when { return when {
query.isNotBlank() -> GET("$baseUrl/search.html?keyword=$query&page=$page", headers) query.isNotBlank() -> GET("$baseUrl/search.html?keyword=$query&page=$page", headers)
genreFilter.state != 0 -> GET("$baseUrl/genre/${genreFilter.toUriPart()}?page=$page") genreFilter.state != 0 -> GET("$baseUrl/genre/${genreFilter.toUriPart()}?page=$page")
else -> GET("$baseUrl/popular.html?page=$page") else -> GET("$baseUrl/popular.html?page=$page")
} }
} }
override fun animeDetailsParse(document: Document): SAnime { override fun animeDetailsParse(document: Document): SAnime {
val anime = SAnime.create() val anime = SAnime.create()
anime.title = document.select("div.anime_info_body_bg h1").text() anime.title = document.select("div.anime_info_body_bg h1").text()
anime.genre = document.select("p.type:eq(5) a").joinToString("") { it.text() } anime.genre = document.select("p.type:eq(5) a").joinToString("") { it.text() }
anime.description = document.select("p.type:eq(4)").first().ownText() anime.description = document.select("p.type:eq(4)").first().ownText()
anime.status = parseStatus(document.select("p.type:eq(7) a").text()) anime.status = parseStatus(document.select("p.type:eq(7) a").text())
// add alternative name to anime description // add alternative name to anime description
val altName = "Other name(s): " val altName = "Other name(s): "
document.select("p.type:eq(8)").firstOrNull()?.ownText()?.let { document.select("p.type:eq(8)").firstOrNull()?.ownText()?.let {
if (it.isBlank().not()) { if (it.isBlank().not()) {
anime.description = when { anime.description = when {
anime.description.isNullOrBlank() -> altName + it anime.description.isNullOrBlank() -> altName + it
else -> anime.description + "\n\n$altName" + it else -> anime.description + "\n\n$altName" + it
} }
} }
} }
return anime return anime
} }
private fun parseStatus(statusString: String): Int { private fun parseStatus(statusString: String): Int {
return when (statusString) { return when (statusString) {
"Ongoing" -> SAnime.ONGOING "Ongoing" -> SAnime.ONGOING
"Completed" -> SAnime.COMPLETED "Completed" -> SAnime.COMPLETED
else -> SAnime.UNKNOWN else -> SAnime.UNKNOWN
} }
} }
override fun latestUpdatesNextPageSelector(): String = "ul.pagination-list li:last-child:not(.selected)" override fun latestUpdatesNextPageSelector(): String = "ul.pagination-list li:last-child:not(.selected)"
override fun latestUpdatesFromElement(element: Element): SAnime { override fun latestUpdatesFromElement(element: Element): SAnime {
val anime = SAnime.create() val anime = SAnime.create()
anime.setUrlWithoutDomain(baseUrl + element.attr("href")) anime.setUrlWithoutDomain(baseUrl + element.attr("href"))
val style = element.select("div.thumbnail-popular").attr("style") val style = element.select("div.thumbnail-popular").attr("style")
anime.thumbnail_url = style.substringAfter("background: url('").substringBefore("');") anime.thumbnail_url = style.substringAfter("background: url('").substringBefore("');")
anime.title = element.attr("title") anime.title = element.attr("title")
return anime return anime
} }
override fun latestUpdatesRequest(page: Int): Request = override fun latestUpdatesRequest(page: Int): Request =
GET("https://ajax.gogo-load.com/ajax/page-recent-release-ongoing.html?page=$page&type=1", headers) GET("https://ajax.gogo-load.com/ajax/page-recent-release-ongoing.html?page=$page&type=1", headers)
override fun latestUpdatesSelector(): String = "div.added_series_body.popular li a:has(div)" override fun latestUpdatesSelector(): String = "div.added_series_body.popular li a:has(div)"
override fun setupPreferenceScreen(screen: PreferenceScreen) { override fun setupPreferenceScreen(screen: PreferenceScreen) {
val videoQualityPref = ListPreference(screen.context).apply { val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality" key = "preferred_quality"
title = "Preferred quality" title = "Preferred quality"
entries = arrayOf("1080p", "720p", "480p", "360p") entries = arrayOf("1080p", "720p", "480p", "360p")
entryValues = arrayOf("1080", "720", "480", "360") entryValues = arrayOf("1080", "720", "480", "360")
setDefaultValue("1080") setDefaultValue("1080")
summary = "%s" summary = "%s"
setOnPreferenceChangeListener { _, newValue -> setOnPreferenceChangeListener { _, newValue ->
val selected = newValue as String val selected = newValue as String
val index = findIndexOfValue(selected) val index = findIndexOfValue(selected)
val entry = entryValues[index] as String val entry = entryValues[index] as String
preferences.edit().putString(key, entry).commit() preferences.edit().putString(key, entry).commit()
} }
} }
screen.addPreference(videoQualityPref) screen.addPreference(videoQualityPref)
} }
// Filters // Filters
override fun getFilterList(): AnimeFilterList = AnimeFilterList( override fun getFilterList(): AnimeFilterList = AnimeFilterList(
AnimeFilter.Header("Text search ignores filters"), AnimeFilter.Header("Text search ignores filters"),
GenreFilter() GenreFilter()
) )
private class GenreFilter : UriPartFilter( private class GenreFilter : UriPartFilter(
"Genres", "Genres",
arrayOf( arrayOf(
Pair("<select>", ""), Pair("<select>", ""),
Pair("Action", "action"), Pair("Action", "action"),
Pair("Adventure", "adventure"), Pair("Adventure", "adventure"),
Pair("Cars", "cars"), Pair("Cars", "cars"),
Pair("Comedy", "comedy"), Pair("Comedy", "comedy"),
Pair("Crime", "crime"), Pair("Crime", "crime"),
Pair("Dementia", "dementia"), Pair("Dementia", "dementia"),
Pair("Demons", "demons"), Pair("Demons", "demons"),
Pair("Drama", "drama"), Pair("Drama", "drama"),
Pair("Dub", "dub"), Pair("Dub", "dub"),
Pair("Ecchi", "ecchi"), Pair("Ecchi", "ecchi"),
Pair("Family", "family"), Pair("Family", "family"),
Pair("Fantasy", "fantasy"), Pair("Fantasy", "fantasy"),
Pair("Game", "game"), Pair("Game", "game"),
Pair("Harem", "harem"), Pair("Harem", "harem"),
Pair("Historical", "historical"), Pair("Historical", "historical"),
Pair("Horror", "horror"), Pair("Horror", "horror"),
Pair("Josei", "josei"), Pair("Josei", "josei"),
Pair("Kids", "kids"), Pair("Kids", "kids"),
Pair("Magic", "magic"), Pair("Magic", "magic"),
Pair("Martial Arts", "martial-arts"), Pair("Martial Arts", "martial-arts"),
Pair("Mature", "mature"), Pair("Mature", "mature"),
Pair("Mecha", "mecha"), Pair("Mecha", "mecha"),
Pair("Military", "military"), Pair("Military", "military"),
Pair("Music", "music"), Pair("Music", "music"),
Pair("Mystery", "mystery"), Pair("Mystery", "mystery"),
Pair("Parody", "parody"), Pair("Parody", "parody"),
Pair("Police", "police"), Pair("Police", "police"),
Pair("Psychological", "psychological"), Pair("Psychological", "psychological"),
Pair("Romance", "romance"), Pair("Romance", "romance"),
Pair("Samurai", "samurai"), Pair("Samurai", "samurai"),
Pair("School", "school"), Pair("School", "school"),
Pair("Sci-Fi", "sci-fi"), Pair("Sci-Fi", "sci-fi"),
Pair("Seinen", "seinen"), Pair("Seinen", "seinen"),
Pair("Shoujo", "shoujo"), Pair("Shoujo", "shoujo"),
Pair("Shoujo Ai", "shoujo-ai"), Pair("Shoujo Ai", "shoujo-ai"),
Pair("Shounen", "shounen"), Pair("Shounen", "shounen"),
Pair("Shounen Ai", "shounen-ai"), Pair("Shounen Ai", "shounen-ai"),
Pair("Slice of Life", "slice-of-life"), Pair("Slice of Life", "slice-of-life"),
Pair("Space", "space"), Pair("Space", "space"),
Pair("Sports", "sports"), Pair("Sports", "sports"),
Pair("Super Power", "super-power"), Pair("Super Power", "super-power"),
Pair("Supernatural", "supernatural"), Pair("Supernatural", "supernatural"),
Pair("Thriller", "thriller"), Pair("Thriller", "thriller"),
Pair("Vampire", "vampire"), Pair("Vampire", "vampire"),
Pair("Yaoi", "yaoi"), Pair("Yaoi", "yaoi"),
Pair("Yuri", "yuri") Pair("Yuri", "yuri")
) )
) )
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) : private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
AnimeFilter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) { AnimeFilter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second fun toUriPart() = vals[state].second
} }
} }

View file

@ -1,39 +1,39 @@
package eu.kanade.tachiyomi.animeextension.en.gogoanime.extractors package eu.kanade.tachiyomi.animeextension.en.gogoanime.extractors
import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
class DoodExtractor(private val client: OkHttpClient) { class DoodExtractor(private val client: OkHttpClient) {
fun videosFromUrl(serverUrl: String): List<Video> { fun videosFromUrl(serverUrl: String): List<Video> {
val response = client.newCall(GET(serverUrl)).execute() val response = client.newCall(GET(serverUrl)).execute()
val doodTld = serverUrl.substringAfter("https://dood.").substringBefore("/") val doodTld = serverUrl.substringAfter("https://dood.").substringBefore("/")
val content = response.body!!.string() val content = response.body!!.string()
if (!content.contains("'/pass_md5/")) return emptyList() if (!content.contains("'/pass_md5/")) return emptyList()
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',") val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
val token = md5.substringAfterLast("/") val token = md5.substringAfterLast("/")
val randomString = getRandomString() val randomString = getRandomString()
val expiry = System.currentTimeMillis() val expiry = System.currentTimeMillis()
val videoUrlStart = client.newCall( val videoUrlStart = client.newCall(
GET( GET(
"https://dood.$doodTld/pass_md5/$md5", "https://dood.$doodTld/pass_md5/$md5",
Headers.headersOf("referer", serverUrl) Headers.headersOf("referer", serverUrl)
) )
).execute().body!!.string() ).execute().body!!.string()
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry" val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
return listOf(Video(serverUrl, "Doodstream mirror", videoUrl, null, doodHeaders(doodTld))) return listOf(Video(serverUrl, "Doodstream mirror", videoUrl, null, doodHeaders(doodTld)))
} }
private fun getRandomString(length: Int = 10): String { private fun getRandomString(length: Int = 10): String {
val allowedChars = ('A'..'Z') + ('a'..'z') + ('0'..'9') val allowedChars = ('A'..'Z') + ('a'..'z') + ('0'..'9')
return (1..length) return (1..length)
.map { allowedChars.random() } .map { allowedChars.random() }
.joinToString("") .joinToString("")
} }
private fun doodHeaders(tld: String) = Headers.Builder().apply { private fun doodHeaders(tld: String) = Headers.Builder().apply {
add("User-Agent", "Aniyomi") add("User-Agent", "Aniyomi")
add("Referer", "https://dood.$tld/") add("Referer", "https://dood.$tld/")
}.build() }.build()
} }

View file

@ -1,88 +1,88 @@
package eu.kanade.tachiyomi.animeextension.en.nineanime; package eu.kanade.tachiyomi.animeextension.en.nineanime;
public class JSONUtil { public class JSONUtil {
public static String escape(String input) { public static String escape(String input) {
StringBuilder output = new StringBuilder(); StringBuilder output = new StringBuilder();
for(int i=0; i<input.length(); i++) { for(int i=0; i<input.length(); i++) {
char ch = input.charAt(i); char ch = input.charAt(i);
int chx = (int) ch; int chx = (int) ch;
// let's not put any nulls in our strings // let's not put any nulls in our strings
assert(chx != 0); assert(chx != 0);
if(ch == '\n') { if(ch == '\n') {
output.append("\\n"); output.append("\\n");
} else if(ch == '\t') { } else if(ch == '\t') {
output.append("\\t"); output.append("\\t");
} else if(ch == '\r') { } else if(ch == '\r') {
output.append("\\r"); output.append("\\r");
} else if(ch == '\\') { } else if(ch == '\\') {
output.append("\\\\"); output.append("\\\\");
} else if(ch == '"') { } else if(ch == '"') {
output.append("\\\""); output.append("\\\"");
} else if(ch == '\b') { } else if(ch == '\b') {
output.append("\\b"); output.append("\\b");
} else if(ch == '\f') { } else if(ch == '\f') {
output.append("\\f"); output.append("\\f");
} else if(chx >= 0x10000) { } else if(chx >= 0x10000) {
assert false : "Java stores as u16, so it should never give us a character that's bigger than 2 bytes. It literally can't."; assert false : "Java stores as u16, so it should never give us a character that's bigger than 2 bytes. It literally can't.";
} else if(chx > 127) { } else if(chx > 127) {
output.append(String.format("\\u%04x", chx)); output.append(String.format("\\u%04x", chx));
} else { } else {
output.append(ch); output.append(ch);
} }
} }
return output.toString(); return output.toString();
} }
public static String unescape(String input) { public static String unescape(String input) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
int i = 0; int i = 0;
while (i < input.length()) { while (i < input.length()) {
char delimiter = input.charAt(i); i++; // consume letter or backslash char delimiter = input.charAt(i); i++; // consume letter or backslash
if(delimiter == '\\' && i < input.length()) { if(delimiter == '\\' && i < input.length()) {
// consume first after backslash // consume first after backslash
char ch = input.charAt(i); i++; char ch = input.charAt(i); i++;
if(ch == '\\' || ch == '/' || ch == '"' || ch == '\'') { if(ch == '\\' || ch == '/' || ch == '"' || ch == '\'') {
builder.append(ch); builder.append(ch);
} }
else if(ch == 'n') builder.append('\n'); else if(ch == 'n') builder.append('\n');
else if(ch == 'r') builder.append('\r'); else if(ch == 'r') builder.append('\r');
else if(ch == 't') builder.append('\t'); else if(ch == 't') builder.append('\t');
else if(ch == 'b') builder.append('\b'); else if(ch == 'b') builder.append('\b');
else if(ch == 'f') builder.append('\f'); else if(ch == 'f') builder.append('\f');
else if(ch == 'u') { else if(ch == 'u') {
StringBuilder hex = new StringBuilder(); StringBuilder hex = new StringBuilder();
// expect 4 digits // expect 4 digits
if (i+4 > input.length()) { if (i+4 > input.length()) {
throw new RuntimeException("Not enough unicode digits! "); throw new RuntimeException("Not enough unicode digits! ");
} }
for (char x : input.substring(i, i + 4).toCharArray()) { for (char x : input.substring(i, i + 4).toCharArray()) {
if(!Character.isLetterOrDigit(x)) { if(!Character.isLetterOrDigit(x)) {
throw new RuntimeException("Bad character in unicode escape."); throw new RuntimeException("Bad character in unicode escape.");
} }
hex.append(Character.toLowerCase(x)); hex.append(Character.toLowerCase(x));
} }
i+=4; // consume those four digits. i+=4; // consume those four digits.
int code = Integer.parseInt(hex.toString(), 16); int code = Integer.parseInt(hex.toString(), 16);
builder.append((char) code); builder.append((char) code);
} else { } else {
throw new RuntimeException("Illegal escape sequence: \\"+ch); throw new RuntimeException("Illegal escape sequence: \\"+ch);
} }
} else { // it's not a backslash, or it's the last character. } else { // it's not a backslash, or it's the last character.
builder.append(delimiter); builder.append(delimiter);
} }
} }
return builder.toString(); return builder.toString();
} }
} }

View file

@ -1,88 +1,88 @@
package eu.kanade.tachiyomi.animeextension.en.zoro; package eu.kanade.tachiyomi.animeextension.en.zoro;
public class JSONUtil { public class JSONUtil {
public static String escape(String input) { public static String escape(String input) {
StringBuilder output = new StringBuilder(); StringBuilder output = new StringBuilder();
for(int i=0; i<input.length(); i++) { for(int i=0; i<input.length(); i++) {
char ch = input.charAt(i); char ch = input.charAt(i);
int chx = (int) ch; int chx = (int) ch;
// let's not put any nulls in our strings // let's not put any nulls in our strings
assert(chx != 0); assert(chx != 0);
if(ch == '\n') { if(ch == '\n') {
output.append("\\n"); output.append("\\n");
} else if(ch == '\t') { } else if(ch == '\t') {
output.append("\\t"); output.append("\\t");
} else if(ch == '\r') { } else if(ch == '\r') {
output.append("\\r"); output.append("\\r");
} else if(ch == '\\') { } else if(ch == '\\') {
output.append("\\\\"); output.append("\\\\");
} else if(ch == '"') { } else if(ch == '"') {
output.append("\\\""); output.append("\\\"");
} else if(ch == '\b') { } else if(ch == '\b') {
output.append("\\b"); output.append("\\b");
} else if(ch == '\f') { } else if(ch == '\f') {
output.append("\\f"); output.append("\\f");
} else if(chx >= 0x10000) { } else if(chx >= 0x10000) {
assert false : "Java stores as u16, so it should never give us a character that's bigger than 2 bytes. It literally can't."; assert false : "Java stores as u16, so it should never give us a character that's bigger than 2 bytes. It literally can't.";
} else if(chx > 127) { } else if(chx > 127) {
output.append(String.format("\\u%04x", chx)); output.append(String.format("\\u%04x", chx));
} else { } else {
output.append(ch); output.append(ch);
} }
} }
return output.toString(); return output.toString();
} }
public static String unescape(String input) { public static String unescape(String input) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
int i = 0; int i = 0;
while (i < input.length()) { while (i < input.length()) {
char delimiter = input.charAt(i); i++; // consume letter or backslash char delimiter = input.charAt(i); i++; // consume letter or backslash
if(delimiter == '\\' && i < input.length()) { if(delimiter == '\\' && i < input.length()) {
// consume first after backslash // consume first after backslash
char ch = input.charAt(i); i++; char ch = input.charAt(i); i++;
if(ch == '\\' || ch == '/' || ch == '"' || ch == '\'') { if(ch == '\\' || ch == '/' || ch == '"' || ch == '\'') {
builder.append(ch); builder.append(ch);
} }
else if(ch == 'n') builder.append('\n'); else if(ch == 'n') builder.append('\n');
else if(ch == 'r') builder.append('\r'); else if(ch == 'r') builder.append('\r');
else if(ch == 't') builder.append('\t'); else if(ch == 't') builder.append('\t');
else if(ch == 'b') builder.append('\b'); else if(ch == 'b') builder.append('\b');
else if(ch == 'f') builder.append('\f'); else if(ch == 'f') builder.append('\f');
else if(ch == 'u') { else if(ch == 'u') {
StringBuilder hex = new StringBuilder(); StringBuilder hex = new StringBuilder();
// expect 4 digits // expect 4 digits
if (i+4 > input.length()) { if (i+4 > input.length()) {
throw new RuntimeException("Not enough unicode digits! "); throw new RuntimeException("Not enough unicode digits! ");
} }
for (char x : input.substring(i, i + 4).toCharArray()) { for (char x : input.substring(i, i + 4).toCharArray()) {
if(!Character.isLetterOrDigit(x)) { if(!Character.isLetterOrDigit(x)) {
throw new RuntimeException("Bad character in unicode escape."); throw new RuntimeException("Bad character in unicode escape.");
} }
hex.append(Character.toLowerCase(x)); hex.append(Character.toLowerCase(x));
} }
i+=4; // consume those four digits. i+=4; // consume those four digits.
int code = Integer.parseInt(hex.toString(), 16); int code = Integer.parseInt(hex.toString(), 16);
builder.append((char) code); builder.append((char) code);
} else { } else {
throw new RuntimeException("Illegal escape sequence: \\"+ch); throw new RuntimeException("Illegal escape sequence: \\"+ch);
} }
} else { // it's not a backslash, or it's the last character. } else { // it's not a backslash, or it's the last character.
builder.append(delimiter); builder.append(delimiter);
} }
} }
return builder.toString(); return builder.toString();
} }
} }

View file

@ -1,2 +1,2 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest package="eu.kanade.tachiyomi.animeextension" /> <manifest package="eu.kanade.tachiyomi.animeextension" />

View file

@ -1,12 +1,12 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
ext { ext {
extName = 'OtakuDesu' extName = 'OtakuDesu'
pkgNameSuffix = 'id.otakudesu' pkgNameSuffix = 'id.otakudesu'
extClass = '.OtakuDesu' extClass = '.OtakuDesu'
extVersionCode = 10 extVersionCode = 10
libVersion = '12' libVersion = '12'
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"