ufdub: New UA extension (#1268)
2
src/uk/ufdub/AndroidManifest.xml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest package="eu.kanade.tachiyomi.animeextension" />
|
12
src/uk/ufdub/build.gradle
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
|
ext {
|
||||||
|
extName = 'UFDub'
|
||||||
|
pkgNameSuffix = 'uk.ufdub'
|
||||||
|
extClass = '.UFDub'
|
||||||
|
extVersionCode = 1
|
||||||
|
libVersion = '13'
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$rootDir/common.gradle"
|
BIN
src/uk/ufdub/ic_launcher-playstore.png
Normal file
After Width: | Height: | Size: 79 KiB |
74
src/uk/ufdub/res/drawable/ic_launcher_background.xml
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector
|
||||||
|
android:height="108dp"
|
||||||
|
android:width="108dp"
|
||||||
|
android:viewportHeight="108"
|
||||||
|
android:viewportWidth="108"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#3DDC84"
|
||||||
|
android:pathData="M0,0h108v108h-108z"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M9,0L9,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,0L19,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M29,0L29,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M39,0L39,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M49,0L49,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M59,0L59,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M69,0L69,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M79,0L79,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M89,0L89,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M99,0L99,108"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,9L108,9"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,19L108,19"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,29L108,29"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,39L108,39"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,49L108,49"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,59L108,59"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,69L108,69"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,79L108,79"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,89L108,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M0,99L108,99"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,29L89,29"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,39L89,39"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,49L89,49"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,59L89,59"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,69L89,69"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M19,79L89,79"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M29,19L29,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M39,19L39,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M49,19L49,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M59,19L59,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M69,19L69,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
<path android:fillColor="#00000000" android:pathData="M79,19L79,89"
|
||||||
|
android:strokeColor="#33FFFFFF" android:strokeWidth="0.8"/>
|
||||||
|
</vector>
|
5
src/uk/ufdub/res/mipmap-anydpi-v26/ic_launcher.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
5
src/uk/ufdub/res/mipmap-anydpi-v26/ic_launcher_round.xml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
BIN
src/uk/ufdub/res/mipmap-hdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
src/uk/ufdub/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 6.9 KiB |
BIN
src/uk/ufdub/res/mipmap-hdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
src/uk/ufdub/res/mipmap-mdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
src/uk/ufdub/res/mipmap-mdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
src/uk/ufdub/res/mipmap-mdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
src/uk/ufdub/res/mipmap-xhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 4.3 KiB |
BIN
src/uk/ufdub/res/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
src/uk/ufdub/res/mipmap-xhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 7.9 KiB |
BIN
src/uk/ufdub/res/mipmap-xxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 8.2 KiB |
BIN
src/uk/ufdub/res/mipmap-xxhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
src/uk/ufdub/res/mipmap-xxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
src/uk/ufdub/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
src/uk/ufdub/res/mipmap-xxxhdpi/ic_launcher_foreground.png
Normal file
After Width: | Height: | Size: 33 KiB |
BIN
src/uk/ufdub/res/mipmap-xxxhdpi/ic_launcher_round.png
Normal file
After Width: | Height: | Size: 22 KiB |
4
src/uk/ufdub/res/values/ic_launcher_background.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="ic_launcher_background">#F8F3F7</color>
|
||||||
|
</resources>
|
@ -0,0 +1,160 @@
|
|||||||
|
package eu.kanade.tachiyomi.animeextension.uk.ufdub
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
import android.util.Log
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
|
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
|
||||||
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.network.POST
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import okhttp3.FormBody
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
import org.jsoup.nodes.Document
|
||||||
|
import org.jsoup.nodes.Element
|
||||||
|
import rx.Observable
|
||||||
|
|
||||||
|
class UFDub : ParsedAnimeHttpSource() {
|
||||||
|
|
||||||
|
override val lang = "uk"
|
||||||
|
override val name = "UFDub"
|
||||||
|
override val supportsLatest = true
|
||||||
|
private val animeSelector = "div.short"
|
||||||
|
private val nextPageSelector = "div.pagi-nav a"
|
||||||
|
|
||||||
|
override val baseUrl = "https://ufdub.com/anime"
|
||||||
|
private val baseUrlWithoutAnime = "https://ufdub.com"
|
||||||
|
|
||||||
|
override val client: OkHttpClient = network.client
|
||||||
|
|
||||||
|
// =========================== Anime Details ============================
|
||||||
|
|
||||||
|
override fun animeDetailsParse(document: Document): SAnime {
|
||||||
|
val anime = SAnime.create()
|
||||||
|
|
||||||
|
val someInfo = document.select("div.full-desc")
|
||||||
|
|
||||||
|
anime.thumbnail_url = baseUrlWithoutAnime + document.select("div.f-poster img").attr("src")
|
||||||
|
anime.title = document.select("h1.top-title").text()
|
||||||
|
anime.description = document.select("div.full-text p").text()
|
||||||
|
|
||||||
|
someInfo.select(".full-info div.fi-col-item")
|
||||||
|
.forEach {
|
||||||
|
ele ->
|
||||||
|
when (ele.select("span").text()) {
|
||||||
|
"Студія:" -> anime.author = ele.select("a").text()
|
||||||
|
"Жанр:" -> anime.genre = ele.select("a").text().replace(" ", ", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return anime
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================== Popular ===============================
|
||||||
|
|
||||||
|
override fun popularAnimeFromElement(element: Element): SAnime {
|
||||||
|
val anime = SAnime.create()
|
||||||
|
|
||||||
|
anime.setUrlWithoutDomain(element.select("div.m-views").attr("data-link"))
|
||||||
|
anime.thumbnail_url = baseUrlWithoutAnime + element.select("div.short-i > img").attr("src")
|
||||||
|
anime.title = element.select("div.short-t-or").text()
|
||||||
|
return anime
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popularAnimeNextPageSelector() = nextPageSelector
|
||||||
|
|
||||||
|
override fun popularAnimeRequest(page: Int): Request {
|
||||||
|
val body = FormBody.Builder()
|
||||||
|
.add("dlenewssortby", "rating")
|
||||||
|
.add("dledirection", "desc")
|
||||||
|
.add("set_new_sort", "dle_sort_cat_12")
|
||||||
|
.add("set_direction_sort", "dle_direction_cat_12")
|
||||||
|
.build()
|
||||||
|
return POST("$baseUrl/page/$page", body = body)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popularAnimeSelector(): String = animeSelector
|
||||||
|
|
||||||
|
// =============================== Latest ===============================
|
||||||
|
|
||||||
|
override fun latestUpdatesFromElement(element: Element) = popularAnimeFromElement(element)
|
||||||
|
|
||||||
|
override fun latestUpdatesNextPageSelector() = nextPageSelector
|
||||||
|
|
||||||
|
override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/anime/page/$page", headers)
|
||||||
|
|
||||||
|
override fun latestUpdatesSelector() = animeSelector
|
||||||
|
|
||||||
|
// =============================== Search ===============================
|
||||||
|
|
||||||
|
override fun searchAnimeFromElement(element: Element) = popularAnimeFromElement(element)
|
||||||
|
|
||||||
|
override fun searchAnimeNextPageSelector() = nextPageSelector
|
||||||
|
|
||||||
|
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||||
|
val body = FormBody.Builder()
|
||||||
|
.add("do", "search")
|
||||||
|
.add("subaction", "search")
|
||||||
|
.add("full_search", "1")
|
||||||
|
.add("result_from", "1")
|
||||||
|
.add("story", query)
|
||||||
|
.build()
|
||||||
|
return POST("$baseUrlWithoutAnime/index.php?do=search", body = body)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun searchAnimeSelector() = animeSelector
|
||||||
|
|
||||||
|
// ============================== Episode ===============================
|
||||||
|
|
||||||
|
override fun episodeFromElement(element: Element) = throw Exception("not used")
|
||||||
|
|
||||||
|
override fun episodeListSelector() = throw Exception("not used")
|
||||||
|
|
||||||
|
override fun episodeListParse(response: Response): List<SEpisode> {
|
||||||
|
val animePage = response.asJsoup()
|
||||||
|
|
||||||
|
// Get Player URL
|
||||||
|
val playerURl = animePage.select("input[value*=https://video.ufdub.com]").attr("value")
|
||||||
|
|
||||||
|
// Parse only player
|
||||||
|
val player = client.newCall(GET(playerURl))
|
||||||
|
.execute()
|
||||||
|
.asJsoup().select("script").html()
|
||||||
|
|
||||||
|
// Parse all episodes
|
||||||
|
val regexUFDubEpisodes = """https:\/\/ufdub.com\/video\/VIDEOS\.php\?(.*?)'""".toRegex()
|
||||||
|
val matchResult = regexUFDubEpisodes.findAll(player)
|
||||||
|
|
||||||
|
// Add to SEpisode
|
||||||
|
val episodeList = mutableListOf<SEpisode>()
|
||||||
|
for (item: MatchResult in matchResult) {
|
||||||
|
val parsedUrl = Uri.parse(item.value)
|
||||||
|
|
||||||
|
val episode = SEpisode.create()
|
||||||
|
|
||||||
|
episode.name = parsedUrl.getQueryParameter("Seriya")!!
|
||||||
|
episode.url = item.value.dropLast(1) // Drop '
|
||||||
|
episodeList.add(episode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return episodeList.reversed()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================ Video ===============================
|
||||||
|
|
||||||
|
override fun fetchVideoList(episode: SEpisode): Observable<List<Video>> {
|
||||||
|
val videoUrl = client.newCall(GET(episode.url)).execute().request.url.toString().replace("dl=1", "raw=1")
|
||||||
|
Log.d("fetchVideoList", videoUrl)
|
||||||
|
val video = Video(videoUrl, "Quality", videoUrl)
|
||||||
|
return Observable.just(listOf(video))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||||
|
|
||||||
|
override fun videoListSelector() = throw Exception("not used")
|
||||||
|
|
||||||
|
override fun videoUrlParse(document: Document) = throw Exception("not used")
|
||||||
|
}
|