forked from AlmightyHak/extensions-source
Merged with dark25 (#636)
* merge merged lib, lib-multisrc, all, ar, de, en, es, fr, hi, id, it, pt, tr src from dark25 * patch
This commit is contained in:
parent
9f385108fc
commit
1384df62f3
350 changed files with 12176 additions and 1064 deletions
33
src/es/flixlatam/build.gradle
Normal file
33
src/es/flixlatam/build.gradle
Normal file
|
@ -0,0 +1,33 @@
|
|||
ext {
|
||||
extName = 'FlixLatam'
|
||||
extClass = '.FlixLatam'
|
||||
themePkg = 'dooplay'
|
||||
baseUrl = 'https://flixlatam.com'
|
||||
overrideVersionCode = 3
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
||||
|
||||
dependencies {
|
||||
implementation(project(':lib:vudeo-extractor'))
|
||||
implementation(project(':lib:uqload-extractor'))
|
||||
implementation(project(':lib:streamwish-extractor'))
|
||||
implementation(project(':lib:filemoon-extractor'))
|
||||
implementation(project(':lib:streamlare-extractor'))
|
||||
implementation(project(':lib:yourupload-extractor'))
|
||||
implementation(project(':lib:streamtape-extractor'))
|
||||
implementation(project(':lib:dood-extractor'))
|
||||
implementation(project(':lib:voe-extractor'))
|
||||
implementation(project(':lib:okru-extractor'))
|
||||
implementation(project(':lib:mp4upload-extractor'))
|
||||
implementation(project(':lib:mixdrop-extractor'))
|
||||
implementation(project(':lib:burstcloud-extractor'))
|
||||
implementation(project(':lib:fastream-extractor'))
|
||||
implementation(project(':lib:upstream-extractor'))
|
||||
implementation(project(':lib:streamhidevid-extractor'))
|
||||
implementation(project(':lib:streamsilk-extractor'))
|
||||
implementation(project(':lib:vidguard-extractor'))
|
||||
implementation(project(':lib:universal-extractor'))
|
||||
implementation(project(':lib:cryptoaes'))
|
||||
implementation(libs.jsunpacker)
|
||||
}
|
BIN
src/es/flixlatam/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
src/es/flixlatam/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9 KiB |
BIN
src/es/flixlatam/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
src/es/flixlatam/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
BIN
src/es/flixlatam/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
src/es/flixlatam/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
BIN
src/es/flixlatam/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
src/es/flixlatam/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
BIN
src/es/flixlatam/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
src/es/flixlatam/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
|
@ -0,0 +1,298 @@
|
|||
package eu.kanade.tachiyomi.animeextension.es.flixlatam
|
||||
|
||||
import android.util.Log
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.lib.burstcloudextractor.BurstCloudExtractor
|
||||
import eu.kanade.tachiyomi.lib.cryptoaes.CryptoAES
|
||||
import eu.kanade.tachiyomi.lib.doodextractor.DoodExtractor
|
||||
import eu.kanade.tachiyomi.lib.fastreamextractor.FastreamExtractor
|
||||
import eu.kanade.tachiyomi.lib.filemoonextractor.FilemoonExtractor
|
||||
import eu.kanade.tachiyomi.lib.mp4uploadextractor.Mp4uploadExtractor
|
||||
import eu.kanade.tachiyomi.lib.okruextractor.OkruExtractor
|
||||
import eu.kanade.tachiyomi.lib.streamhidevidextractor.StreamHideVidExtractor
|
||||
import eu.kanade.tachiyomi.lib.streamlareextractor.StreamlareExtractor
|
||||
import eu.kanade.tachiyomi.lib.streamsilkextractor.StreamSilkExtractor
|
||||
import eu.kanade.tachiyomi.lib.streamtapeextractor.StreamTapeExtractor
|
||||
import eu.kanade.tachiyomi.lib.streamwishextractor.StreamWishExtractor
|
||||
import eu.kanade.tachiyomi.lib.universalextractor.UniversalExtractor
|
||||
import eu.kanade.tachiyomi.lib.upstreamextractor.UpstreamExtractor
|
||||
import eu.kanade.tachiyomi.lib.uqloadextractor.UqloadExtractor
|
||||
import eu.kanade.tachiyomi.lib.vidguardextractor.VidGuardExtractor
|
||||
import eu.kanade.tachiyomi.lib.voeextractor.VoeExtractor
|
||||
import eu.kanade.tachiyomi.lib.youruploadextractor.YourUploadExtractor
|
||||
import eu.kanade.tachiyomi.multisrc.dooplay.DooPlay
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import eu.kanade.tachiyomi.util.parallelFlatMapBlocking
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class FlixLatam : DooPlay(
|
||||
"es",
|
||||
"FlixLatam",
|
||||
"https://flixlatam.com",
|
||||
) {
|
||||
override fun popularAnimeRequest(page: Int) = GET("$baseUrl/pelicula/page/$page")
|
||||
|
||||
override fun popularAnimeSelector() = latestUpdatesSelector()
|
||||
|
||||
override fun popularAnimeNextPageSelector() = latestUpdatesNextPageSelector()
|
||||
|
||||
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/lanzamiento/2024/page/$page")
|
||||
|
||||
override val episodeMovieText = "Película"
|
||||
|
||||
override val episodeSeasonPrefix = "Temporada"
|
||||
override val prefQualityTitle = "Calidad preferida"
|
||||
|
||||
override fun videoListSelector() = "li.dooplay_player_option" // ul#playeroptionsul
|
||||
|
||||
// ============================ Video Links =============================
|
||||
override fun videoListParse(response: Response): List<Video> {
|
||||
val document = response.asJsoup()
|
||||
val videoSet = mutableSetOf<Video>()
|
||||
val players = document.select("ul#playeroptionsul li")
|
||||
|
||||
// Iterar sobre cada player
|
||||
players.parallelFlatMapBlocking { player ->
|
||||
val url = getPlayerUrl(player)
|
||||
?: return@parallelFlatMapBlocking emptyList<Video>()
|
||||
if (url.contains("embed69")) {
|
||||
val htmlContent = client.newCall(GET(url)).execute().body.string()
|
||||
val links = extractNewExtractorLinks(document, htmlContent) ?: return@parallelFlatMapBlocking emptyList<Video>()
|
||||
links.forEach { (link, language) ->
|
||||
videoSet.addAll(serverVideoResolver(link, " $language"))
|
||||
}
|
||||
}
|
||||
return@parallelFlatMapBlocking emptyList<Video>()
|
||||
}
|
||||
|
||||
return videoSet.toList()
|
||||
}
|
||||
|
||||
private fun getPlayerUrl(player: Element): String? {
|
||||
val body = FormBody.Builder()
|
||||
.add("action", "doo_player_ajax")
|
||||
.add("post", player.attr("data-post"))
|
||||
.add("nume", player.attr("data-nume"))
|
||||
.add("type", player.attr("data-type"))
|
||||
.build()
|
||||
|
||||
return client.newCall(POST("$baseUrl/wp-admin/admin-ajax.php", headers, body))
|
||||
.execute().body?.string()
|
||||
?.substringAfter("\"embed_url\":\"")
|
||||
?.substringBefore("\",")
|
||||
?.replace("\\", "")
|
||||
?.takeIf(String::isNotBlank)
|
||||
}
|
||||
|
||||
/*-------------------------------- Video extractors ------------------------------------*/
|
||||
private val voeExtractor by lazy { VoeExtractor(client) }
|
||||
private val okruExtractor by lazy { OkruExtractor(client) }
|
||||
private val filemoonExtractor by lazy { FilemoonExtractor(client) }
|
||||
private val uqloadExtractor by lazy { UqloadExtractor(client) }
|
||||
private val mp4uploadExtractor by lazy { Mp4uploadExtractor(client) }
|
||||
private val streamWishExtractor by lazy { StreamWishExtractor(client, headers) }
|
||||
private val doodExtractor by lazy { DoodExtractor(client) }
|
||||
private val streamlareExtractor by lazy { StreamlareExtractor(client) }
|
||||
private val yourUploadExtractor by lazy { YourUploadExtractor(client) }
|
||||
private val burstCloudExtractor by lazy { BurstCloudExtractor(client) }
|
||||
private val fastreamExtractor by lazy { FastreamExtractor(client, headers) }
|
||||
private val upstreamExtractor by lazy { UpstreamExtractor(client) }
|
||||
private val streamTapeExtractor by lazy { StreamTapeExtractor(client) }
|
||||
private val streamHideVidExtractor by lazy { StreamHideVidExtractor(client, headers) }
|
||||
private val streamSilkExtractor by lazy { StreamSilkExtractor(client) }
|
||||
private val vidGuardExtractor by lazy { VidGuardExtractor(client) }
|
||||
private val universalExtractor by lazy { UniversalExtractor(client) }
|
||||
|
||||
private fun serverVideoResolver(url: String, prefix: String = ""): List<Video> {
|
||||
return runCatching {
|
||||
Log.d("SoloLatino", "URL: $url")
|
||||
when {
|
||||
"voe" in url -> voeExtractor.videosFromUrl(url, "$prefix ")
|
||||
"ok.ru" in url || "okru" in url -> okruExtractor.videosFromUrl(url, prefix)
|
||||
"filemoon" in url || "moonplayer" in url -> filemoonExtractor.videosFromUrl(url, "$prefix Filemoon:")
|
||||
"amazon" in url || "amz" in url -> extractAmazonVideo(url, prefix)
|
||||
"uqload" in url -> uqloadExtractor.videosFromUrl(url, prefix)
|
||||
"mp4upload" in url -> mp4uploadExtractor.videosFromUrl(url, headers, "$prefix ")
|
||||
"streamwish" in url || "wish" in url -> streamWishExtractor.videosFromUrl(url, "$prefix StreamWish:")
|
||||
"doodstream" in url || "dood." in url -> doodExtractor.videosFromUrl(url.replace("https://doodstream.com/e/", "https://d0000d.com/e/"), "$prefix DoodStream")
|
||||
"streamlare" in url -> streamlareExtractor.videosFromUrl(url, prefix)
|
||||
"yourupload" in url -> yourUploadExtractor.videoFromUrl(url, headers, "$prefix ")
|
||||
"burstcloud" in url -> burstCloudExtractor.videoFromUrl(url, headers, "$prefix ")
|
||||
"fastream" in url -> fastreamExtractor.videosFromUrl(url, "$prefix Fastream:")
|
||||
"upstream" in url -> upstreamExtractor.videosFromUrl(url, "$prefix ")
|
||||
"streamsilk" in url -> streamSilkExtractor.videosFromUrl(url, "$prefix StreamSilk:")
|
||||
"streamtape" in url || "stp" in url -> streamTapeExtractor.videosFromUrl(url, "$prefix StreamTape")
|
||||
arrayOf("ahvsh", "streamhide", "guccihide", "streamvid", "vidhide").any(url) -> streamHideVidExtractor.videosFromUrl(url, videoNameGen = { "$prefix StreamHideVid:$it" })
|
||||
arrayOf("vembed", "guard", "listeamed", "bembed", "vgfplay").any(url) -> vidGuardExtractor.videosFromUrl(url, prefix = "$prefix ")
|
||||
else -> emptyList()
|
||||
}
|
||||
}.getOrElse { emptyList() }
|
||||
}
|
||||
|
||||
private fun extractAmazonVideo(url: String, prefix: String): List<Video> {
|
||||
val body = client.newCall(GET(url)).execute().asJsoup()
|
||||
val shareId = body.selectFirst("script:containsData(var shareId)")
|
||||
?.data()
|
||||
?.substringAfter("shareId = \"")
|
||||
?.substringBefore("\"") ?: return emptyList()
|
||||
|
||||
val amazonApiJson = client.newCall(GET("https://www.amazon.com/drive/v1/shares/$shareId?resourceVersion=V2&ContentType=JSON&asset=ALL"))
|
||||
.execute().asJsoup()
|
||||
|
||||
val epId = amazonApiJson.toString().substringAfter("\"id\":\"").substringBefore("\"")
|
||||
val amazonApi = client.newCall(GET("https://www.amazon.com/drive/v1/nodes/$epId/children?resourceVersion=V2&ContentType=JSON&limit=200&sort=%5B%22kind+DESC%22%2C+%22modifiedDate+DESC%22%5D&asset=ALL&tempLink=true&shareId=$shareId"))
|
||||
.execute().asJsoup()
|
||||
|
||||
val videoUrl = amazonApi.toString().substringAfter("\"FOLDER\":").substringAfter("tempLink\":\"").substringBefore("\"")
|
||||
return listOf(Video(videoUrl, "$prefix Amazon", videoUrl))
|
||||
}
|
||||
|
||||
private fun extractNewExtractorLinks(doc: Document, htmlContent: String): List<Pair<String, String>>? {
|
||||
val links = mutableListOf<Pair<String, String>>()
|
||||
val jsLinksMatch = getFirstMatch("""dataLink = (\[.+?\]);""".toRegex(), htmlContent) ?: return null
|
||||
|
||||
val items = Json.decodeFromString<List<Item>>(jsLinksMatch)
|
||||
val idiomas = mapOf("LAT" to "[LAT]", "ESP" to "[CAST]", "SUB" to "[SUB]")
|
||||
|
||||
items.forEach { item ->
|
||||
val languageCode = idiomas[item.video_language] ?: "unknown"
|
||||
item.sortedEmbeds.forEach { embed ->
|
||||
val decryptedLink = CryptoAES.decrypt(embed.link, "Ak7qrvvH4WKYxV2OgaeHAEg2a5eh16vE")
|
||||
links.add(Pair(decryptedLink, languageCode))
|
||||
}
|
||||
}
|
||||
|
||||
return links.ifEmpty { null }
|
||||
}
|
||||
|
||||
private fun getFirstMatch(regex: Regex, input: String): String? {
|
||||
return regex.find(input)?.groupValues?.get(1)
|
||||
}
|
||||
|
||||
// ============================== Filters ===============================
|
||||
override val fetchGenres = false
|
||||
|
||||
override fun getFilterList() = FlixLatamFilters.FILTER_LIST
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
val params = FlixLatamFilters.getSearchParameters(filters)
|
||||
val path = when {
|
||||
params.genre.isNotBlank() -> {
|
||||
if (params.genre in listOf("ratings", "tendencias", "pelicula")) {
|
||||
"/${params.genre}"
|
||||
} else {
|
||||
"/genero/${params.genre}"
|
||||
}
|
||||
}
|
||||
else -> buildString {
|
||||
append(
|
||||
when {
|
||||
query.isNotBlank() -> "/?s=$query"
|
||||
else -> "/"
|
||||
},
|
||||
)
|
||||
|
||||
if (params.isInverted) append("&orden=asc")
|
||||
}
|
||||
}
|
||||
|
||||
return if (path.startsWith("/?s=")) {
|
||||
GET("$baseUrl/page/$page$path")
|
||||
} else {
|
||||
GET("$baseUrl$path/page/$page")
|
||||
}
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
super.setupPreferenceScreen(screen) // Quality preference
|
||||
|
||||
val langPref = ListPreference(screen.context).apply {
|
||||
key = PREF_LANG_KEY
|
||||
title = PREF_LANG_TITLE
|
||||
entries = PREF_LANG_ENTRIES
|
||||
entryValues = PREF_LANG_VALUES
|
||||
setDefaultValue(PREF_LANG_DEFAULT)
|
||||
summary = "%s"
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val selected = newValue as String
|
||||
val index = findIndexOfValue(selected)
|
||||
val entry = entryValues[index] as String
|
||||
preferences.edit().putString(key, entry).commit()
|
||||
}
|
||||
}
|
||||
ListPreference(screen.context).apply {
|
||||
key = PREF_SERVER_KEY
|
||||
title = "Preferred server"
|
||||
entries = SERVER_LIST
|
||||
entryValues = SERVER_LIST
|
||||
setDefaultValue(PREF_SERVER_DEFAULT)
|
||||
summary = "%s"
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val selected = newValue as String
|
||||
val index = findIndexOfValue(selected)
|
||||
val entry = entryValues[index] as String
|
||||
preferences.edit().putString(key, entry).commit()
|
||||
}
|
||||
}.also(screen::addPreference)
|
||||
screen.addPreference(langPref)
|
||||
}
|
||||
|
||||
// ============================= Utilities ==============================
|
||||
override fun String.toDate() = 0L
|
||||
|
||||
@Serializable
|
||||
data class Item(
|
||||
val file_id: Int,
|
||||
val video_language: String, // Campo nuevo para almacenar el idioma
|
||||
val sortedEmbeds: List<Embed>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Embed(
|
||||
val servername: String,
|
||||
val link: String,
|
||||
val type: String,
|
||||
)
|
||||
|
||||
private fun Array<String>.any(url: String): Boolean = this.any { url.contains(it, ignoreCase = true) }
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString(prefQualityKey, prefQualityDefault)!!
|
||||
val lang = preferences.getString(PREF_LANG_KEY, PREF_LANG_DEFAULT)!!
|
||||
val server = preferences.getString(PREF_SERVER_KEY, PREF_SERVER_DEFAULT)!!
|
||||
return sortedWith(
|
||||
compareBy(
|
||||
{ it.quality.contains(lang) },
|
||||
{ it.quality.contains(server, true) },
|
||||
{ it.quality.contains(quality) },
|
||||
),
|
||||
).reversed()
|
||||
}
|
||||
|
||||
override val prefQualityValues = arrayOf("480p", "720p", "1080p")
|
||||
override val prefQualityEntries = prefQualityValues
|
||||
|
||||
companion object {
|
||||
private const val PREF_LANG_KEY = "preferred_lang"
|
||||
private const val PREF_LANG_TITLE = "Preferred language"
|
||||
private const val PREF_LANG_DEFAULT = "[LAT]"
|
||||
private const val PREF_SERVER_KEY = "preferred_server"
|
||||
private const val PREF_SERVER_DEFAULT = "Uqload"
|
||||
private val PREF_LANG_ENTRIES = arrayOf("[LAT]", "[SUB]", "[CAST]")
|
||||
private val PREF_LANG_VALUES = arrayOf("[LAT]", "[SUB]", "[CAST]")
|
||||
private val SERVER_LIST = arrayOf("StreamWish", "Uqload", "VidGuard", "StreamHideVid", "Voe")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package eu.kanade.tachiyomi.animeextension.es.flixlatam
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||
|
||||
object FlixLatamFilters {
|
||||
|
||||
open class UriPartFilter(
|
||||
displayName: String,
|
||||
private val vals: Array<Pair<String, String>>,
|
||||
) : AnimeFilter.Select<String>(
|
||||
displayName,
|
||||
vals.map { it.first }.toTypedArray(),
|
||||
) {
|
||||
|
||||
fun toUriPart() = vals[state].second
|
||||
}
|
||||
|
||||
private inline fun <reified R> AnimeFilterList.getFirst(): R {
|
||||
return first { it is R } as R
|
||||
}
|
||||
|
||||
private inline fun <reified R> AnimeFilterList.asUriPart(): String {
|
||||
return getFirst<R>().let {
|
||||
(it as UriPartFilter).toUriPart()
|
||||
}
|
||||
}
|
||||
|
||||
class GenreFilter : UriPartFilter("Generos", FlixLatamFiltersData.GENRES)
|
||||
|
||||
val FILTER_LIST get() = AnimeFilterList(
|
||||
GenreFilter(),
|
||||
)
|
||||
|
||||
data class FilterSearchParams(
|
||||
val isInverted: Boolean = false,
|
||||
val genre: String = "",
|
||||
val year: String = "",
|
||||
)
|
||||
|
||||
internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams {
|
||||
if (filters.isEmpty()) return FilterSearchParams()
|
||||
|
||||
return FilterSearchParams(
|
||||
genre = filters.asUriPart<GenreFilter>(),
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
private object FlixLatamFiltersData {
|
||||
val EVERY = Pair("Seleccionar", "")
|
||||
|
||||
val GENRES = arrayOf(
|
||||
EVERY,
|
||||
Pair("Acción", "accion"),
|
||||
Pair("Action & Adventure", "action-adventure"),
|
||||
Pair("Adolescencia", "adolescencia"),
|
||||
Pair("Animación", "animacion"),
|
||||
Pair("Anime", "anime"),
|
||||
Pair("Artes Marciales", "artes-marciales"),
|
||||
Pair("Aventura", "aventura"),
|
||||
Pair("Aventuras", "aventuras"),
|
||||
Pair("Bélica", "belica"),
|
||||
Pair("Bélico", "belico"),
|
||||
Pair("Ciencia Ficción", "ciencia-ficcion"),
|
||||
Pair("Comedia", "comedia"),
|
||||
Pair("Comedia de Situación", "comedia-de-situacion"),
|
||||
Pair("Crimen", "crimen"),
|
||||
Pair("Deporte", "deporte"),
|
||||
Pair("Dibujo Animado", "dibujo-animado"),
|
||||
Pair("Documental", "documental"),
|
||||
Pair("Drama", "drama"),
|
||||
Pair("Drama Adolescente", "drama-adolescente"),
|
||||
Pair("Drama Médico", "drama-medico"),
|
||||
Pair("Familia", "familia"),
|
||||
Pair("Fantasía", "fantasia"),
|
||||
Pair("Ficción Histórica", "ficcion-historica"),
|
||||
Pair("Hentai", "hentai"),
|
||||
Pair("Historia", "historia"),
|
||||
Pair("Humor Negro", "humor-negro"),
|
||||
Pair("Infantil", "infantil"),
|
||||
Pair("Kids", "kids"),
|
||||
Pair("Misterio", "misterio"),
|
||||
Pair("Música", "musica"),
|
||||
Pair("Película de TV", "pelicula-de-tv"),
|
||||
Pair("Política", "politica"),
|
||||
Pair("Psicológico", "psicologico"),
|
||||
Pair("Reality", "reality"),
|
||||
Pair("Romance", "romance"),
|
||||
Pair("Sátira", "satira"),
|
||||
Pair("Sci-Fi & Fantasy", "sci-fi-fantasy"),
|
||||
Pair("Sexualidad y Pornografía", "sexualidad-y-pornografia"),
|
||||
Pair("Soap", "soap"),
|
||||
Pair("Sobrenatural", "sobrenatural"),
|
||||
Pair("Superhéroes", "superheroes"),
|
||||
Pair("Suspense", "suspense"),
|
||||
Pair("Suspenso", "suspenso"),
|
||||
Pair("Talk", "talk"),
|
||||
Pair("Telecomedia", "telecomedia"),
|
||||
Pair("Telenovela", "telenovela"),
|
||||
Pair("Terror", "terror"),
|
||||
Pair("TV Asiática", "tv-asiatica"),
|
||||
Pair("TV Latina", "tv-latina"),
|
||||
Pair("War & Politics", "war-politics"),
|
||||
Pair("Western", "western"),
|
||||
)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue