|
| 1 | +package eu.kanade.tachiyomi.animeextension.de.twoixtwo |
| 2 | + |
| 3 | +import android.app.Application |
| 4 | +import android.content.SharedPreferences |
| 5 | +import androidx.preference.ListPreference |
| 6 | +import androidx.preference.MultiSelectListPreference |
| 7 | +import androidx.preference.PreferenceScreen |
| 8 | +import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource |
| 9 | +import eu.kanade.tachiyomi.animesource.model.AnimeFilterList |
| 10 | +import eu.kanade.tachiyomi.animesource.model.SAnime |
| 11 | +import eu.kanade.tachiyomi.animesource.model.SEpisode |
| 12 | +import eu.kanade.tachiyomi.animesource.model.Video |
| 13 | +import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource |
| 14 | +import eu.kanade.tachiyomi.network.GET |
| 15 | +import eu.kanade.tachiyomi.util.asJsoup |
| 16 | +import okhttp3.OkHttpClient |
| 17 | +import okhttp3.Request |
| 18 | +import okhttp3.Response |
| 19 | +import org.jsoup.nodes.Document |
| 20 | +import org.jsoup.nodes.Element |
| 21 | +import uy.kohesive.injekt.Injekt |
| 22 | +import uy.kohesive.injekt.api.get |
| 23 | +import java.lang.Exception |
| 24 | + |
| 25 | +class twoixtwo : ConfigurableAnimeSource, ParsedAnimeHttpSource() { |
| 26 | + |
| 27 | + override val name = "2ix2" |
| 28 | + |
| 29 | + override val baseUrl = "https://www.2ix2.com" |
| 30 | + |
| 31 | + override val lang = "de" |
| 32 | + |
| 33 | + override val supportsLatest = false |
| 34 | + |
| 35 | + override val client: OkHttpClient = network.cloudflareClient |
| 36 | + |
| 37 | + private val preferences: SharedPreferences by lazy { |
| 38 | + Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000) |
| 39 | + } |
| 40 | + |
| 41 | + override fun popularAnimeSelector(): String = "div.filmcontent div.moviefilm" |
| 42 | + |
| 43 | + override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/meist-gelikte-tv-sender/") |
| 44 | + |
| 45 | + override fun popularAnimeFromElement(element: Element): SAnime { |
| 46 | + val anime = SAnime.create() |
| 47 | + anime.setUrlWithoutDomain(element.select("div.movief a").attr("href")) |
| 48 | + anime.thumbnail_url = element.select("a img").attr("src") |
| 49 | + anime.title = element.select("div.movief a").text() |
| 50 | + return anime |
| 51 | + } |
| 52 | + |
| 53 | + override fun popularAnimeNextPageSelector(): String? = null |
| 54 | + |
| 55 | + // episodes |
| 56 | + |
| 57 | + override fun episodeListSelector() = throw Exception("not used") |
| 58 | + |
| 59 | + override fun episodeListParse(response: Response): List<SEpisode> { |
| 60 | + val document = response.asJsoup() |
| 61 | + val episodeList = mutableListOf<SEpisode>() |
| 62 | + val episode = SEpisode.create() |
| 63 | + episode.name = document.select("div.filmaltiaciklama h2").text() |
| 64 | + .substringBefore(" Live") |
| 65 | + episode.episode_number = 1F |
| 66 | + episode.setUrlWithoutDomain(document.select("link[rel=canonical]").attr("href")) |
| 67 | + episodeList.add(episode) |
| 68 | + return episodeList.reversed() |
| 69 | + } |
| 70 | + |
| 71 | + override fun episodeFromElement(element: Element): SEpisode = throw Exception("not used") |
| 72 | + |
| 73 | + // Video Extractor |
| 74 | + |
| 75 | + override fun videoListParse(response: Response): List<Video> { |
| 76 | + val document = response.asJsoup() |
| 77 | + return videosFromElement(document) |
| 78 | + } |
| 79 | + |
| 80 | + private fun videosFromElement(document: Document): List<Video> { |
| 81 | + val videoList = mutableListOf<Video>() |
| 82 | + val script = document.select("div.filmicerik script[type]").toString() |
| 83 | + val quality = "LIVE" |
| 84 | + val videoUrl = script.substringAfter("file: \"").substringBefore("\",") |
| 85 | + videoList.add(Video(videoUrl, quality, videoUrl)) |
| 86 | + return videoList |
| 87 | + } |
| 88 | + |
| 89 | + override fun List<Video>.sort(): List<Video> { |
| 90 | + val hoster = preferences.getString("preferred_hoster", "Voe") |
| 91 | + val hosterList = mutableListOf<Video>() |
| 92 | + val otherList = mutableListOf<Video>() |
| 93 | + if (hoster != null) { |
| 94 | + for (video in this) { |
| 95 | + if (video.url.contains(hoster)) { |
| 96 | + hosterList.add(video) |
| 97 | + } else { |
| 98 | + otherList.add(video) |
| 99 | + } |
| 100 | + } |
| 101 | + } else otherList += this |
| 102 | + val newList = mutableListOf<Video>() |
| 103 | + var preferred = 0 |
| 104 | + for (video in hosterList) { |
| 105 | + if (hoster?.let { video.quality.contains(it) } == true) { |
| 106 | + newList.add(preferred, video) |
| 107 | + preferred++ |
| 108 | + } else newList.add(video) |
| 109 | + } |
| 110 | + for (video in otherList) { |
| 111 | + if (hoster?.let { video.quality.contains(it) } == true) { |
| 112 | + newList.add(preferred, video) |
| 113 | + preferred++ |
| 114 | + } else newList.add(video) |
| 115 | + } |
| 116 | + return newList |
| 117 | + } |
| 118 | + |
| 119 | + override fun videoListSelector() = throw Exception("not used") |
| 120 | + |
| 121 | + override fun videoFromElement(element: Element) = throw Exception("not used") |
| 122 | + |
| 123 | + override fun videoUrlParse(document: Document) = throw Exception("not used") |
| 124 | + |
| 125 | + // Search |
| 126 | + |
| 127 | + override fun searchAnimeFromElement(element: Element): SAnime = popularAnimeFromElement(element) |
| 128 | + |
| 129 | + override fun searchAnimeNextPageSelector(): String? = null |
| 130 | + |
| 131 | + override fun searchAnimeSelector(): String = popularAnimeSelector() |
| 132 | + |
| 133 | + override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request = GET("$baseUrl/?s=$query") |
| 134 | + |
| 135 | + // Details |
| 136 | + |
| 137 | + override fun animeDetailsParse(document: Document): SAnime { |
| 138 | + val anime = SAnime.create() |
| 139 | + anime.thumbnail_url = document.select("div.filmaltiimg img").attr("src") |
| 140 | + anime.title = document.select("div.filmaltiaciklama h2").text() |
| 141 | + .substringBefore(" Live") |
| 142 | + // anime.genre = document.select("#detail-content-list > li:nth-child(2) > span").joinToString(", ") { it.text() } |
| 143 | + // anime.description = document.select("#detail-content-list > li:nth-child(3) > span").text() |
| 144 | + // anime.author = document.select("#detail-content-list > li:nth-child(4) > span").joinToString(", ") { it.text() } |
| 145 | + // anime.status = SAnime.COMPLETED |
| 146 | + return anime |
| 147 | + } |
| 148 | + |
| 149 | + // Latest |
| 150 | + |
| 151 | + override fun latestUpdatesNextPageSelector(): String = throw Exception("Not used") |
| 152 | + |
| 153 | + override fun latestUpdatesFromElement(element: Element): SAnime = throw Exception("Not used") |
| 154 | + |
| 155 | + override fun latestUpdatesRequest(page: Int): Request = throw Exception("Not used") |
| 156 | + |
| 157 | + override fun latestUpdatesSelector(): String = throw Exception("Not used") |
| 158 | + |
| 159 | + // Preferences |
| 160 | + |
| 161 | + override fun setupPreferenceScreen(screen: PreferenceScreen) { |
| 162 | + val hosterPref = ListPreference(screen.context).apply { |
| 163 | + key = "preferred_hoster" |
| 164 | + title = "Standard-Hoster" |
| 165 | + entries = arrayOf("Voe", "Streamtape", "Evoload") |
| 166 | + entryValues = arrayOf("https://voe.sx", "https://streamtape.com", "https://evoload.io") |
| 167 | + setDefaultValue("https://voe.sx") |
| 168 | + summary = "%s" |
| 169 | + |
| 170 | + setOnPreferenceChangeListener { _, newValue -> |
| 171 | + val selected = newValue as String |
| 172 | + val index = findIndexOfValue(selected) |
| 173 | + val entry = entryValues[index] as String |
| 174 | + preferences.edit().putString(key, entry).commit() |
| 175 | + } |
| 176 | + } |
| 177 | + val subSelection = MultiSelectListPreference(screen.context).apply { |
| 178 | + key = "hoster_selection" |
| 179 | + title = "Hoster auswählen" |
| 180 | + entries = arrayOf("Voe", "Streamtape", "Evoload") |
| 181 | + entryValues = arrayOf("voe", "stape", "evo") |
| 182 | + setDefaultValue(setOf("voe", "stape", "evo")) |
| 183 | + |
| 184 | + setOnPreferenceChangeListener { _, newValue -> |
| 185 | + preferences.edit().putStringSet(key, newValue as Set<String>).commit() |
| 186 | + } |
| 187 | + } |
| 188 | + screen.addPreference(hosterPref) |
| 189 | + screen.addPreference(subSelection) |
| 190 | + } |
| 191 | +} |
0 commit comments