From 6b27db036b2dac4a29aa86aca649ae0d172c693e Mon Sep 17 00:00:00 2001 From: LagradOst Date: Sun, 1 Aug 2021 00:11:56 +0200 Subject: [PATCH] trailers.to subtitles + subtitle helper --- app/src/main/AndroidManifest.xml | 1 + .../lagradost/cloudstream3/MainActivity.kt | 8 +- .../movieproviders/TrailersToProvider.kt | 97 ++++-- .../lagradost/cloudstream3/utils/AppUtils.kt | 8 + .../cloudstream3/utils/SubtitleHelper.kt | 292 ++++++++++++++++++ 5 files changed, 386 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/com/lagradost/cloudstream3/utils/SubtitleHelper.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d43a78a7..a083008d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,7 @@ + diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index b53b5649..529db96c 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -31,8 +31,10 @@ import com.lagradost.cloudstream3.utils.DataStore.getKey import com.lagradost.cloudstream3.utils.DataStore.removeKey import com.lagradost.cloudstream3.utils.DataStoreHelper.setViewPos import com.lagradost.cloudstream3.utils.Event +import com.lagradost.cloudstream3.utils.SubtitleHelper.createISO import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.fragment_result.* +import kotlin.concurrent.thread const val VLC_PACKAGE = "org.videolan.vlc" const val VLC_INTENT_ACTION_RESULT = "org.videolan.vlc.player.result" @@ -100,7 +102,7 @@ class MainActivity : AppCompatActivity() { navController.navigate(R.id.navigation_downloads, Bundle(), navOptions) return true } - if(child is SearchFragment || child is HomeFragment || child is DownloadFragment || child is SettingsFragment) { + if (child is SearchFragment || child is HomeFragment || child is DownloadFragment || child is SettingsFragment) { this.finish() return true } @@ -283,7 +285,9 @@ class MainActivity : AppCompatActivity() { } } }*/ - + /*thread { + createISO() + }*/ handleAppIntent(intent) } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TrailersToProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TrailersToProvider.kt index 2ebffd20..4460207b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TrailersToProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TrailersToProvider.kt @@ -1,8 +1,11 @@ package com.lagradost.cloudstream3.movieproviders +import com.fasterxml.jackson.module.kotlin.readValue import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.utils.AppUtils.imdbUrlToId import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.Qualities +import com.lagradost.cloudstream3.utils.SubtitleHelper import org.jsoup.Jsoup // referer = https://trailers.to, USERAGENT ALSO REQUIRED @@ -57,7 +60,7 @@ class TrailersToProvider : MainAPI() { returnList.add(HomePageList(title, currentList)) } } - if(returnList.size <= 0) return null + if (returnList.size <= 0) return null return HomePageResponse(returnList) //section.section > div.container > div.owl-carousel @@ -118,14 +121,38 @@ class TrailersToProvider : MainAPI() { return returnValue } - private fun loadLink(data: String, callback: (ExtractorLink) -> Unit): Boolean { + private fun loadLink( + data: String, + callback: (ExtractorLink) -> Unit, + ): Boolean { val response = khttp.get(data) val url = " Unit) { + if (url.isEmpty()) return + + val response = khttp.get(fixUrl(url)) + val document = Jsoup.parse(response.text) + + val items = document.select("div.list-group > a.list-group-item") + for (item in items) { + val hash = item.attr("hash") ?: continue + val languageCode = item.attr("languagecode") ?: continue + if (hash.isEmpty()) continue + if (languageCode.isEmpty()) continue + + subtitleCallback.invoke( + SubtitleFile( + SubtitleHelper.fromTwoLettersToLanguage(languageCode) ?: languageCode, + "$mainUrl/subtitles/$hash" + ) + ) + } } override fun loadLinks( @@ -135,22 +162,35 @@ class TrailersToProvider : MainAPI() { callback: (ExtractorLink) -> Unit ): Boolean { if (isCasting) return false - val isMovie = data.contains("/web-sources/") + val pairData = mapper.readValue>(data) + val url = pairData.second + + val isMovie = url.contains("/web-sources/") if (isMovie) { - return loadLink(data, callback) - } else if (data.contains("/episode/")) { - val response = khttp.get(data) + val isSucc = loadLink(url, callback) + val subUrl = pairData.first + loadSubs(subUrl, subtitleCallback) + + return isSucc + } else if (url.contains("/episode/")) { + val response = khttp.get(url) val document = Jsoup.parse(response.text) + val qSub = document.select("subtitle-content") + val subUrl = document.select("subtitle-content")?.attr("data-url") ?: "" + val subData = fixUrl(document.selectFirst("content").attr("data-url") ?: return false) - if (subData.contains("/web-sources/")) { - return loadLink(subData, callback) - } + val isSucc = if (subData.contains("/web-sources/")) { + loadLink(subData, callback) + } else false + + loadSubs(subUrl, subtitleCallback) + return isSucc } return false } - override fun load(slug: String): LoadResponse? { - val response = khttp.get(slug) + override fun load(url: String): LoadResponse? { + val response = khttp.get(url) val document = Jsoup.parse(response.text) val metaInfo = document.select("div.post-info-meta > ul.post-info-meta-list > li") val year = metaInfo?.get(0)?.selectFirst("> span.small-text")?.text()?.takeLast(4)?.toIntOrNull() @@ -175,7 +215,7 @@ class TrailersToProvider : MainAPI() { } val tags = if (generes == null) null else ArrayList(generes) - val isTvShow = slug.contains("/tvshow/") + val isTvShow = url.contains("/tvshow/") if (isTvShow) { val episodes = document.select("article.tour-modern") ?: return null val parsedEpisodes = episodes.map { item -> @@ -193,11 +233,21 @@ class TrailersToProvider : MainAPI() { val ratingText = infoHeaders?.get(1)?.text()?.replace("/ 10", "") val epRating = if (ratingText == null) null else parseRating(ratingText) val epDescript = main.selectFirst("> p")?.text() - TvSeriesEpisode(epName, season, episode, href, epPoster, date, epRating, epDescript) + + TvSeriesEpisode( + epName, + season, + episode, + mapper.writeValueAsString(Pair("", href)), + epPoster, + date, + epRating, + epDescript + ) } return TvSeriesLoadResponse( title, - slug, + url, this.name, TvType.TvSeries, ArrayList(parsedEpisodes), @@ -212,10 +262,21 @@ class TrailersToProvider : MainAPI() { trailer ) } else { - val data = fixUrl(document.selectFirst("content").attr("data-url") ?: return null) + + //https://trailers.to/en/subtitle-details/2086212/jungle-cruise-2021?imdbId=tt0870154&season=0&episode=0 + //https://trailers.to/en/movie/2086212/jungle-cruise-2021 + + val subUrl = if (imdbUrl != null) { + val imdbId = imdbUrlToId(imdbUrl) + url.replace("/movie/", "/subtitle-details/") + "?imdbId=$imdbId&season=0&episode=0" + } else "" + + val data = mapper.writeValueAsString( + Pair(subUrl, fixUrl(document.selectFirst("content").attr("data-url") ?: return null)) + ) return MovieLoadResponse( title, - slug, + url, this.name, TvType.Movie, data, diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/AppUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/AppUtils.kt index f6ae40e0..bcf7a975 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/AppUtils.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/AppUtils.kt @@ -155,4 +155,12 @@ object AppUtils { } return currentAudioFocusRequest } + + /** https://www.imdb.com/title/tt2861424/ -> tt2861424 */ + fun imdbUrlToId(url: String): String { + return url + .removePrefix("https://www.imdb.com/title/") + .removePrefix("https://imdb.com/title/tt2861424/") + .replace("/", "") + } } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/SubtitleHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/SubtitleHelper.kt new file mode 100644 index 00000000..b2b18b71 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/SubtitleHelper.kt @@ -0,0 +1,292 @@ +package com.lagradost.cloudstream3.utils + +import org.jsoup.Jsoup +import java.util.* + +object SubtitleHelper { + data class Language639( + val languageName: String, + val nativeName: String, + val ISO_639_1: String, + val ISO_639_2_T: String, + val ISO_639_2_B: String, + val ISO_639_3: String, + val ISO_639_6: String, + ) + + fun createISO() { + val url = "https://infogalactic.com/info/List_of_ISO_639-1_codes" + val response = khttp.get(url) + val document = Jsoup.parse(response.text) + val headers = document.select("table.wikitable > tbody > tr") + + var text = "listOf(\n" + for (head in headers) { + val tds = head.select("td") + if (tds.size < 8) continue + val name = tds[2].selectFirst("> a").text() + val native = tds[3].text() + val ISO_639_1 = tds[4].ownText().replace("+", "").replace(" ", "") + val ISO_639_2_T = tds[5].ownText().replace("+", "").replace(" ", "") + val ISO_639_2_B = tds[6].ownText().replace("+", "").replace(" ", "") + val ISO_639_3 = tds[7].ownText().replace("+", "").replace(" ", "") + val ISO_639_6 = tds[8].ownText().replace("+", "").replace(" ", "") + + val txtAdd = + "Language(\"$name\", \"$native\", \"$ISO_639_1\", \"$ISO_639_2_T\", \"$ISO_639_2_B\", \"$ISO_639_3\", \"$ISO_639_6\"),\n" + text += txtAdd + } + text += ")" + println("ISO CREATED:\n$text") + } + + /** lang -> ISO_639_1*/ + fun fromLanguageToTwoLetters(input: String): String? { + for (lang in languages) { + if (lang.languageName == input || lang.nativeName == input) { + return lang.ISO_639_1 + } + } + return null + } + + /** ISO_639_1 -> lang*/ + fun fromTwoLettersToLanguage(input: String): String? { + if (input.length != 2) return null + val comparison = input.toLowerCase(Locale.ROOT) + for (lang in languages) { + if (lang.ISO_639_1 == comparison) { + return lang.languageName + } + } + return null + } + + /**ISO_639_2_B or ISO_639_2_T or ISO_639_3-> lang*/ + fun fromThreeLettersToLanguage(input: String): String? { + if (input.length != 3) return null + val comparison = input.toLowerCase(Locale.ROOT) + for (lang in languages) { + if (lang.ISO_639_2_B == comparison) { + return lang.languageName + } + } + for (lang in languages) { + if (lang.ISO_639_2_T == comparison) { + return lang.languageName + } + } + for (lang in languages) { + if (lang.ISO_639_3 == comparison) { + return lang.languageName + } + } + return null + } + + /** lang -> ISO_639_2_T*/ + fun fromLanguageToThreeLetters(input: String): String? { + for (lang in languages) { + if (lang.languageName == input || lang.nativeName == input) { + return lang.ISO_639_2_T + } + } + return null + } + + val languages = listOf( + Language639("Abkhaz", "аҧсуа бызшәа, аҧсшәа", "ab", "abk", "abk", "abk", "abks"), + Language639("Afar", "Afaraf", "aa", "aar", "aar", "aar", "aars"), + Language639("Afrikaans", "Afrikaans", "af", "afr", "afr", "afr", "afrs"), + Language639("Akan", "Akan", "ak", "aka", "aka", "aka", ""), + Language639("Albanian", "Shqip", "sq", "sqi", "", "sqi", ""), + Language639("Amharic", "አማርኛ", "am", "amh", "amh", "amh", ""), + Language639("Arabic", "العربية", "ar", "ara", "ara", "ara", ""), + Language639("Aragonese", "aragonés", "an", "arg", "arg", "arg", ""), + Language639("Armenian", "Հայերեն", "hy", "hye", "", "hye", ""), + Language639("Assamese", "অসমীয়া", "as", "asm", "asm", "asm", ""), + Language639("Avaric", "авар мацӀ, магӀарул мацӀ", "av", "ava", "ava", "ava", ""), + Language639("Avestan", "avesta", "ae", "ave", "ave", "ave", ""), + Language639("Aymara", "aymar aru", "ay", "aym", "aym", "aym", ""), + Language639("Azerbaijani", "azərbaycan dili", "az", "aze", "aze", "aze", ""), + Language639("Bambara", "bamanankan", "bm", "bam", "bam", "bam", ""), + Language639("Bashkir", "башҡорт теле", "ba", "bak", "bak", "bak", ""), + Language639("Basque", "euskara, euskera", "eu", "eus", "", "eus", ""), + Language639("Belarusian", "беларуская мова", "be", "bel", "bel", "bel", ""), + Language639("Bengali", "বাংলা", "bn", "ben", "ben", "ben", ""), + Language639("Bihari", "भोजपुरी", "bh", "bih", "bih", "", ""), + Language639("Bislama", "Bislama", "bi", "bis", "bis", "bis", ""), + Language639("Bosnian", "bosanski jezik", "bs", "bos", "bos", "bos", "boss"), + Language639("Breton", "brezhoneg", "br", "bre", "bre", "bre", ""), + Language639("Bulgarian", "български език", "bg", "bul", "bul", "bul", "buls"), + Language639("Burmese", "ဗမာစာ", "my", "mya", "", "mya", ""), + Language639("Catalan", "català", "ca", "cat", "cat", "cat", ""), + Language639("Chamorro", "Chamoru", "ch", "cha", "cha", "cha", ""), + Language639("Chechen", "нохчийн мотт", "ce", "che", "che", "che", ""), + Language639("Chichewa", "chiCheŵa, chinyanja", "ny", "nya", "nya", "nya", ""), + Language639("Chinese", "中文 (Zhōngwén), 汉语, 漢語", "zh", "zho", "", "zho", ""), + Language639("Chuvash", "чӑваш чӗлхи", "cv", "chv", "chv", "chv", ""), + Language639("Cornish", "Kernewek", "kw", "cor", "cor", "cor", ""), + Language639("Corsican", "corsu, lingua corsa", "co", "cos", "cos", "cos", ""), + Language639("Cree", "ᓀᐦᐃᔭᐍᐏᐣ", "cr", "cre", "cre", "cre", ""), + Language639("Croatian", "hrvatski jezik", "hr", "hrv", "hrv", "hrv", ""), + Language639("Czech", "čeština, český jazyk", "cs", "ces", "", "ces", ""), + Language639("Danish", "dansk", "da", "dan", "dan", "dan", ""), + Language639("Divehi", "ދިވެހި", "dv", "div", "div", "div", ""), + Language639("Dutch", "Nederlands, Vlaams", "nl", "nld", "", "nld", ""), + Language639("Dzongkha", "རྫོང་ཁ", "dz", "dzo", "dzo", "dzo", ""), + Language639("English", "English", "en", "eng", "eng", "eng", "engs"), + Language639("Esperanto", "Esperanto", "eo", "epo", "epo", "epo", ""), + Language639("Estonian", "eesti, eesti keel", "et", "est", "est", "est", ""), + Language639("Ewe", "Eʋegbe", "ee", "ewe", "ewe", "ewe", ""), + Language639("Faroese", "føroyskt", "fo", "fao", "fao", "fao", ""), + Language639("Fijian", "vosa Vakaviti", "fj", "fij", "fij", "fij", ""), + Language639("Finnish", "suomi, suomen kieli", "fi", "fin", "fin", "fin", ""), + Language639("French", "français, langue française", "fr", "fra", "", "fra", "fras"), + Language639("Fula", "Fulfulde, Pulaar, Pular", "ff", "ful", "ful", "ful", ""), + Language639("Galician", "galego", "gl", "glg", "glg", "glg", ""), + Language639("Georgian", "ქართული", "ka", "kat", "", "kat", ""), + Language639("German", "Deutsch", "de", "deu", "", "deu", "deus"), + Language639("Greek", "ελληνικά", "el", "ell", "", "ell", "ells"), + Language639("Guaraní", "Avañe'ẽ", "gn", "grn", "grn", "grn", ""), + Language639("Gujarati", "ગુજરાતી", "gu", "guj", "guj", "guj", ""), + Language639("Haitian", "Kreyòl ayisyen", "ht", "hat", "hat", "hat", ""), + Language639("Hausa", "(Hausa) هَوُسَ", "ha", "hau", "hau", "hau", ""), + Language639("Hebrew", "עברית", "he", "heb", "heb", "heb", ""), + Language639("Herero", "Otjiherero", "hz", "her", "her", "her", ""), + Language639("Hindi", "हिन्दी, हिंदी", "hi", "hin", "hin", "hin", "hins"), + Language639("Hiri Motu", "Hiri Motu", "ho", "hmo", "hmo", "hmo", ""), + Language639("Hungarian", "magyar", "hu", "hun", "hun", "hun", ""), + Language639("Interlingua", "Interlingua", "ia", "ina", "ina", "ina", ""), + Language639("Indonesian", "Bahasa Indonesia", "id", "ind", "ind", "ind", ""), + Language639( + "Interlingue", + "Originally called Occidental; then Interlingue after WWII", + "ie", + "ile", + "ile", + "ile", + "" + ), + Language639("Irish", "Gaeilge", "ga", "gle", "gle", "gle", ""), + Language639("Igbo", "Asụsụ Igbo", "ig", "ibo", "ibo", "ibo", ""), + Language639("Inupiaq", "Iñupiaq, Iñupiatun", "ik", "ipk", "ipk", "ipk", ""), + Language639("Ido", "Ido", "io", "ido", "ido", "ido", "idos"), + Language639("Icelandic", "Íslenska", "is", "isl", "", "isl", ""), + Language639("Italian", "italiano", "it", "ita", "ita", "ita", "itas"), + Language639("Inuktitut", "ᐃᓄᒃᑎᑐᑦ", "iu", "iku", "iku", "iku", ""), + Language639("Japanese", "日本語 (にほんご)", "ja", "jpn", "jpn", "jpn", ""), + Language639("Javanese", "ꦧꦱꦗꦮ", "jv", "jav", "jav", "jav", ""), + Language639("Kalaallisut", "kalaallisut, kalaallit oqaasii", "kl", "kal", "kal", "kal", ""), + Language639("Kannada", "ಕನ್ನಡ", "kn", "kan", "kan", "kan", ""), + Language639("Kanuri", "Kanuri", "kr", "kau", "kau", "kau", ""), + Language639("Kashmiri", "कश्मीरी, كشميري‎", "ks", "kas", "kas", "kas", ""), + Language639("Kazakh", "қазақ тілі", "kk", "kaz", "kaz", "kaz", ""), + Language639("Khmer", "ខ្មែរ, ខេមរភាសា, ភាសាខ្មែរ", "km", "khm", "khm", "khm", ""), + Language639("Kikuyu", "Gĩkũyũ", "ki", "kik", "kik", "kik", ""), + Language639("Kinyarwanda", "Ikinyarwanda", "rw", "kin", "kin", "kin", ""), + Language639("Kyrgyz", "Кыргызча, Кыргыз тили", "ky", "kir", "kir", "kir", ""), + Language639("Komi", "коми кыв", "kv", "kom", "kom", "kom", ""), + Language639("Kongo", "Kikongo", "kg", "kon", "kon", "kon", ""), + Language639("Korean", "한국어, 조선어", "ko", "kor", "kor", "kor", ""), + Language639("Kurdish", "Kurdî, كوردی‎", "ku", "kur", "kur", "kur", ""), + Language639("Kwanyama", "Kuanyama", "kj", "kua", "kua", "kua", ""), + Language639("Latin", "latine, lingua latina", "la", "lat", "lat", "lat", "lats"), + Language639("Luxembourgish", "Lëtzebuergesch", "lb", "ltz", "ltz", "ltz", ""), + Language639("Ganda", "Luganda", "lg", "lug", "lug", "lug", ""), + Language639("Limburgish", "Limburgs", "li", "lim", "lim", "lim", ""), + Language639("Lingala", "Lingála", "ln", "lin", "lin", "lin", ""), + Language639("Lao", "ພາສາລາວ", "lo", "lao", "lao", "lao", ""), + Language639("Lithuanian", "lietuvių kalba", "lt", "lit", "lit", "lit", ""), + Language639("Luba-Katanga", "Tshiluba", "lu", "lub", "lub", "lub", ""), + Language639("Latvian", "latviešu valoda", "lv", "lav", "lav", "lav", ""), + Language639("Manx", "Gaelg, Gailck", "gv", "glv", "glv", "glv", ""), + Language639("Macedonian", "македонски јазик", "mk", "mkd", "", "mkd", ""), + Language639("Malagasy", "fiteny malagasy", "mg", "mlg", "mlg", "mlg", ""), + Language639("Malay", "bahasa Melayu, بهاس ملايو‎", "ms", "msa", "", "msa", ""), + Language639("Malayalam", "മലയാളം", "ml", "mal", "mal", "mal", ""), + Language639("Maltese", "Malti", "mt", "mlt", "mlt", "mlt", ""), + Language639("Māori", "te reo Māori", "mi", "mri", "", "mri", ""), + Language639("Marathi (Marāṭhī)", "मराठी", "mr", "mar", "mar", "mar", ""), + Language639("Marshallese", "Kajin M̧ajeļ", "mh", "mah", "mah", "mah", ""), + Language639("Mongolian", "Монгол хэл", "mn", "mon", "mon", "mon", ""), + Language639("Nauruan", "Dorerin Naoero", "na", "nau", "nau", "nau", ""), + Language639("Navajo", "Diné bizaad", "nv", "nav", "nav", "nav", ""), + Language639("Northern Ndebele", "isiNdebele", "nd", "nde", "nde", "nde", ""), + Language639("Nepali", "नेपाली", "ne", "nep", "nep", "nep", ""), + Language639("Ndonga", "Owambo", "ng", "ndo", "ndo", "ndo", ""), + Language639("Norwegian Bokmål", "Norsk bokmål", "nb", "nob", "nob", "nob", ""), + Language639("Norwegian Nynorsk", "Norsk nynorsk", "nn", "nno", "nno", "nno", ""), + Language639("Norwegian", "Norsk", "no", "nor", "nor", "nor", ""), + Language639("Nuosu", "ꆈꌠ꒿ Nuosuhxop", "ii", "iii", "iii", "iii", ""), + Language639("Southern Ndebele", "isiNdebele", "nr", "nbl", "nbl", "nbl", ""), + Language639("Occitan", "occitan, lenga d'òc", "oc", "oci", "oci", "oci", ""), + Language639("Ojibwe", "ᐊᓂᔑᓈᐯᒧᐎᓐ", "oj", "oji", "oji", "oji", ""), + Language639("Old Church Slavonic", "ѩзыкъ словѣньскъ", "cu", "chu", "chu", "chu", ""), + Language639("Oromo", "Afaan Oromoo", "om", "orm", "orm", "orm", ""), + Language639("Oriya", "ଓଡ଼ିଆ", "or", "ori", "ori", "ori", ""), + Language639("Ossetian", "ирон æвзаг", "os", "oss", "oss", "oss", ""), + Language639("Panjabi", "ਪੰਜਾਬੀ, پنجابی‎", "pa", "pan", "pan", "pan", ""), + Language639("Pāli", "पाऴि", "pi", "pli", "pli", "pli", ""), + Language639("Persian", "فارسی", "fa", "fas", "", "fas", ""), + Language639("Polish", "język polski, polszczyzna", "pl", "pol", "pol", "pol", "pols"), + Language639("Pashto", "پښتو", "ps", "pus", "pus", "pus", ""), + Language639("Portuguese", "português", "pt", "por", "por", "por", ""), + Language639("Quechua", "Runa Simi, Kichwa", "qu", "que", "que", "que", ""), + Language639("Romansh", "rumantsch grischun", "rm", "roh", "roh", "roh", ""), + Language639("Kirundi", "Ikirundi", "rn", "run", "run", "run", ""), + Language639("Reunion Creole", "Kréol Rénioné", "rc", "rcf", "rcf", "rcf", ""), + Language639("Romanian", "limba română", "ro", "ron", "", "ron", ""), + Language639("Russian", "Русский", "ru", "rus", "rus", "rus", ""), + Language639("Sanskrit (Saṁskṛta)", "संस्कृतम्", "sa", "san", "san", "san", ""), + Language639("Sardinian", "sardu", "sc", "srd", "srd", "srd", ""), + Language639("Sindhi", "सिन्धी, سنڌي، سندھی‎", "sd", "snd", "snd", "snd", ""), + Language639("Northern Sami", "Davvisámegiella", "se", "sme", "sme", "sme", ""), + Language639("Samoan", "gagana fa'a Samoa", "sm", "smo", "smo", "smo", ""), + Language639("Sango", "yângâ tî sängö", "sg", "sag", "sag", "sag", ""), + Language639("Serbian", "српски језик", "sr", "srp", "srp", "srp", ""), + Language639("Scottish Gaelic", "Gàidhlig", "gd", "gla", "gla", "gla", ""), + Language639("Shona", "chiShona", "sn", "sna", "sna", "sna", ""), + Language639("Sinhalese", "සිංහල", "si", "sin", "sin", "sin", ""), + Language639("Slovak", "slovenčina, slovenský jazyk", "sk", "slk", "", "slk", ""), + Language639("Slovene", "slovenski jezik, slovenščina", "sl", "slv", "slv", "slv", ""), + Language639("Somali", "Soomaaliga, af Soomaali", "so", "som", "som", "som", ""), + Language639("Southern Sotho", "Sesotho", "st", "sot", "sot", "sot", ""), + Language639("Spanish", "español", "es", "spa", "spa", "spa", ""), + Language639("Sundanese", "Basa Sunda", "su", "sun", "sun", "sun", ""), + Language639("Swahili", "Kiswahili", "sw", "swa", "swa", "swa", ""), + Language639("Swati", "SiSwati", "ss", "ssw", "ssw", "ssw", ""), + Language639("Swedish", "svenska", "sv", "swe", "swe", "swe", ""), + Language639("Tamil", "தமிழ்", "ta", "tam", "tam", "tam", ""), + Language639("Telugu", "తెలుగు", "te", "tel", "tel", "tel", ""), + Language639("Tajik", "тоҷикӣ, toçikī, تاجیکی‎", "tg", "tgk", "tgk", "tgk", ""), + Language639("Thai", "ไทย", "th", "tha", "tha", "tha", ""), + Language639("Tigrinya", "ትግርኛ", "ti", "tir", "tir", "tir", ""), + Language639("Tibetan Standard", "བོད་ཡིག", "bo", "bod", "", "bod", ""), + Language639("Turkmen", "Türkmen, Түркмен", "tk", "tuk", "tuk", "tuk", ""), + Language639("Tagalog", "Wikang Tagalog", "tl", "tgl", "tgl", "tgl", ""), + Language639("Tswana", "Setswana", "tn", "tsn", "tsn", "tsn", ""), + Language639("Tonga", "faka Tonga", "to", "ton", "ton", "ton", ""), + Language639("Turkish", "Türkçe", "tr", "tur", "tur", "tur", ""), + Language639("Tsonga", "Xitsonga", "ts", "tso", "tso", "tso", ""), + Language639("Tatar", "татар теле, tatar tele", "tt", "tat", "tat", "tat", ""), + Language639("Twi", "Twi", "tw", "twi", "twi", "twi", ""), + Language639("Tahitian", "Reo Tahiti", "ty", "tah", "tah", "tah", ""), + Language639("Uyghur", "ئۇيغۇرچە‎, Uyghurche", "ug", "uig", "uig", "uig", ""), + Language639("Ukrainian", "Українська", "uk", "ukr", "ukr", "ukr", ""), + Language639("Urdu", "اردو", "ur", "urd", "urd", "urd", ""), + Language639("Uzbek", "Oʻzbek, Ўзбек, أۇزبېك‎", "uz", "uzb", "uzb", "uzb", ""), + Language639("Venda", "Tshivenḓa", "ve", "ven", "ven", "ven", ""), + Language639("Vietnamese", "Tiếng Việt", "vi", "vie", "vie", "vie", ""), + Language639("Volapük", "Volapük", "vo", "vol", "vol", "vol", ""), + Language639("Walloon", "walon", "wa", "wln", "wln", "wln", ""), + Language639("Welsh", "Cymraeg", "cy", "cym", "", "cym", ""), + Language639("Wolof", "Wollof", "wo", "wol", "wol", "wol", ""), + Language639("Western Frisian", "Frysk", "fy", "fry", "fry", "fry", ""), + Language639("Xhosa", "isiXhosa", "xh", "xho", "xho", "xho", ""), + Language639("Yiddish", "ייִדיש", "yi", "yid", "yid", "yid", ""), + Language639("Yoruba", "Yorùbá", "yo", "yor", "yor", "yor", ""), + Language639("Zhuang", "Saɯ cueŋƅ, Saw cuengh", "za", "zha", "zha", "zha", ""), + Language639("Zulu", "isiZulu", "zu", "zul", "zul", "zul", ""), + ) +} \ No newline at end of file